diff --git a/.github/workflows/dev.yml b/.github/workflows/dev.yml
new file mode 100644
index 00000000..ba3ba9b1
--- /dev/null
+++ b/.github/workflows/dev.yml
@@ -0,0 +1,32 @@
+name: Development pipeline
+
+on:
+ push:
+ branches:
+ - "*"
+ - "!feature/"
+
+jobs:
+ release:
+ name: Publish development build to CDN
+ runs-on: ubuntu-latest
+ env:
+ DEPLOY_KEY: ${{ secrets.DEPLOY_KEY }}
+ steps:
+ - name: Clone project
+ uses: actions/checkout@v4
+ with:
+ fetch-depth: 0
+ - name: Workaround checkout issues
+ run: |
+ git fetch --tags --force
+ - name: Create Package
+ uses: BigWigsMods/packager@v2
+ with:
+ args: -n "{package-name}-$GITHUB_REF_NAME-{project-version}"
+ - name: Get package name
+ run: |
+ echo "PACKAGE=$(find .release -type f -name *.zip -printf "%f\n")" >> $GITHUB_ENV
+ - name: Publish package
+ run: |
+ curl https://api.tukui.org/v1/upload/dev/$PACKAGE --upload-file .release/$PACKAGE -H "X-Tukui-Key: $DEPLOY_KEY" -H "Content-Type: application/zip"
\ No newline at end of file
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 3d78157a..7e7b7fd4 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -14,9 +14,18 @@ jobs:
steps:
- name: Clone project
uses: actions/checkout@v4
- - name: Prepare package
+ with:
+ fetch-depth: 0
+ - name: Workaround checkout issues
run: |
- zip -9 -r tukui-$VERSION.zip Tukui
+ git fetch --tags --force
+ - name: Create Package
+ uses: BigWigsMods/packager@v2
+ with:
+ args: -n "{package-name}-{project-version}"
+ - name: Get package name
+ run: |
+ echo "PACKAGE=$(find .release -type f -name *.zip -printf "%f\n")" >> $GITHUB_ENV
- name: Publish package
run: |
- curl https://api.tukui.org/v1/upload/tukui-$GITHUB_REF_NAME.zip --upload-file tukui-$GITHUB_REF_NAME.zip -H "X-Tukui-Key: $DEPLOY_KEY" -H "Content-Type: application/zip"
+ curl https://api.tukui.org/v1/upload/$PACKAGE --upload-file .release/$PACKAGE -H "X-Tukui-Key: $DEPLOY_KEY" -H "Content-Type: application/zip"
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 00000000..b18906bb
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,31 @@
+Thumbs.db
+Desktop.ini
+.DS_Store
+.vscode
+
+# Libraries
+Tukui/Libs/*
+!Tukui/Libs/LibAnim
+!Tukui/Libs/LibDeflate
+!Tukui/Libs/LibHealComm-4.0
+!Tukui/Libs/LibSerialize
+!Tukui/Libs/oUF
+!Tukui/Libs/oUF_ArcaneCharge
+!Tukui/Libs/oUF_Atonement
+!Tukui/Libs/oUF_AuraBars
+!Tukui/Libs/oUF_AuraTrack
+!Tukui/Libs/oUF_CombatFeedback
+!Tukui/Libs/oUF_ComboPointsBar
+!Tukui/Libs/oUF_DruidMana
+!Tukui/Libs/oUF_EnergyManaRegen
+!Tukui/Libs/oUF_FloatingCombatFeedback
+!Tukui/Libs/oUF_HarmonyBar
+!Tukui/Libs/oUF_HolyPowerBar
+!Tukui/Libs/oUF_QuestIcon
+!Tukui/Libs/oUF_RaidDebuffs
+!Tukui/Libs/oUF_Retail
+!Tukui/Libs/oUF_SoulShards
+!Tukui/Libs/oUF_Trinkets
+
+# Pipelines
+.release
diff --git a/.pkgmeta b/.pkgmeta
new file mode 100644
index 00000000..ddc0f23e
--- /dev/null
+++ b/.pkgmeta
@@ -0,0 +1,31 @@
+package-as: Tukui
+
+externals:
+ Tukui/Libs/CallbackHandler-1.0: https://repos.curseforge.com/wow/callbackhandler/trunk/CallbackHandler-1.0
+ Tukui/Libs/LibStub: https://repos.curseforge.com/wow/libstub/trunk
+ Tukui/Libs/SortBags: https://github.com/shirsig/SortBags
+ Tukui/Libs/SortBags_Vanilla: https://github.com/shirsig/SortBags-vanilla
+ Tukui/Libs/TaintLess:
+ url: https://www.townlong-yak.com/addons.git/taintless
+ commit: default
+
+manual-changelog:
+ filename: CHANGELOG.md
+ markup-type: markdown
+
+ignore:
+ - "*.md"
+ - "*.textile"
+ - Tukui/Libs/LibStub/tests
+
+plain-copy:
+ - Tukui/Config
+ - Tukui/Core
+ - Tukui/Licenses
+ - Tukui/Locales
+ - Tukui/Medias
+ - Tukui/Modules
+ - Tukui/Themes
+
+move-folders:
+ Tukui/Tukui: Tukui
diff --git a/Tukui/Core/Init.lua b/Tukui/Core/Init.lua
index 972c490f..c53a7a20 100644
--- a/Tukui/Core/Init.lua
+++ b/Tukui/Core/Init.lua
@@ -15,6 +15,17 @@ Engine[2] = {}
Engine[3] = {}
Engine[4] = {}
+local function ParseVersionString()
+ local version = strsub(GetAddOnMetadata(AddOn, 'Version'), 2)
+ if not strfind(version, '%-') then
+ return tonumber(version), version
+ elseif strfind(version, 'project%-version') then
+ return 99999, 'Development'
+ else
+ return 99999, version
+ end
+end
+
function Engine:unpack()
return self[1], self[2], self[3], self[4]
end
@@ -36,15 +47,13 @@ Engine[1].MyLevel = UnitLevel("player")
Engine[1].MyFaction = select(2, UnitFactionGroup("player"))
Engine[1].MyRace = select(2, UnitRace("player"))
Engine[1].MyRealm = GetRealmName()
-Engine[1].Version = GetAddOnMetadata(AddOn, "Version")
-Engine[1].VersionNumber = tonumber(Engine[1].Version)
+Engine[1].VersionNumber, Engine[1].Version = ParseVersionString()
Engine[1].WoWPatch, Engine[1].WoWBuild, Engine[1].WoWPatchReleaseDate, Engine[1].TocVersion = GetBuildInfo()
Engine[1].WoWBuild = tonumber(Engine[1].WoWBuild)
Engine[1].Hider = CreateFrame("Frame", "TukuiHider", UIParent)
Engine[1].PetHider = CreateFrame("Frame", "TukuiPetHider", UIParent, "SecureHandlerStateTemplate")
Engine[1].OffScreen = CreateFrame("Frame", "TukuiOffScreen", UIParent)
-
SLASH_RELOADUI1 = "/rl"
SlashCmdList.RELOADUI = ReloadUI
diff --git a/Tukui/Libs/CallbackHandler-1.0/CallbackHandler-1.0.lua b/Tukui/Libs/CallbackHandler-1.0/CallbackHandler-1.0.lua
deleted file mode 100644
index 39e265d0..00000000
--- a/Tukui/Libs/CallbackHandler-1.0/CallbackHandler-1.0.lua
+++ /dev/null
@@ -1,212 +0,0 @@
---[[ $Id: CallbackHandler-1.0.lua 22 2018-07-21 14:17:22Z nevcairiel $ ]]
-local MAJOR, MINOR = "CallbackHandler-1.0", 7
-local CallbackHandler = LibStub:NewLibrary(MAJOR, MINOR)
-
-if not CallbackHandler then return end -- No upgrade needed
-
-local meta = {__index = function(tbl, key) tbl[key] = {} return tbl[key] end}
-
--- Lua APIs
-local tconcat = table.concat
-local assert, error, loadstring = assert, error, loadstring
-local setmetatable, rawset, rawget = setmetatable, rawset, rawget
-local next, select, pairs, type, tostring = next, select, pairs, type, tostring
-
--- Global vars/functions that we don't upvalue since they might get hooked, or upgraded
--- List them here for Mikk's FindGlobals script
--- GLOBALS: geterrorhandler
-
-local xpcall = xpcall
-
-local function errorhandler(err)
- return geterrorhandler()(err)
-end
-
-local function Dispatch(handlers, ...)
- local index, method = next(handlers)
- if not method then return end
- repeat
- xpcall(method, errorhandler, ...)
- index, method = next(handlers, index)
- until not method
-end
-
---------------------------------------------------------------------------
--- CallbackHandler:New
---
--- target - target object to embed public APIs in
--- RegisterName - name of the callback registration API, default "RegisterCallback"
--- UnregisterName - name of the callback unregistration API, default "UnregisterCallback"
--- UnregisterAllName - name of the API to unregister all callbacks, default "UnregisterAllCallbacks". false == don't publish this API.
-
-function CallbackHandler:New(target, RegisterName, UnregisterName, UnregisterAllName)
-
- RegisterName = RegisterName or "RegisterCallback"
- UnregisterName = UnregisterName or "UnregisterCallback"
- if UnregisterAllName==nil then -- false is used to indicate "don't want this method"
- UnregisterAllName = "UnregisterAllCallbacks"
- end
-
- -- we declare all objects and exported APIs inside this closure to quickly gain access
- -- to e.g. function names, the "target" parameter, etc
-
-
- -- Create the registry object
- local events = setmetatable({}, meta)
- local registry = { recurse=0, events=events }
-
- -- registry:Fire() - fires the given event/message into the registry
- function registry:Fire(eventname, ...)
- if not rawget(events, eventname) or not next(events[eventname]) then return end
- local oldrecurse = registry.recurse
- registry.recurse = oldrecurse + 1
-
- Dispatch(events[eventname], eventname, ...)
-
- registry.recurse = oldrecurse
-
- if registry.insertQueue and oldrecurse==0 then
- -- Something in one of our callbacks wanted to register more callbacks; they got queued
- for eventname,callbacks in pairs(registry.insertQueue) do
- local first = not rawget(events, eventname) or not next(events[eventname]) -- test for empty before. not test for one member after. that one member may have been overwritten.
- for self,func in pairs(callbacks) do
- events[eventname][self] = func
- -- fire OnUsed callback?
- if first and registry.OnUsed then
- registry.OnUsed(registry, target, eventname)
- first = nil
- end
- end
- end
- registry.insertQueue = nil
- end
- end
-
- -- Registration of a callback, handles:
- -- self["method"], leads to self["method"](self, ...)
- -- self with function ref, leads to functionref(...)
- -- "addonId" (instead of self) with function ref, leads to functionref(...)
- -- all with an optional arg, which, if present, gets passed as first argument (after self if present)
- target[RegisterName] = function(self, eventname, method, ... --[[actually just a single arg]])
- if type(eventname) ~= "string" then
- error("Usage: "..RegisterName.."(eventname, method[, arg]): 'eventname' - string expected.", 2)
- end
-
- method = method or eventname
-
- local first = not rawget(events, eventname) or not next(events[eventname]) -- test for empty before. not test for one member after. that one member may have been overwritten.
-
- if type(method) ~= "string" and type(method) ~= "function" then
- error("Usage: "..RegisterName.."(\"eventname\", \"methodname\"): 'methodname' - string or function expected.", 2)
- end
-
- local regfunc
-
- if type(method) == "string" then
- -- self["method"] calling style
- if type(self) ~= "table" then
- error("Usage: "..RegisterName.."(\"eventname\", \"methodname\"): self was not a table?", 2)
- elseif self==target then
- error("Usage: "..RegisterName.."(\"eventname\", \"methodname\"): do not use Library:"..RegisterName.."(), use your own 'self'", 2)
- elseif type(self[method]) ~= "function" then
- error("Usage: "..RegisterName.."(\"eventname\", \"methodname\"): 'methodname' - method '"..tostring(method).."' not found on self.", 2)
- end
-
- if select("#",...)>=1 then -- this is not the same as testing for arg==nil!
- local arg=select(1,...)
- regfunc = function(...) self[method](self,arg,...) end
- else
- regfunc = function(...) self[method](self,...) end
- end
- else
- -- function ref with self=object or self="addonId" or self=thread
- if type(self)~="table" and type(self)~="string" and type(self)~="thread" then
- error("Usage: "..RegisterName.."(self or \"addonId\", eventname, method): 'self or addonId': table or string or thread expected.", 2)
- end
-
- if select("#",...)>=1 then -- this is not the same as testing for arg==nil!
- local arg=select(1,...)
- regfunc = function(...) method(arg,...) end
- else
- regfunc = method
- end
- end
-
-
- if events[eventname][self] or registry.recurse<1 then
- -- if registry.recurse<1 then
- -- we're overwriting an existing entry, or not currently recursing. just set it.
- events[eventname][self] = regfunc
- -- fire OnUsed callback?
- if registry.OnUsed and first then
- registry.OnUsed(registry, target, eventname)
- end
- else
- -- we're currently processing a callback in this registry, so delay the registration of this new entry!
- -- yes, we're a bit wasteful on garbage, but this is a fringe case, so we're picking low implementation overhead over garbage efficiency
- registry.insertQueue = registry.insertQueue or setmetatable({},meta)
- registry.insertQueue[eventname][self] = regfunc
- end
- end
-
- -- Unregister a callback
- target[UnregisterName] = function(self, eventname)
- if not self or self==target then
- error("Usage: "..UnregisterName.."(eventname): bad 'self'", 2)
- end
- if type(eventname) ~= "string" then
- error("Usage: "..UnregisterName.."(eventname): 'eventname' - string expected.", 2)
- end
- if rawget(events, eventname) and events[eventname][self] then
- events[eventname][self] = nil
- -- Fire OnUnused callback?
- if registry.OnUnused and not next(events[eventname]) then
- registry.OnUnused(registry, target, eventname)
- end
- end
- if registry.insertQueue and rawget(registry.insertQueue, eventname) and registry.insertQueue[eventname][self] then
- registry.insertQueue[eventname][self] = nil
- end
- end
-
- -- OPTIONAL: Unregister all callbacks for given selfs/addonIds
- if UnregisterAllName then
- target[UnregisterAllName] = function(...)
- if select("#",...)<1 then
- error("Usage: "..UnregisterAllName.."([whatFor]): missing 'self' or \"addonId\" to unregister events for.", 2)
- end
- if select("#",...)==1 and ...==target then
- error("Usage: "..UnregisterAllName.."([whatFor]): supply a meaningful 'self' or \"addonId\"", 2)
- end
-
-
- for i=1,select("#",...) do
- local self = select(i,...)
- if registry.insertQueue then
- for eventname, callbacks in pairs(registry.insertQueue) do
- if callbacks[self] then
- callbacks[self] = nil
- end
- end
- end
- for eventname, callbacks in pairs(events) do
- if callbacks[self] then
- callbacks[self] = nil
- -- Fire OnUnused callback?
- if registry.OnUnused and not next(callbacks) then
- registry.OnUnused(registry, target, eventname)
- end
- end
- end
- end
- end
- end
-
- return registry
-end
-
-
--- CallbackHandler purposefully does NOT do explicit embedding. Nor does it
--- try to upgrade old implicit embeds since the system is selfcontained and
--- relies on closures to work.
-
diff --git a/Tukui/Libs/CallbackHandler-1.0/CallbackHandler-1.0.xml b/Tukui/Libs/CallbackHandler-1.0/CallbackHandler-1.0.xml
deleted file mode 100644
index 876df83a..00000000
--- a/Tukui/Libs/CallbackHandler-1.0/CallbackHandler-1.0.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-
-
-
\ No newline at end of file
diff --git a/Tukui/Libs/LibAnim/LibAnim.lua b/Tukui/Libs/LibAnim/LibAnim.lua
index 468bfd0a..9a3d63f3 100644
--- a/Tukui/Libs/LibAnim/LibAnim.lua
+++ b/Tukui/Libs/LibAnim/LibAnim.lua
@@ -1,109 +1,110 @@
-- LibAnim by Hydra
-local Version = 2.07
+local Version = 2.901 -- based on 2.03
-if (_LibAnim and _LibAnim >= Version) then
+-- Note, deprecated items will be removed next version.
+-- Please update your usage accordingly. (ctrl + f - "Deprecated")
+
+if _G._LibAnim and _G._LibAnim >= Version then
return
end
-local pi = math.pi
-local cos = math.cos
-local sin = math.sin
-local mod = math.fmod
-local sqrt = math.sqrt
-local ceil = math.ceil
-local floor = math.floor
-local tinsert = table.insert
-local tremove = table.remove
-local lower = string.lower
-local pairs = pairs
-local Updater = CreateFrame("StatusBar")
+local Updater = CreateFrame("StatusBar", nil, nil, "BackdropTemplate")
local Texture = Updater:CreateTexture()
local FontString = Updater:CreateFontString()
-local Initialize = {}
-local Update = {}
-local Easing = {}
-local Callbacks = {["onplay"] = {}, ["onpause"] = {}, ["onresume"] = {}, ["onstop"] = {}, ["onreset"] = {}, ["onfinished"] = {}}
+local Initialize, Update, Easing = {}, {}, {}
+local Callbacks = {onplay = {}, onpause = {}, onresume = {}, onstop = {}, onreset = {}, onfinished = {}}
+local pi, cos, sin, sqrt, floor = math.pi, math.cos, math.sin, math.sqrt, math.floor
+local type, pairs, ipairs, tonumber = type, pairs, ipairs, tonumber
+local tinsert, tremove, strlower = tinsert, tremove, strlower
-- Update all current animations
-local OnUpdate = function(self, elapsed)
- for i = #self, 1, -1 do
+local AnimationOnUpdate = function(self, elapsed)
+ for i = 1, #self do
if self[i] then -- Double check that the index still exists, due to pauses/stops removing them on the fly
self[i]:Update(elapsed, i)
end
end
- if (#self == 0) then
+ if #self == 0 then
self:SetScript("OnUpdate", nil)
end
end
+local StartUpdating = function(anim)
+ tinsert(Updater, anim)
+
+ if not Updater:GetScript("OnUpdate") then
+ Updater:SetScript("OnUpdate", AnimationOnUpdate)
+ end
+end
+
local GetColor = function(p, r1, g1, b1, r2, g2, b2)
return r1 + (r2 - r1) * p, g1 + (g2 - g1) * p, b1 + (b2 - b1) * p
end
local Set = {
- ["backdrop"] = Updater.SetBackdropColor,
- ["border"] = Updater.SetBackdropBorderColor,
- ["statusbar"] = Updater.SetStatusBarColor,
- ["text"] = FontString.SetTextColor,
- ["texture"] = Texture.SetTexture,
- ["vertex"] = Texture.SetVertexColor,
+ backdrop = Updater.SetBackdropColor,
+ border = Updater.SetBackdropBorderColor,
+ statusbar = Updater.SetStatusBarColor,
+ text = FontString.SetTextColor,
+ texture = Texture.SetTexture,
+ vertex = Texture.SetVertexColor
}
local Get = {
- ["backdrop"] = Updater.GetBackdropColor,
- ["border"] = Updater.GetBackdropBorderColor,
- ["statusbar"] = Updater.GetStatusBarColor,
- ["text"] = FontString.GetTextColor,
- ["texture"] = Texture.GetVertexColor,
- ["vertex"] = Texture.GetVertexColor,
+ backdrop = Updater.GetBackdropColor,
+ border = Updater.GetBackdropBorderColor,
+ statusbar = Updater.GetStatusBarColor,
+ text = FontString.GetTextColor,
+ texture = Texture.GetVertexColor,
+ vertex = Texture.GetVertexColor
}
--- Linear easing
-Easing["linear"] = function(t, b, c, d)
+-- Linear
+local Linear = function(t, b, c, d)
return c * t / d + b
end
--- Quadratic easing
-Easing["in-quadratic"] = function(t, b, c, d)
+-- Quadratic
+local InQuadratic = function(t, b, c, d)
t = t / d
return c * (t ^ 2) + b
end
-Easing["out-quadratic"] = function(t, b, c, d)
+local OutQuadratic = function(t, b, c, d)
t = t / d
return -c * t * (t - 2) + b
end
-Easing["inout-quadratic"] = function(t, b, c, d)
+local InOutQuadratic = function(t, b, c, d)
t = t / d * 2
- if (t < 1) then
+ if t < 1 then
return c / 2 * (t ^ 2) + b
else
return -c / 2 * ((t - 1) * (t - 3) - 1) + b
end
end
--- Cubic easing
-Easing["in-cubic"] = function(t, b, c, d)
+-- Cubic
+local InCubic = function(t, b, c, d)
t = t / d
return c * (t ^ 3) + b
end
-Easing["out-cubic"] = function(t, b, c, d)
+local OutCubic = function(t, b, c, d)
t = t / d - 1
return c * (t ^ 3 + 1) + b
end
-Easing["inout-cubic"] = function(t, b, c, d)
+local InOutCubic = function(t, b, c, d)
t = t / d * 2
- if (t < 1) then
+ if t < 1 then
return c / 2 * (t ^ 3) + b
else
t = t - 2
@@ -112,23 +113,23 @@ Easing["inout-cubic"] = function(t, b, c, d)
end
end
--- Quartic easing
-Easing["in-quartic"] = function(t, b, c, d)
+-- Quartic
+local InQuartic = function(t, b, c, d)
t = t / d
return c * (t ^ 4) + b
end
-Easing["out-quartic"] = function(t, b, c, d)
+local OutQuartic = function(t, b, c, d)
t = t / d - 1
return -c * (t ^ 4 - 1) + b
end
-Easing["inout-quartic"] = function(t, b, c, d)
+local InOutQuartic = function(t, b, c, d)
t = t / d * 2
- if (t < 1) then
+ if t < 1 then
return c / 2 * t ^ 4 + b
else
t = t - 2
@@ -137,23 +138,23 @@ Easing["inout-quartic"] = function(t, b, c, d)
end
end
--- Quintic easing
-Easing["in-quintic"] = function(t, b, c, d)
+-- Quintic
+local InQuintic = function(t, b, c, d)
t = t / d
return c * (t ^ 5) + b
end
-Easing["out-quintic"] = function(t, b, c, d)
+local OutQuintic = function(t, b, c, d)
t = t / d - 1
return c * (t ^ 5 + 1) + b
end
-Easing["inout-quintic"] = function(t, b, c, d)
+local InOutQuintic = function(t, b, c, d)
t = t / d * 2
- if (t < 1) then
+ if t < 1 then
return c / 2 * t ^ 5 + b
else
t = t - 2
@@ -162,48 +163,48 @@ Easing["inout-quintic"] = function(t, b, c, d)
end
end
--- Sinusoidal easing
-Easing["in-sinusoidal"] = function(t, b, c, d)
+-- Sinusoidal
+local InSinusoidal = function(t, b, c, d)
return -c * cos(t / d * (pi / 2)) + c + b
end
-Easing["out-sinusoidal"] = function(t, b, c, d)
+local OutSinusoidal = function(t, b, c, d)
return c * sin(t / d * (pi / 2)) + b
end
-Easing["inout-sinusoidal"] = function(t, b, c, d)
+local InOutSinusoidal = function(t, b, c, d)
return -c / 2 * (cos(pi * t / d) - 1) + b
end
--- Exponential easing
-Easing["in-exponential"] = function(t, b, c, d)
- if (t == 0) then
+-- Exponential
+local InExponential = function(t, b, c, d)
+ if t == 0 then
return b
else
return c * (2 ^ (10 * (t / d - 1))) + b - c * 0.001
end
end
-Easing["out-exponential"] = function(t, b, c, d)
- if (t == d) then
+local OutExponential = function(t, b, c, d)
+ if t == d then
return b + c
else
return c * 1.001 * (-(2 ^ (-10 * t / d)) + 1) + b
end
end
-Easing["inout-exponential"] = function(t, b, c, d)
- if (t == 0) then
+local InOutExponential = function(t, b, c, d)
+ if t == 0 then
return b
end
- if (t == d) then
+ if t == d then
return b + c
end
t = t / d * 2
- if (t < 1) then
+ if t < 1 then
return c / 2 * (2 ^ (10 * (t - 1))) + b - c * 0.0005
else
t = t - 1
@@ -212,23 +213,23 @@ Easing["inout-exponential"] = function(t, b, c, d)
end
end
--- Circular easing
-Easing["in-circular"] = function(t, b, c, d)
+-- Circular
+local InCircular = function(t, b, c, d)
t = t / d
return (-c * (sqrt(1 - t * t) - 1) + b)
end
-Easing["out-circular"] = function(t, b, c, d)
+local OutCircular = function(t, b, c, d)
t = t / d - 1
return (c * sqrt(1 - t * t) + b)
end
-Easing["inout-circular"] = function(t, b, c, d)
+local InOutCircular = function(t, b, c, d)
t = t / d * 2
- if (t < 1) then
+ if t < 1 then
return -c / 2 * (sqrt(1 - t * t) - 1) + b
else
t = t - 2
@@ -237,17 +238,17 @@ Easing["inout-circular"] = function(t, b, c, d)
end
end
--- Bounce easing
-Easing["out-bounce"] = function(t, b, c, d)
+-- Bounce
+local OutBounce = function(t, b, c, d)
t = t / d
- if (t < (1 / 2.75)) then
+ if t < (1 / 2.75) then
return c * (7.5625 * t * t) + b
- elseif (t < (2 / 2.75)) then
+ elseif t < (2 / 2.75) then
t = t - (1.5 / 2.75)
return c * (7.5625 * t * t + 0.75) + b
- elseif (t < (2.5 / 2.75)) then
+ elseif t < (2.5 / 2.75) then
t = t - (2.25 / 2.75)
return c * (7.5625 * t * t + 0.9375) + b
@@ -258,27 +259,27 @@ Easing["out-bounce"] = function(t, b, c, d)
end
end
-Easing["in-bounce"] = function(t, b, c, d)
- return c - Easing["out-bounce"](d - t, 0, c, d) + b
+local InBounce = function(t, b, c, d)
+ return c - OutBounce(d - t, 0, c, d) + b
end
-Easing["inout-bounce"] = function(t, b, c, d)
- if (t < d / 2) then
- return Easing["in-bounce"](t * 2, 0, c, d) * 0.5 + b
+local InOutBounce = function(t, b, c, d)
+ if t < d / 2 then
+ return InBounce(t * 2, 0, c, d) * 0.5 + b
else
- return Easing["out-bounce"](t * 2 - d, 0, c, d) * 0.5 + c * 0.5 + b
+ return OutBounce(t * 2 - d, 0, c, d) * 0.5 + c * 0.5 + b
end
end
--- Elastic easing
-Easing["in-elastic"] = function(t, b, c, d)
- if (t == 0) then
+-- Elastic
+local InElastic = function(t, b, c, d)
+ if t == 0 then
return b
end
t = t / d
- if (t == 1) then
+ if t == 1 then
return b + c
end
@@ -291,14 +292,14 @@ Easing["in-elastic"] = function(t, b, c, d)
return -(a * 2 ^ (10 * t) * sin((t * d - s) * (2 * pi) / p)) + b
end
-Easing["out-elastic"] = function(t, b, c, d)
- if (t == 0) then
+local OutElastic = function(t, b, c, d)
+ if t == 0 then
return b
end
t = t / d
- if (t == 1) then
+ if t == 1 then
return b + c
end
@@ -309,14 +310,14 @@ Easing["out-elastic"] = function(t, b, c, d)
return a * 2 ^ (-10 * t) * sin((t * d - s) * (2 * pi) / p) + c + b
end
-Easing["inout-elastic"] = function(t, b, c, d)
- if (t == 0) then
+local InOutElastic = function(t, b, c, d)
+ if t == 0 then
return b
end
t = t / d * 2
- if (t == 2) then
+ if t == 2 then
return b + c
end
@@ -324,7 +325,7 @@ Easing["inout-elastic"] = function(t, b, c, d)
local p = d * (0.3 * 1.5)
local s = p / 4
- if (t < 1) then
+ if t < 1 then
t = t - 1
return -0.5 * (a * 2 ^ (10 * t) * sin((t * d - s) * (2 * pi) / p)) + b
@@ -335,19 +336,49 @@ Easing["inout-elastic"] = function(t, b, c, d)
end
end
--- Simple options
+Easing["linear"] = Linear
+Easing["in-quadratic"] = InQuadratic
+Easing["out-quadratic"] = OutQuadratic
+Easing["inout-quadratic"] = InOutQuadratic
+Easing["in-cubic"] = InCubic
+Easing["out-cubic"] = OutCubic
+Easing["inout-cubic"] = InOutCubic
+Easing["in-quartic"] = InQuartic
+Easing["out-quartic"] = OutQuartic
+Easing["inout-quartic"] = InOutQuartic
+Easing["in-quintic"] = InQuintic
+Easing["out-quintic"] = OutQuintic
+Easing["inout-quintic"] = InOutQuintic
+Easing["in-sinusoidal"] = InSinusoidal
+Easing["out-sinusoidal"] = OutSinusoidal
+Easing["inout-sinusoidal"] = InOutSinusoidal
+Easing["in-exponential"] = InExponential
+Easing["out-exponential"] = OutExponential
+Easing["inout-exponential"] = InOutExponential
+Easing["in-circular"] = InCircular
+Easing["out-circular"] = OutCircular
+Easing["inout-circular"] = InOutCircular
+Easing["in-bounce"] = InBounce
+Easing["out-bounce"] = OutBounce
+Easing["inout-bounce"] = InOutBounce
+Easing["in-elastic"] = InElastic
+Easing["out-elastic"] = OutElastic
+Easing["inout-elastic"] = InOutElastic
+
+-- Some fallbacks / lazy options
Easing["in"] = Easing["in-quadratic"]
Easing["out"] = Easing["out-quadratic"]
Easing["inout"] = Easing["inout-quadratic"]
+Easing["bounce"] = Easing["out-bounce"] -- Deprecated, don't use bounce without an explicit motion anymore
local AnimMethods = {
All = {
Play = function(self)
- if (not self.Paused) then
+ if not self.Paused then
Initialize[self.Type](self)
self:Callback("OnPlay")
else
- self:StartUpdating()
+ StartUpdating(self)
self:Callback("OnResume")
end
@@ -362,7 +393,7 @@ local AnimMethods = {
Pause = function(self)
for i = 1, #Updater do
- if (Updater[i] == self) then
+ if Updater[i] == self then
tremove(Updater, i)
break
@@ -381,7 +412,7 @@ local AnimMethods = {
Stop = function(self, reset)
for i = 1, #Updater do
- if (Updater[i] == self) then
+ if Updater[i] == self then
tremove(Updater, i)
break
@@ -406,7 +437,7 @@ local AnimMethods = {
end,
SetEasing = function(self, easing)
- easing = lower(easing)
+ easing = strlower(easing)
self.Easing = Easing[easing] and easing or "linear"
end,
@@ -415,6 +446,16 @@ local AnimMethods = {
return self.Easing
end,
+ SetSmoothing = function(self, easing) -- Deprecated, change "SetSmoothing" to "SetEasing"
+ easing = strlower(easing)
+
+ self.Easing = Easing[easing] and easing or "linear"
+ end,
+
+ GetSmoothing = function(self) -- Deprecated, change "GetSmoothing" to "GetEasing"
+ return self.Easing
+ end,
+
SetDuration = function(self, duration)
self.Duration = duration or 0
end,
@@ -430,7 +471,7 @@ local AnimMethods = {
SetOrder = function(self, order)
self.Order = order or 1
- if (order > self.Group.MaxOrder) then
+ if order > self.Group.MaxOrder then
self.Group.MaxOrder = order
end
end,
@@ -443,8 +484,29 @@ local AnimMethods = {
return self.Parent
end,
+ AddChild = function(self, child, mainChild)
+ if not self.children then self.children = {} end
+ if not self.mainChild then
+ self.mainChild = mainChild or child
+ elseif mainChild then
+ self.mainChild = mainChild
+ end
+ tinsert(self.children, child)
+ end,
+
+ RemoveChild = function(self, child)
+ if not self.children then return end
+ local checkIndex = type(child) == 'number'
+ for index, tchild in ipairs(self.children) do
+ if (checkIndex and index == child) or tchild == child then
+ tremove(self.children, index)
+ break
+ end
+ end
+ end,
+
SetScript = function(self, handler, func)
- handler = lower(handler)
+ handler = strlower(handler)
if Callbacks[handler] then
Callbacks[handler][self] = func
@@ -452,28 +514,20 @@ local AnimMethods = {
end,
GetScript = function(self, handler)
- handler = lower(handler)
+ handler = strlower(handler)
- if (Callbacks[handler] and Callbacks[handler][self]) then
+ if Callbacks[handler] and Callbacks[handler][self] then
return Callbacks[handler][self]
end
end,
Callback = function(self, handler)
- handler = lower(handler)
+ handler = strlower(handler)
if Callbacks[handler][self] then
Callbacks[handler][self](self)
end
end,
-
- StartUpdating = function(self)
- tinsert(Updater, self)
-
- if (not Updater:GetScript("OnUpdate")) then
- Updater:SetScript("OnUpdate", OnUpdate)
- end
- end,
},
move = {
@@ -507,17 +561,6 @@ local AnimMethods = {
self.ModTimer = 0
end
end,
-
- Finish = function(self)
- self:Stop()
-
- if self.IsRounded then
- self.ModTimer = 0
- end
-
- self.Parent:ClearAllPoints()
- self.Parent:SetPoint(self.A1, self.P, self.A2, self.EndX, self.EndY)
- end,
},
fade = {
@@ -530,18 +573,13 @@ local AnimMethods = {
end,
GetProgress = function(self)
- return self.CurrentValue
+ return self.AlphaOffset
end,
Reset = function(self)
self.Timer = 0
self.Parent:SetAlpha(self.StartAlpha)
end,
-
- Finish = function(self)
- self:Stop()
- self.Parent:SetAlpha(self.EndAlpha)
- end,
},
height = {
@@ -554,18 +592,13 @@ local AnimMethods = {
end,
GetProgress = function(self)
- return self.CurrentValue
+ return self.HeightOffset
end,
Reset = function(self)
self.Timer = 0
self.Parent:SetHeight(self.StartHeight)
end,
-
- Finish = function(self)
- self:Stop()
- self.Parent:SetHeight(self.EndHeight)
- end,
},
width = {
@@ -578,18 +611,13 @@ local AnimMethods = {
end,
GetProgress = function(self)
- return self.CurrentValue
+ return self.WidthOffset
end,
Reset = function(self)
self.Timer = 0
self.Parent:SetWidth(self.StartWidth)
end,
-
- Finish = function(self)
- self:Stop()
- self.Parent:SetWidth(self.EndWidth)
- end,
},
color = {
@@ -604,9 +632,9 @@ local AnimMethods = {
end,
SetColorType = function(self, region)
- region = lower(region)
+ region = strlower(region)
- self.ColorType = Set[region] and region or "border"
+ self.ColorType = (Set[region] and region) or "border"
end,
GetColorType = function(self)
@@ -614,18 +642,13 @@ local AnimMethods = {
end,
GetProgress = function(self)
- return self.CurrentValue
+ return self.ColorOffset
end,
Reset = function(self)
self.Timer = 0
Set[self.ColorType](self.Parent, self.StartR, self.StartG, self.StartB)
end,
-
- Finish = function(self)
- self:Stop()
- Set[self.ColorType](self.Parent, self.EndR, self.EndG, self.EndB)
- end,
},
progress = {
@@ -638,18 +661,13 @@ local AnimMethods = {
end,
GetProgress = function(self)
- return self.CurrentValue
+ return self.ValueOffset
end,
Reset = function(self)
self.Timer = 0
self.Parent:SetValue(self.StartValue)
end,
-
- Finish = function(self)
- self:Stop()
- self.Parent:SetValue(self.EndValue)
- end,
},
number = {
@@ -686,18 +704,13 @@ local AnimMethods = {
end,
GetProgress = function(self)
- return self.CurrentValue
+ return self.NumberOffset
end,
Reset = function(self)
self.Timer = 0
self.Parent:SetText(self.StartNumber)
end,
-
- Finish = function(self)
- self:Stop()
- self.Parent:SetText(self.EndNumber)
- end,
},
sleep = {
@@ -708,87 +721,13 @@ local AnimMethods = {
Reset = function(self)
self.Timer = 0
end,
-
- Finish = function(self)
- self:Stop()
- end,
- },
-
- scale = {
- SetChange = function(self, width)
- self.EndScaleSetting = width or 0
- end,
-
- GetChange = function(self)
- return self.EndScaleSetting
- end,
-
- GetProgress = function(self)
- return self.CurrentValue
- end,
-
- Reset = function(self)
- self.Timer = 0
- end,
-
- Finish = function(self)
- self:Stop()
- self.Parent:SetScale(self.EndScale)
- end,
- },
-
- frames = {
- SetTextureSize = function(self, width, height)
- self.TextureWidthSetting = width or 0
- self.TextureHeightSetting = height or width or 0
- end,
-
- GetTextureSize = function(self)
- return self.TextureWidthSetting, self.TextureHeightSetting
- end,
-
- SetFrameSize = function(self, size)
- self.FrameSizeSetting = size or 0
- end,
-
- GetFrameSize = function(self)
- return self.FrameSizeSetting
- end,
-
- SetNumFrames = function(self, frames)
- self.NumFramesSetting = frames or 0
- end,
-
- GetNumFrames = function(self)
- return self.NumFramesSetting
- end,
-
- SetFrameDelay = function(self, delay)
- self.DelaySetting = delay or 0
- end,
-
- GetFrameDelay = function(self)
- return self.DelaySetting
- end,
-
- GetProgress = function(self)
- return self.Frame
- end,
-
- Reset = function(self)
- self.Timer = 0
- end,
-
- Finish = function(self)
- self:Stop()
- end,
},
}
local GroupMethods = {
Play = function(self)
for i = 1, #self.Animations do
- if (self.Animations[i].Order == self.Order) then
+ if self.Animations[i].Order == self.Order then
self.Animations[i]:Play()
end
end
@@ -806,7 +745,7 @@ local GroupMethods = {
Pause = function(self)
for i = 1, #self.Animations do
- if (self.Animations[i].Order == self.Order) then
+ if self.Animations[i].Order == self.Order then
self.Animations[i]:Pause()
end
end
@@ -852,7 +791,7 @@ local GroupMethods = {
end,
SetScript = function(self, handler, func)
- handler = lower(handler)
+ handler = strlower(handler)
if Callbacks[handler] then
Callbacks[handler][self] = func
@@ -860,15 +799,15 @@ local GroupMethods = {
end,
GetScript = function(self, handler)
- handler = lower(handler)
+ handler = strlower(handler)
- if (Callbacks[handler] and Callbacks[handler][self]) then
+ if Callbacks[handler] and Callbacks[handler][self] then
return Callbacks[handler][self]
end
end,
Callback = function(self, handler)
- handler = lower(handler)
+ handler = strlower(handler)
if Callbacks[handler][self] then
Callbacks[handler][self](self)
@@ -881,26 +820,26 @@ local GroupMethods = {
local NumDoneAtOrder = 0
for i = 1, #self.Animations do
- if (self.Animations[i].Order == self.Order) then
+ if self.Animations[i].Order == self.Order then
NumAtOrder = NumAtOrder + 1
- if (not self.Animations[i].Playing) then
+ if not self.Animations[i].Playing then
NumDoneAtOrder = NumDoneAtOrder + 1
end
end
end
-- All the animations at x order finished, go to next order
- if (NumAtOrder == NumDoneAtOrder) then
+ if NumAtOrder == NumDoneAtOrder then
self.Order = self.Order + 1
-- We exceeded max order, reset to 1 and bail the function, or restart if we're looping
- if (self.Order > self.MaxOrder) then
+ if self.Order > self.MaxOrder then
self.Order = 1
self:Callback("OnFinished")
- if (self.Stopped or not self.Looping) then
+ if self.Stopped or not self.Looping then
self.Playing = false
return
@@ -909,7 +848,7 @@ local GroupMethods = {
-- Play!
for i = 1, #self.Animations do
- if (self.Animations[i].Order == self.Order) then
+ if self.Animations[i].Order == self.Order then
self.Animations[i]:Play()
end
end
@@ -917,9 +856,9 @@ local GroupMethods = {
end,
CreateAnimation = function(self, style)
- style = lower(style)
+ style = strlower(style)
- if (not Initialize[style]) then
+ if not Initialize[style] then
return
end
@@ -956,7 +895,7 @@ local GroupMethods = {
end,
}
-CreateAnimationGroup = function(parent)
+_G.CreateAnimationGroup = function(parent)
local Group = {Animations = {}}
-- Add methods to the group
@@ -975,7 +914,7 @@ CreateAnimationGroup = function(parent)
end
-- Movement
-Initialize["move"] = function(self)
+Initialize.move = function(self)
if self.Playing then
return
end
@@ -994,20 +933,20 @@ Initialize["move"] = function(self)
self.YChange = self.EndY - self.StartY
if self.IsRounded then
- if (self.XChange == 0 or self.YChange == 0) then -- Double check if we're valid to be rounded
+ if self.XChange == 0 or self.YChange == 0 then -- Double check if we're valid to be rounded
self.IsRounded = false
else
self.ModTimer = 0
end
end
- self:StartUpdating()
+ StartUpdating(self)
end
-Update["move"] = function(self, elapsed, i)
+Update.move = function(self, elapsed, i)
self.Timer = self.Timer + elapsed
- if (self.Timer >= self.Duration) then
+ if self.Timer >= self.Duration then
tremove(Updater, i)
self.Parent:SetPoint(self.A1, self.P, self.A2, self.EndX, self.EndY)
self.Playing = false
@@ -1028,36 +967,51 @@ Update["move"] = function(self, elapsed, i)
end
-- Fade
-Initialize["fade"] = function(self)
+Initialize.fade = function(self)
if self.Playing then
return
end
self.Timer = 0
- self.StartAlpha = self.Parent:GetAlpha() or 1
+ self.StartAlpha = (self.mainChild or self.Parent):GetAlpha() or 1
self.EndAlpha = self.EndAlphaSetting or 0
self.Change = self.EndAlpha - self.StartAlpha
- self:StartUpdating()
+ StartUpdating(self)
end
-Update["fade"] = function(self, elapsed, i)
+Update.fade = function(self, elapsed, i)
self.Timer = self.Timer + elapsed
- if (self.Timer >= self.Duration) then
+ if self.Timer >= self.Duration then
tremove(Updater, i)
- self.Parent:SetAlpha(self.EndAlpha)
+
+ if self.children then
+ for _, child in pairs(self.children) do
+ child:SetAlpha(self.EndAlpha)
+ end
+ else
+ self.Parent:SetAlpha(self.EndAlpha)
+ end
+
self.Playing = false
self:Callback("OnFinished")
self.Group:CheckOrder()
- else
- self.CurrentValue = Easing[self.Easing](self.Timer, self.StartAlpha, self.Change, self.Duration)
- self.Parent:SetAlpha(self.CurrentValue)
+ elseif self.children then
+ self.AlphaOffset = Easing[self.Easing](self.Timer, self.StartAlpha, self.Change, self.Duration)
+ for _, child in pairs(self.children) do
+ if child:IsShown() then
+ child:SetAlpha(self.AlphaOffset)
+ end
+ end
+ elseif self.Parent:IsShown() then
+ self.AlphaOffset = Easing[self.Easing](self.Timer, self.StartAlpha, self.Change, self.Duration)
+ self.Parent:SetAlpha(self.AlphaOffset)
end
end
-- Height
-Initialize["height"] = function(self)
+Initialize.height = function(self)
if self.Playing then
return
end
@@ -1067,26 +1021,26 @@ Initialize["height"] = function(self)
self.EndHeight = self.EndHeightSetting or 0
self.HeightChange = self.EndHeight - self.StartHeight
- self:StartUpdating()
+ StartUpdating(self)
end
-Update["height"] = function(self, elapsed, i)
+Update.height = function(self, elapsed, i)
self.Timer = self.Timer + elapsed
- if (self.Timer >= self.Duration) then
+ if self.Timer >= self.Duration then
tremove(Updater, i)
self.Parent:SetHeight(self.EndHeight)
self.Playing = false
self:Callback("OnFinished")
self.Group:CheckOrder()
else
- self.CurrentValue = Easing[self.Easing](self.Timer, self.StartHeight, self.HeightChange, self.Duration)
- self.Parent:SetHeight(self.CurrentValue)
+ self.HeightOffset = Easing[self.Easing](self.Timer, self.StartHeight, self.HeightChange, self.Duration)
+ self.Parent:SetHeight(self.HeightOffset)
end
end
-- Width
-Initialize["width"] = function(self)
+Initialize.width = function(self)
if self.Playing then
return
end
@@ -1096,87 +1050,98 @@ Initialize["width"] = function(self)
self.EndWidth = self.EndWidthSetting or 0
self.WidthChange = self.EndWidth - self.StartWidth
- self:StartUpdating()
+ StartUpdating(self)
end
-Update["width"] = function(self, elapsed, i)
+Update.width = function(self, elapsed, i)
self.Timer = self.Timer + elapsed
- if (self.Timer >= self.Duration) then
+ if self.Timer >= self.Duration then
tremove(Updater, i)
self.Parent:SetWidth(self.EndWidth)
self.Playing = false
self:Callback("OnFinished")
self.Group:CheckOrder()
else
- self.CurrentValue = Easing[self.Easing](self.Timer, self.StartWidth, self.WidthChange, self.Duration)
- self.Parent:SetWidth(self.CurrentValue)
+ self.WidthOffset = Easing[self.Easing](self.Timer, self.StartWidth, self.WidthChange, self.Duration)
+ self.Parent:SetWidth(self.WidthOffset)
end
end
-- Color
-Initialize["color"] = function(self)
+Initialize.color = function(self)
self.Timer = 0
self.ColorType = self.ColorType or "backdrop"
- self.StartR, self.StartG, self.StartB = Get[self.ColorType](self.Parent)
+ self.StartR, self.StartG, self.StartB = Get[self.ColorType](self.mainChild or self.Parent)
self.EndR = self.EndRSetting or 1
self.EndG = self.EndGSetting or 1
self.EndB = self.EndBSetting or 1
- self:StartUpdating()
+ StartUpdating(self)
end
-Update["color"] = function(self, elapsed, i)
+Update.color = function(self, elapsed, i)
self.Timer = self.Timer + elapsed
- if (self.Timer >= self.Duration) then
+ if self.Timer >= self.Duration then
tremove(Updater, i)
- Set[self.ColorType](self.Parent, self.EndR, self.EndG, self.EndB)
+ if self.children then
+ for _, child in pairs(self.children) do
+ Set[self.ColorType](child, self.EndR, self.EndG, self.EndB)
+ end
+ else
+ Set[self.ColorType](self.Parent, self.EndR, self.EndG, self.EndB)
+ end
self.Playing = false
self:Callback("OnFinished")
self.Group:CheckOrder()
+ elseif self.children then
+ self.ColorOffset = Easing[self.Easing](self.Timer, 0, self.Duration, self.Duration)
+ for _, child in pairs(self.children) do
+ Set[self.ColorType](child, GetColor(self.Timer / self.Duration, self.StartR, self.StartG, self.StartB, self.EndR, self.EndG, self.EndB))
+ end
else
- self.CurrentValue = Easing[self.Easing](self.Timer, 0, self.Duration, self.Duration)
+ self.ColorOffset = Easing[self.Easing](self.Timer, 0, self.Duration, self.Duration)
Set[self.ColorType](self.Parent, GetColor(self.Timer / self.Duration, self.StartR, self.StartG, self.StartB, self.EndR, self.EndG, self.EndB))
end
end
-- Progress
-Initialize["progress"] = function(self)
+Initialize.progress = function(self)
self.Timer = 0
self.StartValue = self.Parent:GetValue() or 0
self.EndValue = self.EndValueSetting or 0
self.ProgressChange = self.EndValue - self.StartValue
- self:StartUpdating()
+ StartUpdating(self)
end
-Update["progress"] = function(self, elapsed, i)
+Update.progress = function(self, elapsed, i)
self.Timer = self.Timer + elapsed
- if (self.Timer >= self.Duration) then
+ if self.Timer >= self.Duration then
tremove(Updater, i)
self.Parent:SetValue(self.EndValue)
self.Playing = false
self:Callback("OnFinished")
self.Group:CheckOrder()
else
- self.CurrentValue = Easing[self.Easing](self.Timer, self.StartValue, self.ProgressChange, self.Duration)
- self.Parent:SetValue(self.CurrentValue)
+ self.ValueOffset = Easing[self.Easing](self.Timer, self.StartValue, self.ProgressChange, self.Duration)
+ self.Parent:SetValue(self.ValueOffset)
end
end
-- Sleep
-Initialize["sleep"] = function(self)
+Initialize.sleep = function(self)
self.Timer = 0
- self:StartUpdating()
+ StartUpdating(self)
end
-Update["sleep"] = function(self, elapsed, i)
+Update.sleep = function(self, elapsed, i)
self.Timer = self.Timer + elapsed
- if (self.Timer >= self.Duration) then
+ if self.Timer >= self.Duration then
tremove(Updater, i)
self.Playing = false
self:Callback("OnFinished")
@@ -1185,10 +1150,10 @@ Update["sleep"] = function(self, elapsed, i)
end
-- Number
-Initialize["number"] = function(self)
+Initialize.number = function(self)
self.Timer = 0
- if (not self.StartNumber) then
+ if not self.StartNumber then
self.StartNumber = tonumber(self.Parent:GetText()) or 0
end
@@ -1197,103 +1162,72 @@ Initialize["number"] = function(self)
self.Prefix = self.Prefix or ""
self.Postfix = self.Postfix or ""
- self:StartUpdating()
+ StartUpdating(self)
end
-Update["number"] = function(self, elapsed, i)
+Update.number = function(self, elapsed, i)
self.Timer = self.Timer + elapsed
- if (self.Timer >= self.Duration) then
+ if self.Timer >= self.Duration then
tremove(Updater, i)
self.Parent:SetText(self.Prefix..floor(self.EndNumber)..self.Postfix)
self.Playing = false
self:Callback("OnFinished")
self.Group:CheckOrder()
else
- self.CurrentValue = Easing[self.Easing](self.Timer, self.StartNumber, self.NumberChange, self.Duration)
- self.Parent:SetText(self.Prefix..floor(self.CurrentValue)..self.Postfix)
+ self.NumberOffset = Easing[self.Easing](self.Timer, self.StartNumber, self.NumberChange, self.Duration)
+ self.Parent:SetText(self.Prefix..floor(self.NumberOffset)..self.Postfix)
end
end
--- Scale
-Initialize["scale"] = function(self)
- if self.Playing then
+-- Global exposure
+_G._LibAnim = Version
+_G.LibAnimStartUpdating = StartUpdating
+_G.LibAnimUpdater = Updater
+_G.LibAnimAddType = function(name, init, update)
+ if type(init) ~= "function" or type(update) ~= "function" then
return
end
- self.Timer = 0
- self.StartScale = self.Parent:GetScale() or 1
- self.EndScale = self.EndScaleSetting or 1
- self.ScaleChange = self.EndScale - self.StartScale
+ name = strlower(name)
- self:StartUpdating()
-end
-
-Update["scale"] = function(self, elapsed, i)
- self.Timer = self.Timer + elapsed
-
- if (self.Timer >= self.Duration) then
- tremove(Updater, i)
- self.Parent:SetScale(self.EndScale)
- self.Playing = false
- self:Callback("OnFinished")
- self.Group:CheckOrder()
- else
- self.CurrentValue = Easing[self.Easing](self.Timer, self.StartScale, self.ScaleChange, self.Duration)
- self.Parent:SetScale(self.CurrentValue)
- end
-end
-
--- Frames
-Initialize["frames"] = function(self)
- if self.Playing then
+ if Initialize[name] then
return
end
- self.Timer = 0
- self.Frame = 1
- self.Delay = self.DelaySetting or 0
- self.Throttle = self.Delay
- self.NumFrames = self.NumFramesSetting or 0
- self.TextureWidth = self.TextureWidthSetting or self.Parent:GetWidth()
- self.TextureHeight = self.TextureHeightSetting or self.Parent:GetHeight()
- self.FrameSize = self.FrameSizeSetting or 0
- self.NumColumns = floor(self.TextureWidth / self.FrameSize)
- self.ColumnWidth = self.FrameSize / self.TextureWidth
- self.NumRows = floor(self.TextureHeight / self.FrameSize)
- self.RowHeight = self.FrameSize / self.TextureHeight
-
- self:StartUpdating()
+ Initialize[name] = init
+ Update[name] = update
end
-Update["frames"] = function(self, elapsed, i)
- self.Timer = self.Timer + elapsed
+--[[
+ Want to create your own animations for this system? Follow the example below
+ If you make a custom animation I would love to see it!
- if (self.Timer >= self.Duration) then
- tremove(Updater, i)
- self.Playing = false
- self:Callback("OnFinished")
- self.Group:CheckOrder()
- else
- if (self.Throttle > self.Delay) then
- local Advance = floor(self.Throttle / self.Delay)
+ Example:
- while (self.Frame + Advance > self.NumFrames) do
- self.Frame = self.Frame - self.NumFrames
- end
+ local MyInitialize = function(self)
+ self.Timer = 0
- self.Frame = self.Frame + Advance
+ -- do any initialization right before the animation plays
- local Left = mod(self.Frame - 1, self.NumColumns) * self.ColumnWidth
- local Bottom = ceil(self.Frame / self.NumColumns) * self.RowHeight
+ LibAnimStartUpdating(self)
+ end
- self.Parent:SetTexCoord(Left, Left + self.ColumnWidth, Bottom - self.RowHeight, Bottom)
- self.Throttle = 0
- end
+ local MyUpdate = function(self, elapsed, i)
+ self.Timer = self.Timer + elapsed
+
+ if self.Timer >= self.Duration then
+ table.remove(LibAnimUpdater, i)
- self.Throttle = self.Throttle + elapsed
+ -- Set finished attributes here
+
+ self.Playing = false
+ self:Callback("OnFinished")
+ self.Group:CheckOrder()
+ else
+ -- Do any updating necessary here
+ end
end
-end
--- Global exposure
-_G["_LibAnim"] = Version
+ LibAnimAddType("MyAnim", MyInitialize, MyUpdate)
+--]]
diff --git a/Tukui/Libs/LibDeflate/LICENSE.txt b/Tukui/Libs/LibDeflate/LICENSE.txt
deleted file mode 100644
index 697547d0..00000000
--- a/Tukui/Libs/LibDeflate/LICENSE.txt
+++ /dev/null
@@ -1,50 +0,0 @@
-
GNU LESSER GENERAL PUBLIC LICENSE
-
Version 3, 29 June 2007
-
Copyright (C) 2007 Free Software Foundation, Inc. http://fsf.org
-
Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed.
-
This version of the GNU Lesser General Public License incorporates the terms and conditions of version 3 of the GNU General Public License, supplemented by the additional permissions listed below.
-
0. Additional Definitions.
-
As used herein, “this License” refers to version 3 of the GNU Lesser General Public License, and the “GNU GPL” refers to version 3 of the GNU General Public License.
-
“The Library” refers to a covered work governed by this License, other than an Application or a Combined Work as defined below.
-
An “Application” is any work that makes use of an interface provided by the Library, but which is not otherwise based on the Library. Defining a subclass of a class defined by the Library is deemed a mode of using an interface provided by the Library.
-
A “Combined Work” is a work produced by combining or linking an Application with the Library. The particular version of the Library with which the Combined Work was made is also called the “Linked Version”.
-
The “Minimal Corresponding Source” for a Combined Work means the Corresponding Source for the Combined Work, excluding any source code for portions of the Combined Work that, considered in isolation, are based on the Application, and not on the Linked Version.
-
The “Corresponding Application Code” for a Combined Work means the object code and/or source code for the Application, including any data and utility programs needed for reproducing the Combined Work from the Application, but excluding the System Libraries of the Combined Work.
-
1. Exception to Section 3 of the GNU GPL.
-
You may convey a covered work under sections 3 and 4 of this License without being bound by section 3 of the GNU GPL.
-
2. Conveying Modified Versions.
-
If you modify a copy of the Library, and, in your modifications, a facility refers to a function or data to be supplied by an Application that uses the facility (other than as an argument passed when the facility is invoked), then you may convey a copy of the modified version:
-
-
a) under this License, provided that you make a good faith effort to ensure that, in the event an Application does not supply the function or data, the facility still operates, and performs whatever part of its purpose remains meaningful, or
-
b) under the GNU GPL, with none of the additional permissions of this License applicable to that copy.
-
-
3. Object Code Incorporating Material from Library Header Files.
-
The object code form of an Application may incorporate material from a header file that is part of the Library. You may convey such object code under terms of your choice, provided that, if the incorporated material is not limited to numerical parameters, data structure layouts and accessors, or small macros, inline functions and templates (ten or fewer lines in length), you do both of the following:
-
-
a) Give prominent notice with each copy of the object code that the Library is used in it and that the Library and its use are covered by this License.
-
b) Accompany the object code with a copy of the GNU GPL and this license document.
-
-
4. Combined Works.
-
You may convey a Combined Work under terms of your choice that, taken together, effectively do not restrict modification of the portions of the Library contained in the Combined Work and reverse engineering for debugging such modifications, if you also do each of the following:
-
-
a) Give prominent notice with each copy of the Combined Work that the Library is used in it and that the Library and its use are covered by this License.
-
b) Accompany the Combined Work with a copy of the GNU GPL and this license document.
-
c) For a Combined Work that displays copyright notices during execution, include the copyright notice for the Library among these notices, as well as a reference directing the user to the copies of the GNU GPL and this license document.
-
d) Do one of the following:
-
-
0) Convey the Minimal Corresponding Source under the terms of this License, and the Corresponding Application Code in a form suitable for, and under terms that permit, the user to recombine or relink the Application with a modified version of the Linked Version to produce a modified Combined Work, in the manner specified by section 6 of the GNU GPL for conveying Corresponding Source.
-
1) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (a) uses at run time a copy of the Library already present on the user's computer system, and (b) will operate properly with a modified version of the Library that is interface-compatible with the Linked Version.
-
-
-
e) Provide Installation Information, but only if you would otherwise be required to provide such information under section 6 of the GNU GPL, and only to the extent that such information is necessary to install and execute a modified version of the Combined Work produced by recombining or relinking the Application with a modified version of the Linked Version. (If you use option 4d0, the Installation Information must accompany the Minimal Corresponding Source and Corresponding Application Code. If you use option 4d1, you must provide the Installation Information in the manner specified by section 6 of the GNU GPL for conveying Corresponding Source.)
-
-
5. Combined Libraries.
-
You may place library facilities that are a work based on the Library side by side in a single library together with other library facilities that are not Applications and are not covered by this License, and convey such a combined library under terms of your choice, if you do both of the following:
-
-
a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities, conveyed under the terms of this License.
-
b) Give prominent notice with the combined library that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work.
-
-
6. Revised Versions of the GNU Lesser General Public License.
-
The Free Software Foundation may publish revised and/or new versions of the GNU Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns.
-
Each version is given a distinguishing version number. If the Library as you received it specifies that a certain numbered version of the GNU Lesser General Public License “or any later version” applies to it, you have the option of following the terms and conditions either of that published version or of any later version published by the Free Software Foundation. If the Library as you received it does not specify a version number of the GNU Lesser General Public License, you may choose any version of the GNU Lesser General Public License ever published by the Free Software Foundation.
-
If the Library as you received it specifies that a proxy can decide whether future versions of the GNU Lesser General Public License shall apply, that proxy's public statement of acceptance of any version is permanent authorization for you to choose that version for the Library.
\ No newline at end of file
diff --git a/Tukui/Libs/LibDeflate/LibDeflate.lua b/Tukui/Libs/LibDeflate/LibDeflate.lua
index cc00b096..02b36ab2 100644
--- a/Tukui/Libs/LibDeflate/LibDeflate.lua
+++ b/Tukui/Libs/LibDeflate/LibDeflate.lua
@@ -5,7 +5,7 @@ DEFLATE/zlib format.
@file LibDeflate.lua
@author Haoqian He (Github: SafeteeWoW; World of Warcraft: Safetyy-Illidan(US))
-@copyright LibDeflate <2018-2020> Haoqian He
+@copyright LibDeflate <2018-2021> Haoqian He
@license zlib License
This library is implemented according to the following specifications.
@@ -18,19 +18,15 @@ https://tools.ietf.org/html/rfc1950
This library requires Lua 5.1/5.2/5.3/5.4 interpreter or LuaJIT v2.0+.
This library does not have any dependencies.
-Note at the time of this release, Lua 5.4 final is not released yet.
-For Lua 5.4, This library is tested with its rc6 version.
This file "LibDeflate.lua" is the only source file of
the library.
Submit suggestions or report bugs to
https://github.com/safeteeWow/LibDeflate/issues
-]]
-
---[[
+]] --[[
zlib License
-(C) 2018-2020 Haoqian He
+(C) 2018-2021 Haoqian He
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
@@ -48,12 +44,17 @@ freely, subject to the following restrictions:
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
+License History:
+1. GNU General Public License Version 3 in v1.0.0 and earlier versions.
+2. GNU Lesser General Public License Version 3 in v1.0.1
+3. the zlib License since v1.0.2
Credits and Disclaimer:
-The following projects are used to the help to test the correctness
-of this program. The code of this program (LibDeflate.lua) does not
-use their code directly, but uses their ideas and algorithms. Their original
-licenses shall be comply when used.
+This library rewrites the code from the algorithm
+and the ideas of the following projects,
+and uses their code to help to test the correctness of this library,
+but their code is not included directly in the library itself.
+Their original licenses shall be comply when used.
1. zlib, by Jean-loup Gailly (compression) and Mark Adler (decompression).
http://www.zlib.net/
@@ -71,64 +72,59 @@ licenses shall be comply when used.
https://github.com/WeakAuras/WeakAuras2
Licensed under GPLv2.
For the 6bit encoding and decoding.
-]]
-
---[[
+]] --[[
Curseforge auto-packaging replacements:
- Project Date: 2020-06-26T15:11:26Z
- Project Hash: c19f978f053ebd22950eb6f1df4445677a4b0160
- Project Version: 1.0.2-release
---]]
-
-local LibDeflate
+ Project Date: @project-date-iso@
+ Project Hash: @project-hash@
+ Project Version: @project-version@
+--]] local LibDeflate
do
- -- Semantic version. all lowercase.
- -- Suffix can be alpha1, alpha2, beta1, beta2, rc1, rc2, etc.
- -- NOTE: Two version numbers needs to modify.
- -- 1. On the top of LibDeflate.lua
- -- 2. _VERSION
- -- 3. _MINOR
-
- -- version to store the official version of LibDeflate
- local _VERSION = "1.0.2-release"
-
- -- When MAJOR is changed, I should name it as LibDeflate2
- local _MAJOR = "LibDeflate"
-
- -- Update this whenever a new version, for LibStub version registration.
- -- 0 : v0.x
- -- 1 : v1.0.0
- -- 2 : v1.0.1
- -- 3 : v1.0.2
- local _MINOR = 3
-
- local _COPYRIGHT =
- "LibDeflate ".._VERSION
- .." Copyright (C) 2018-2020 Haoqian He."
- .." Licensed under the zlib License"
-
- -- Register in the World of Warcraft library "LibStub" if detected.
- if LibStub then
- local lib, minor = LibStub:GetLibrary(_MAJOR, true)
- if lib and minor and minor >= _MINOR then -- No need to update.
- return lib
- else -- Update or first time register
- LibDeflate = LibStub:NewLibrary(_MAJOR, _MINOR)
- -- NOTE: It is important that new version has implemented
- -- all exported APIs and tables in the old version,
- -- so the old library is fully garbage collected,
- -- and we 100% ensure the backward compatibility.
- end
- else -- "LibStub" is not detected.
- LibDeflate = {}
- end
-
- LibDeflate._VERSION = _VERSION
- LibDeflate._MAJOR = _MAJOR
- LibDeflate._MINOR = _MINOR
- LibDeflate._COPYRIGHT = _COPYRIGHT
+ -- Semantic version. all lowercase.
+ -- Suffix can be alpha1, alpha2, beta1, beta2, rc1, rc2, etc.
+ -- NOTE: Two version numbers needs to modify.
+ -- 1. On the top of LibDeflate.lua
+ -- 2. _VERSION
+ -- 3. _MINOR
+
+ -- version to store the official version of LibDeflate
+ local _VERSION = "1.0.2-release"
+
+ -- When MAJOR is changed, I should name it as LibDeflate2
+ local _MAJOR = "LibDeflate"
+
+ -- Update this whenever a new version, for LibStub version registration.
+ -- 0 : v0.x
+ -- 1 : v1.0.0
+ -- 2 : v1.0.1
+ -- 3 : v1.0.2
+ local _MINOR = 3
+
+ local _COPYRIGHT = "LibDeflate " .. _VERSION ..
+ " Copyright (C) 2018-2021 Haoqian He." ..
+ " Licensed under the zlib License"
+
+ -- Register in the World of Warcraft library "LibStub" if detected.
+ if LibStub then
+ local lib, minor = LibStub:GetLibrary(_MAJOR, true)
+ if lib and minor and minor >= _MINOR then -- No need to update.
+ return lib
+ else -- Update or first time register
+ LibDeflate = LibStub:NewLibrary(_MAJOR, _MINOR)
+ -- NOTE: It is important that new version has implemented
+ -- all exported APIs and tables in the old version,
+ -- so the old library is fully garbage collected,
+ -- and we 100% ensure the backward compatibility.
+ end
+ else -- "LibStub" is not detected.
+ LibDeflate = {}
+ end
+
+ LibDeflate._VERSION = _VERSION
+ LibDeflate._MAJOR = _MAJOR
+ LibDeflate._MINOR = _MINOR
+ LibDeflate._COPYRIGHT = _COPYRIGHT
end
-- localize Lua api for faster access.
@@ -189,35 +185,93 @@ local _dist256_to_deflate_extra_bitlen = {}
-- Convert a literal/LZ77_length deflate code to LZ77 base length
-- The key of the table is (code - 256), 257<=code<=285
-local _literal_deflate_code_to_base_len = {
- 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
- 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258,
-}
+local _literal_deflate_code_to_base_len =
+ {
+ 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, 67,
+ 83, 99, 115, 131, 163, 195, 227, 258
+ }
-- Convert a literal/LZ77_length deflate code to base LZ77 length extra bits
-- The key of the table is (code - 256), 257<=code<=285
-local _literal_deflate_code_to_extra_bitlen = {
- 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2,
- 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0,
-}
+local _literal_deflate_code_to_extra_bitlen =
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5,
+ 5, 5, 5, 0
+ }
-- Convert a distance deflate code to base LZ77 distance. (0<=code<=29)
local _dist_deflate_code_to_base_dist = {
- [0] = 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
- 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
- 8193, 12289, 16385, 24577,
+ [0] = 1,
+ 2,
+ 3,
+ 4,
+ 5,
+ 7,
+ 9,
+ 13,
+ 17,
+ 25,
+ 33,
+ 49,
+ 65,
+ 97,
+ 129,
+ 193,
+ 257,
+ 385,
+ 513,
+ 769,
+ 1025,
+ 1537,
+ 2049,
+ 3073,
+ 4097,
+ 6145,
+ 8193,
+ 12289,
+ 16385,
+ 24577
}
-- Convert a distance deflate code to LZ77 bits length. (0<=code<=29)
-local _dist_deflate_code_to_extra_bitlen = {
- [0] = 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6,
- 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13,
-}
+local _dist_deflate_code_to_extra_bitlen =
+ {
+ [0] = 0,
+ 0,
+ 0,
+ 0,
+ 1,
+ 1,
+ 2,
+ 2,
+ 3,
+ 3,
+ 4,
+ 4,
+ 5,
+ 5,
+ 6,
+ 6,
+ 7,
+ 7,
+ 8,
+ 8,
+ 9,
+ 9,
+ 10,
+ 10,
+ 11,
+ 11,
+ 12,
+ 12,
+ 13,
+ 13
+ }
-- The code order of the first huffman header in the dynamic deflate block.
-- See the page 12 of RFC1951
-local _rle_codes_huffman_bitlen_order = {16, 17, 18,
- 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15,
+local _rle_codes_huffman_bitlen_order = {
+ 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15
}
-- The following tables are used by fixed deflate block.
@@ -256,88 +310,86 @@ local _fix_block_dist_huffman_bitlen
-- in fixed deflate block.
local _fix_block_dist_huffman_bitlen_count
-for i = 0, 255 do
- _byte_to_char[i] = string_char(i)
-end
+for i = 0, 255 do _byte_to_char[i] = string_char(i) end
do
- local pow = 1
- for i = 0, 32 do
- _pow2[i] = pow
- pow = pow * 2
- end
+ local pow = 1
+ for i = 0, 32 do
+ _pow2[i] = pow
+ pow = pow * 2
+ end
end
for i = 1, 9 do
- _reverse_bits_tbl[i] = {}
- for j=0, _pow2[i+1]-1 do
- local reverse = 0
- local value = j
- for _ = 1, i do
- -- The following line is equivalent to "res | (code %2)" in C.
- reverse = reverse - reverse%2
- + (((reverse%2==1) or (value % 2) == 1) and 1 or 0)
- value = (value-value%2)/2
- reverse = reverse * 2
- end
- _reverse_bits_tbl[i][j] = (reverse-reverse%2)/2
- end
+ _reverse_bits_tbl[i] = {}
+ for j = 0, _pow2[i + 1] - 1 do
+ local reverse = 0
+ local value = j
+ for _ = 1, i do
+ -- The following line is equivalent to "res | (code %2)" in C.
+ reverse = reverse - reverse % 2 +
+ (((reverse % 2 == 1) or (value % 2) == 1) and 1 or 0)
+ value = (value - value % 2) / 2
+ reverse = reverse * 2
+ end
+ _reverse_bits_tbl[i][j] = (reverse - reverse % 2) / 2
+ end
end
-- The source code is written according to the pattern in the numbers
-- in RFC1951 Page10.
do
- local a = 18
- local b = 16
- local c = 265
- local bitlen = 1
- for len = 3, 258 do
- if len <= 10 then
- _length_to_deflate_code[len] = len + 254
- _length_to_deflate_extra_bitlen[len] = 0
- elseif len == 258 then
- _length_to_deflate_code[len] = 285
- _length_to_deflate_extra_bitlen[len] = 0
- else
- if len > a then
- a = a + b
- b = b * 2
- c = c + 4
- bitlen = bitlen + 1
- end
- local t = len-a-1+b/2
- _length_to_deflate_code[len] = (t-(t%(b/8)))/(b/8) + c
- _length_to_deflate_extra_bitlen[len] = bitlen
- _length_to_deflate_extra_bits[len] = t % (b/8)
- end
- end
+ local a = 18
+ local b = 16
+ local c = 265
+ local bitlen = 1
+ for len = 3, 258 do
+ if len <= 10 then
+ _length_to_deflate_code[len] = len + 254
+ _length_to_deflate_extra_bitlen[len] = 0
+ elseif len == 258 then
+ _length_to_deflate_code[len] = 285
+ _length_to_deflate_extra_bitlen[len] = 0
+ else
+ if len > a then
+ a = a + b
+ b = b * 2
+ c = c + 4
+ bitlen = bitlen + 1
+ end
+ local t = len - a - 1 + b / 2
+ _length_to_deflate_code[len] = (t - (t % (b / 8))) / (b / 8) + c
+ _length_to_deflate_extra_bitlen[len] = bitlen
+ _length_to_deflate_extra_bits[len] = t % (b / 8)
+ end
+ end
end
-- The source code is written according to the pattern in the numbers
-- in RFC1951 Page11.
do
- _dist256_to_deflate_code[1] = 0
- _dist256_to_deflate_code[2] = 1
- _dist256_to_deflate_extra_bitlen[1] = 0
- _dist256_to_deflate_extra_bitlen[2] = 0
-
- local a = 3
- local b = 4
- local code = 2
- local bitlen = 0
- for dist = 3, 256 do
- if dist > b then
- a = a * 2
- b = b * 2
- code = code + 2
- bitlen = bitlen + 1
- end
- _dist256_to_deflate_code[dist] = (dist <= a) and code or (code+1)
- _dist256_to_deflate_extra_bitlen[dist] = (bitlen < 0) and 0 or bitlen
- if b >= 8 then
- _dist256_to_deflate_extra_bits[dist] = (dist-b/2-1) % (b/4)
- end
- end
+ _dist256_to_deflate_code[1] = 0
+ _dist256_to_deflate_code[2] = 1
+ _dist256_to_deflate_extra_bitlen[1] = 0
+ _dist256_to_deflate_extra_bitlen[2] = 0
+
+ local a = 3
+ local b = 4
+ local code = 2
+ local bitlen = 0
+ for dist = 3, 256 do
+ if dist > b then
+ a = a * 2
+ b = b * 2
+ code = code + 2
+ bitlen = bitlen + 1
+ end
+ _dist256_to_deflate_code[dist] = (dist <= a) and code or (code + 1)
+ _dist256_to_deflate_extra_bitlen[dist] = (bitlen < 0) and 0 or bitlen
+ if b >= 8 then
+ _dist256_to_deflate_extra_bits[dist] = (dist - b / 2 - 1) % (b / 4)
+ end
+ end
end
--- Calculate the Adler-32 checksum of the string.
@@ -347,49 +399,53 @@ end
-- @return [integer] The Adler-32 checksum, which is greater or equal to 0,
-- and less than 2^32 (4294967296).
function LibDeflate:Adler32(str)
- -- This function is loop unrolled by better performance.
- --
- -- Here is the minimum code:
- --
- -- local a = 1
- -- local b = 0
- -- for i=1, #str do
- -- local s = string.byte(str, i, i)
- -- a = (a+s)%65521
- -- b = (b+a)%65521
- -- end
- -- return b*65536+a
- if type(str) ~= "string" then
- error(("Usage: LibDeflate:Adler32(str):"
- .." 'str' - string expected got '%s'."):format(type(str)), 2)
- end
- local strlen = #str
-
- local i = 1
- local a = 1
- local b = 0
- while i <= strlen - 15 do
- local x1, x2, x3, x4, x5, x6, x7, x8,
- x9, x10, x11, x12, x13, x14, x15, x16 = string_byte(str, i, i+15)
- b = (b+16*a+16*x1+15*x2+14*x3+13*x4+12*x5+11*x6+10*x7+9*x8+8*x9
- +7*x10+6*x11+5*x12+4*x13+3*x14+2*x15+x16)%65521
- a = (a+x1+x2+x3+x4+x5+x6+x7+x8+x9+x10+x11+x12+x13+x14+x15+x16)%65521
- i = i + 16
- end
- while (i <= strlen) do
- local x = string_byte(str, i, i)
- a = (a + x) % 65521
- b = (b + a) % 65521
- i = i + 1
- end
- return (b*65536+a) % 4294967296
+ -- This function is loop unrolled by better performance.
+ --
+ -- Here is the minimum code:
+ --
+ -- local a = 1
+ -- local b = 0
+ -- for i=1, #str do
+ -- local s = string.byte(str, i, i)
+ -- a = (a+s)%65521
+ -- b = (b+a)%65521
+ -- end
+ -- return b*65536+a
+ if type(str) ~= "string" then
+ error(("Usage: LibDeflate:Adler32(str):" ..
+ " 'str' - string expected got '%s'."):format(type(str)), 2)
+ end
+ local strlen = #str
+
+ local i = 1
+ local a = 1
+ local b = 0
+ while i <= strlen - 15 do
+ local x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15, x16 =
+ string_byte(str, i, i + 15)
+ b =
+ (b + 16 * a + 16 * x1 + 15 * x2 + 14 * x3 + 13 * x4 + 12 * x5 + 11 * x6 +
+ 10 * x7 + 9 * x8 + 8 * x9 + 7 * x10 + 6 * x11 + 5 * x12 + 4 * x13 + 3 *
+ x14 + 2 * x15 + x16) % 65521
+ a =
+ (a + x1 + x2 + x3 + x4 + x5 + x6 + x7 + x8 + x9 + x10 + x11 + x12 + x13 +
+ x14 + x15 + x16) % 65521
+ i = i + 16
+ end
+ while (i <= strlen) do
+ local x = string_byte(str, i, i)
+ a = (a + x) % 65521
+ b = (b + a) % 65521
+ i = i + 1
+ end
+ return (b * 65536 + a) % 4294967296
end
-- Compare adler32 checksum.
-- adler32 should be compared with a mod to avoid sign problem
-- 4072834167 (unsigned) is the same adler32 as -222133129
local function IsEqualAdler32(actual, expected)
- return (actual % 4294967296) == (expected % 4294967296)
+ return (actual % 4294967296) == (expected % 4294967296)
end
--- Create a preset dictionary.
@@ -435,95 +491,108 @@ end
-- @raise error if 'strlen' does not match the length of 'str',
-- or if 'adler32' does not match the Adler-32 checksum of 'str'.
function LibDeflate:CreateDictionary(str, strlen, adler32)
- if type(str) ~= "string" then
- error(("Usage: LibDeflate:CreateDictionary(str, strlen, adler32):"
- .." 'str' - string expected got '%s'."):format(type(str)), 2)
- end
- if type(strlen) ~= "number" then
- error(("Usage: LibDeflate:CreateDictionary(str, strlen, adler32):"
- .." 'strlen' - number expected got '%s'."):format(
- type(strlen)), 2)
- end
- if type(adler32) ~= "number" then
- error(("Usage: LibDeflate:CreateDictionary(str, strlen, adler32):"
- .." 'adler32' - number expected got '%s'."):format(
- type(adler32)), 2)
- end
- if strlen ~= #str then
- error(("Usage: LibDeflate:CreateDictionary(str, strlen, adler32):"
- .." 'strlen' does not match the actual length of 'str'."
- .." 'strlen': %u, '#str': %u ."
- .." Please check if 'str' is modified unintentionally.")
- :format(strlen, #str))
- end
- if strlen == 0 then
- error(("Usage: LibDeflate:CreateDictionary(str, strlen, adler32):"
- .." 'str' - Empty string is not allowed."), 2)
- end
- if strlen > 32768 then
- error(("Usage: LibDeflate:CreateDictionary(str, strlen, adler32):"
- .." 'str' - string longer than 32768 bytes is not allowed."
- .." Got %d bytes."):format(strlen), 2)
- end
- local actual_adler32 = self:Adler32(str)
- if not IsEqualAdler32(adler32, actual_adler32) then
- error(("Usage: LibDeflate:CreateDictionary(str, strlen, adler32):"
- .." 'adler32' does not match the actual adler32 of 'str'."
- .." 'adler32': %u, 'Adler32(str)': %u ."
- .." Please check if 'str' is modified unintentionally.")
- :format(adler32, actual_adler32))
- end
-
- local dictionary = {}
- dictionary.adler32 = adler32
- dictionary.hash_tables = {}
- dictionary.string_table = {}
- dictionary.strlen = strlen
- local string_table = dictionary.string_table
- local hash_tables = dictionary.hash_tables
- string_table[1] = string_byte(str, 1, 1)
- string_table[2] = string_byte(str, 2, 2)
- if strlen >= 3 then
- local i = 1
- local hash = string_table[1]*256+string_table[2]
- while i <= strlen - 2 - 3 do
- local x1, x2, x3, x4 = string_byte(str, i+2, i+5)
- string_table[i+2] = x1
- string_table[i+3] = x2
- string_table[i+4] = x3
- string_table[i+5] = x4
- hash = (hash*256+x1)%16777216
- local t = hash_tables[hash]
- if not t then t = {}; hash_tables[hash] = t end
- t[#t+1] = i-strlen
- i = i + 1
- hash = (hash*256+x2)%16777216
- t = hash_tables[hash]
- if not t then t = {}; hash_tables[hash] = t end
- t[#t+1] = i-strlen
- i = i + 1
- hash = (hash*256+x3)%16777216
- t = hash_tables[hash]
- if not t then t = {}; hash_tables[hash] = t end
- t[#t+1] = i-strlen
- i = i + 1
- hash = (hash*256+x4)%16777216
- t = hash_tables[hash]
- if not t then t = {}; hash_tables[hash] = t end
- t[#t+1] = i-strlen
- i = i + 1
- end
- while i <= strlen - 2 do
- local x = string_byte(str, i+2)
- string_table[i+2] = x
- hash = (hash*256+x)%16777216
- local t = hash_tables[hash]
- if not t then t = {}; hash_tables[hash] = t end
- t[#t+1] = i-strlen
- i = i + 1
- end
- end
- return dictionary
+ if type(str) ~= "string" then
+ error(("Usage: LibDeflate:CreateDictionary(str, strlen, adler32):" ..
+ " 'str' - string expected got '%s'."):format(type(str)), 2)
+ end
+ if type(strlen) ~= "number" then
+ error(("Usage: LibDeflate:CreateDictionary(str, strlen, adler32):" ..
+ " 'strlen' - number expected got '%s'."):format(type(strlen)), 2)
+ end
+ if type(adler32) ~= "number" then
+ error(("Usage: LibDeflate:CreateDictionary(str, strlen, adler32):" ..
+ " 'adler32' - number expected got '%s'."):format(type(adler32)), 2)
+ end
+ if strlen ~= #str then
+ error(("Usage: LibDeflate:CreateDictionary(str, strlen, adler32):" ..
+ " 'strlen' does not match the actual length of 'str'." ..
+ " 'strlen': %u, '#str': %u ." ..
+ " Please check if 'str' is modified unintentionally."):format(
+ strlen, #str))
+ end
+ if strlen == 0 then
+ error(("Usage: LibDeflate:CreateDictionary(str, strlen, adler32):" ..
+ " 'str' - Empty string is not allowed."), 2)
+ end
+ if strlen > 32768 then
+ error(("Usage: LibDeflate:CreateDictionary(str, strlen, adler32):" ..
+ " 'str' - string longer than 32768 bytes is not allowed." ..
+ " Got %d bytes."):format(strlen), 2)
+ end
+ local actual_adler32 = self:Adler32(str)
+ if not IsEqualAdler32(adler32, actual_adler32) then
+ error(("Usage: LibDeflate:CreateDictionary(str, strlen, adler32):" ..
+ " 'adler32' does not match the actual adler32 of 'str'." ..
+ " 'adler32': %u, 'Adler32(str)': %u ." ..
+ " Please check if 'str' is modified unintentionally."):format(
+ adler32, actual_adler32))
+ end
+
+ local dictionary = {}
+ dictionary.adler32 = adler32
+ dictionary.hash_tables = {}
+ dictionary.string_table = {}
+ dictionary.strlen = strlen
+ local string_table = dictionary.string_table
+ local hash_tables = dictionary.hash_tables
+ string_table[1] = string_byte(str, 1, 1)
+ string_table[2] = string_byte(str, 2, 2)
+ if strlen >= 3 then
+ local i = 1
+ local hash = string_table[1] * 256 + string_table[2]
+ while i <= strlen - 2 - 3 do
+ local x1, x2, x3, x4 = string_byte(str, i + 2, i + 5)
+ string_table[i + 2] = x1
+ string_table[i + 3] = x2
+ string_table[i + 4] = x3
+ string_table[i + 5] = x4
+ hash = (hash * 256 + x1) % 16777216
+ local t = hash_tables[hash]
+ if not t then
+ t = {};
+ hash_tables[hash] = t
+ end
+ t[#t + 1] = i - strlen
+ i = i + 1
+ hash = (hash * 256 + x2) % 16777216
+ t = hash_tables[hash]
+ if not t then
+ t = {};
+ hash_tables[hash] = t
+ end
+ t[#t + 1] = i - strlen
+ i = i + 1
+ hash = (hash * 256 + x3) % 16777216
+ t = hash_tables[hash]
+ if not t then
+ t = {};
+ hash_tables[hash] = t
+ end
+ t[#t + 1] = i - strlen
+ i = i + 1
+ hash = (hash * 256 + x4) % 16777216
+ t = hash_tables[hash]
+ if not t then
+ t = {};
+ hash_tables[hash] = t
+ end
+ t[#t + 1] = i - strlen
+ i = i + 1
+ end
+ while i <= strlen - 2 do
+ local x = string_byte(str, i + 2)
+ string_table[i + 2] = x
+ hash = (hash * 256 + x) % 16777216
+ local t = hash_tables[hash]
+ if not t then
+ t = {};
+ hash_tables[hash] = t
+ end
+ t[#t + 1] = i - strlen
+ i = i + 1
+ end
+ end
+ return dictionary
end
-- Check if the dictionary is valid.
@@ -531,22 +600,18 @@ end
-- @return true if valid, false if not valid.
-- @return if not valid, the error message.
local function IsValidDictionary(dictionary)
- if type(dictionary) ~= "table" then
- return false, ("'dictionary' - table expected got '%s'.")
- :format(type(dictionary))
- end
- if type(dictionary.adler32) ~= "number"
- or type(dictionary.string_table) ~= "table"
- or type(dictionary.strlen) ~= "number"
- or dictionary.strlen <= 0
- or dictionary.strlen > 32768
- or dictionary.strlen ~= #dictionary.string_table
- or type(dictionary.hash_tables) ~= "table"
- then
- return false, ("'dictionary' - corrupted dictionary.")
- :format(type(dictionary))
- end
- return true, ""
+ if type(dictionary) ~= "table" then
+ return false,
+ ("'dictionary' - table expected got '%s'."):format(type(dictionary))
+ end
+ if type(dictionary.adler32) ~= "number" or type(dictionary.string_table) ~=
+ "table" or type(dictionary.strlen) ~= "number" or dictionary.strlen <= 0 or
+ dictionary.strlen > 32768 or dictionary.strlen ~= #dictionary.string_table or
+ type(dictionary.hash_tables) ~= "table" then
+ return false,
+ ("'dictionary' - corrupted dictionary."):format(type(dictionary))
+ end
+ return true, ""
end
--[[
@@ -590,17 +655,17 @@ end
Number. The maximum number of hash chains we look.
--]]
local _compression_level_configs = {
- [0] = {false, nil, 0, 0, 0}, -- level 0, no compression
- [1] = {false, nil, 4, 8, 4}, -- level 1, similar to zlib level 1
- [2] = {false, nil, 5, 18, 8}, -- level 2, similar to zlib level 2
- [3] = {false, nil, 6, 32, 32}, -- level 3, similar to zlib level 3
- [4] = {true, 4, 4, 16, 16}, -- level 4, similar to zlib level 4
- [5] = {true, 8, 16, 32, 32}, -- level 5, similar to zlib level 5
- [6] = {true, 8, 16, 128, 128}, -- level 6, similar to zlib level 6
- [7] = {true, 8, 32, 128, 256}, -- (SLOW) level 7, similar to zlib level 7
- [8] = {true, 32, 128, 258, 1024} , --(SLOW) level 8,similar to zlib level 8
- [9] = {true, 32, 258, 258, 4096},
- -- (VERY SLOW) level 9, similar to zlib level 9
+ [0] = {false, nil, 0, 0, 0}, -- level 0, no compression
+ [1] = {false, nil, 4, 8, 4}, -- level 1, similar to zlib level 1
+ [2] = {false, nil, 5, 18, 8}, -- level 2, similar to zlib level 2
+ [3] = {false, nil, 6, 32, 32}, -- level 3, similar to zlib level 3
+ [4] = {true, 4, 4, 16, 16}, -- level 4, similar to zlib level 4
+ [5] = {true, 8, 16, 32, 32}, -- level 5, similar to zlib level 5
+ [6] = {true, 8, 16, 128, 128}, -- level 6, similar to zlib level 6
+ [7] = {true, 8, 32, 128, 256}, -- (SLOW) level 7, similar to zlib level 7
+ [8] = {true, 32, 128, 258, 1024}, -- (SLOW) level 8,similar to zlib level 8
+ [9] = {true, 32, 258, 258, 4096}
+ -- (VERY SLOW) level 9, similar to zlib level 9
}
-- Check if the compression/decompression arguments is valid
@@ -611,50 +676,43 @@ local _compression_level_configs = {
-- @param configs The compression configuration table
-- @return true if valid, false if not valid.
-- @return if not valid, the error message.
-local function IsValidArguments(str,
- check_dictionary, dictionary,
- check_configs, configs)
-
- if type(str) ~= "string" then
- return false,
- ("'str' - string expected got '%s'."):format(type(str))
- end
- if check_dictionary then
- local dict_valid, dict_err = IsValidDictionary(dictionary)
- if not dict_valid then
- return false, dict_err
- end
- end
- if check_configs then
- local type_configs = type(configs)
- if type_configs ~= "nil" and type_configs ~= "table" then
- return false,
- ("'configs' - nil or table expected got '%s'.")
- :format(type(configs))
- end
- if type_configs == "table" then
- for k, v in pairs(configs) do
- if k ~= "level" and k ~= "strategy" then
- return false,
- ("'configs' - unsupported table key in the configs: '%s'.")
- :format(k)
- elseif k == "level" and not _compression_level_configs[v] then
- return false,
- ("'configs' - unsupported 'level': %s."):format(tostring(v))
- elseif k == "strategy" and v ~= "fixed" and v ~= "huffman_only"
- and v ~= "dynamic" then
- -- random_block_type is for testing purpose
- return false, ("'configs' - unsupported 'strategy': '%s'.")
- :format(tostring(v))
- end
- end
- end
- end
- return true, ""
+local function IsValidArguments(str, check_dictionary, dictionary,
+ check_configs, configs)
+
+ if type(str) ~= "string" then
+ return false, ("'str' - string expected got '%s'."):format(type(str))
+ end
+ if check_dictionary then
+ local dict_valid, dict_err = IsValidDictionary(dictionary)
+ if not dict_valid then return false, dict_err end
+ end
+ if check_configs then
+ local type_configs = type(configs)
+ if type_configs ~= "nil" and type_configs ~= "table" then
+ return false, ("'configs' - nil or table expected got '%s'."):format(
+ type(configs))
+ end
+ if type_configs == "table" then
+ for k, v in pairs(configs) do
+ if k ~= "level" and k ~= "strategy" then
+ return false,
+ ("'configs' - unsupported table key in the configs: '%s'."):format(
+ k)
+ elseif k == "level" and not _compression_level_configs[v] then
+ return false,
+ ("'configs' - unsupported 'level': %s."):format(tostring(v))
+ elseif k == "strategy" and v ~= "fixed" and v ~= "huffman_only" and v ~=
+ "dynamic" then
+ -- random_block_type is for testing purpose
+ return false, ("'configs' - unsupported 'strategy': '%s'."):format(
+ tostring(v))
+ end
+ end
+ end
+ end
+ return true, ""
end
-
-
--[[ --------------------------------------------------------------------------
Compress code
--]] --------------------------------------------------------------------------
@@ -676,103 +734,101 @@ local _FLUSH_MODE_NO_FLUSH = 3
3. Flush(mode):
--]]
local function CreateWriter()
- local buffer_size = 0
- local cache = 0
- local cache_bitlen = 0
- local total_bitlen = 0
- local buffer = {}
- -- When buffer is big enough, flush into result_buffer to save memory.
- local result_buffer = {}
-
- -- Write bits with value "value" and bit length of "bitlen" into writer.
- -- @param value: The value being written
- -- @param bitlen: The bit length of "value"
- -- @return nil
- local function WriteBits(value, bitlen)
- cache = cache + value * _pow2[cache_bitlen]
- cache_bitlen = cache_bitlen + bitlen
- total_bitlen = total_bitlen + bitlen
- -- Only bulk to buffer every 4 bytes. This is quicker.
- if cache_bitlen >= 32 then
- buffer_size = buffer_size + 1
- buffer[buffer_size] =
- _byte_to_char[cache % 256]
- .._byte_to_char[((cache-cache%256)/256 % 256)]
- .._byte_to_char[((cache-cache%65536)/65536 % 256)]
- .._byte_to_char[((cache-cache%16777216)/16777216 % 256)]
- local rshift_mask = _pow2[32 - cache_bitlen + bitlen]
- cache = (value - value%rshift_mask)/rshift_mask
- cache_bitlen = cache_bitlen - 32
- end
- end
-
- -- Write the entire string into the writer.
- -- @param str The string being written
- -- @return nil
- local function WriteString(str)
- for _ = 1, cache_bitlen, 8 do
- buffer_size = buffer_size + 1
- buffer[buffer_size] = string_char(cache % 256)
- cache = (cache-cache%256)/256
- end
- cache_bitlen = 0
- buffer_size = buffer_size + 1
- buffer[buffer_size] = str
- total_bitlen = total_bitlen + #str*8
- end
-
- -- Flush current stuffs in the writer and return it.
- -- This operation will free most of the memory.
- -- @param mode See the descrtion of the constant and the source code.
- -- @return The total number of bits stored in the writer right now.
- -- for byte boundary mode, it includes the padding bits.
- -- for output mode, it does not include padding bits.
- -- @return Return the outputs if mode is output.
- local function FlushWriter(mode)
- if mode == _FLUSH_MODE_NO_FLUSH then
- return total_bitlen
- end
-
- if mode == _FLUSH_MODE_OUTPUT
- or mode == _FLUSH_MODE_BYTE_BOUNDARY then
- -- Full flush, also output cache.
- -- Need to pad some bits if cache_bitlen is not multiple of 8.
- local padding_bitlen = (8 - cache_bitlen % 8) % 8
-
- if cache_bitlen > 0 then
- -- padding with all 1 bits, mainly because "\000" is not
- -- good to be tranmitted. I do this so "\000" is a little bit
- -- less frequent.
- cache = cache - _pow2[cache_bitlen]
- + _pow2[cache_bitlen+padding_bitlen]
- for _ = 1, cache_bitlen, 8 do
- buffer_size = buffer_size + 1
- buffer[buffer_size] = _byte_to_char[cache % 256]
- cache = (cache-cache%256)/256
- end
-
- cache = 0
- cache_bitlen = 0
- end
- if mode == _FLUSH_MODE_BYTE_BOUNDARY then
- total_bitlen = total_bitlen + padding_bitlen
- return total_bitlen
- end
- end
-
- local flushed = table_concat(buffer)
- buffer = {}
- buffer_size = 0
- result_buffer[#result_buffer+1] = flushed
-
- if mode == _FLUSH_MODE_MEMORY_CLEANUP then
- return total_bitlen
- else
- return total_bitlen, table_concat(result_buffer)
- end
- end
-
- return WriteBits, WriteString, FlushWriter
+ local buffer_size = 0
+ local cache = 0
+ local cache_bitlen = 0
+ local total_bitlen = 0
+ local buffer = {}
+ -- When buffer is big enough, flush into result_buffer to save memory.
+ local result_buffer = {}
+
+ -- Write bits with value "value" and bit length of "bitlen" into writer.
+ -- @param value: The value being written
+ -- @param bitlen: The bit length of "value"
+ -- @return nil
+ local function WriteBits(value, bitlen)
+ cache = cache + value * _pow2[cache_bitlen]
+ cache_bitlen = cache_bitlen + bitlen
+ total_bitlen = total_bitlen + bitlen
+ -- Only bulk to buffer every 4 bytes. This is quicker.
+ if cache_bitlen >= 32 then
+ buffer_size = buffer_size + 1
+ buffer[buffer_size] = _byte_to_char[cache % 256] ..
+ _byte_to_char[((cache - cache % 256) / 256 % 256)] ..
+ _byte_to_char[((cache - cache % 65536) / 65536 %
+ 256)] ..
+ _byte_to_char[((cache - cache % 16777216) /
+ 16777216 % 256)]
+ local rshift_mask = _pow2[32 - cache_bitlen + bitlen]
+ cache = (value - value % rshift_mask) / rshift_mask
+ cache_bitlen = cache_bitlen - 32
+ end
+ end
+
+ -- Write the entire string into the writer.
+ -- @param str The string being written
+ -- @return nil
+ local function WriteString(str)
+ for _ = 1, cache_bitlen, 8 do
+ buffer_size = buffer_size + 1
+ buffer[buffer_size] = string_char(cache % 256)
+ cache = (cache - cache % 256) / 256
+ end
+ cache_bitlen = 0
+ buffer_size = buffer_size + 1
+ buffer[buffer_size] = str
+ total_bitlen = total_bitlen + #str * 8
+ end
+
+ -- Flush current stuffs in the writer and return it.
+ -- This operation will free most of the memory.
+ -- @param mode See the descrtion of the constant and the source code.
+ -- @return The total number of bits stored in the writer right now.
+ -- for byte boundary mode, it includes the padding bits.
+ -- for output mode, it does not include padding bits.
+ -- @return Return the outputs if mode is output.
+ local function FlushWriter(mode)
+ if mode == _FLUSH_MODE_NO_FLUSH then return total_bitlen end
+
+ if mode == _FLUSH_MODE_OUTPUT or mode == _FLUSH_MODE_BYTE_BOUNDARY then
+ -- Full flush, also output cache.
+ -- Need to pad some bits if cache_bitlen is not multiple of 8.
+ local padding_bitlen = (8 - cache_bitlen % 8) % 8
+
+ if cache_bitlen > 0 then
+ -- padding with all 1 bits, mainly because "\000" is not
+ -- good to be tranmitted. I do this so "\000" is a little bit
+ -- less frequent.
+ cache = cache - _pow2[cache_bitlen] +
+ _pow2[cache_bitlen + padding_bitlen]
+ for _ = 1, cache_bitlen, 8 do
+ buffer_size = buffer_size + 1
+ buffer[buffer_size] = _byte_to_char[cache % 256]
+ cache = (cache - cache % 256) / 256
+ end
+
+ cache = 0
+ cache_bitlen = 0
+ end
+ if mode == _FLUSH_MODE_BYTE_BOUNDARY then
+ total_bitlen = total_bitlen + padding_bitlen
+ return total_bitlen
+ end
+ end
+
+ local flushed = table_concat(buffer)
+ buffer = {}
+ buffer_size = 0
+ result_buffer[#result_buffer + 1] = flushed
+
+ if mode == _FLUSH_MODE_MEMORY_CLEANUP then
+ return total_bitlen
+ else
+ return total_bitlen, table_concat(result_buffer)
+ end
+ end
+
+ return WriteBits, WriteString, FlushWriter
end
-- Push an element into a max heap
@@ -784,19 +840,19 @@ end
-- heap[heap_size+1], heap[heap_size+2], etc..
-- @return nil
local function MinHeapPush(heap, e, heap_size)
- heap_size = heap_size + 1
- heap[heap_size] = e
- local value = e[1]
- local pos = heap_size
- local parent_pos = (pos-pos%2)/2
-
- while (parent_pos >= 1 and heap[parent_pos][1] > value) do
- local t = heap[parent_pos]
- heap[parent_pos] = e
- heap[pos] = t
- pos = parent_pos
- parent_pos = (parent_pos-parent_pos%2)/2
- end
+ heap_size = heap_size + 1
+ heap[heap_size] = e
+ local value = e[1]
+ local pos = heap_size
+ local parent_pos = (pos - pos % 2) / 2
+
+ while (parent_pos >= 1 and heap[parent_pos][1] > value) do
+ local t = heap[parent_pos]
+ heap[parent_pos] = e
+ heap[pos] = t
+ pos = parent_pos
+ parent_pos = (parent_pos - parent_pos % 2) / 2
+ end
end
-- Pop an element from a max heap
@@ -805,45 +861,45 @@ end
-- @return the poped element
-- Note: This function does not change table size of "heap" to save CPU time.
local function MinHeapPop(heap, heap_size)
- local top = heap[1]
- local e = heap[heap_size]
- local value = e[1]
- heap[1] = e
- heap[heap_size] = top
- heap_size = heap_size - 1
-
- local pos = 1
- local left_child_pos = pos * 2
- local right_child_pos = left_child_pos + 1
-
- while (left_child_pos <= heap_size) do
- local left_child = heap[left_child_pos]
- if (right_child_pos <= heap_size
- and heap[right_child_pos][1] < left_child[1]) then
- local right_child = heap[right_child_pos]
- if right_child[1] < value then
- heap[right_child_pos] = e
- heap[pos] = right_child
- pos = right_child_pos
- left_child_pos = pos * 2
- right_child_pos = left_child_pos + 1
- else
- break
- end
- else
- if left_child[1] < value then
- heap[left_child_pos] = e
- heap[pos] = left_child
- pos = left_child_pos
- left_child_pos = pos * 2
- right_child_pos = left_child_pos + 1
- else
- break
- end
- end
- end
-
- return top
+ local top = heap[1]
+ local e = heap[heap_size]
+ local value = e[1]
+ heap[1] = e
+ heap[heap_size] = top
+ heap_size = heap_size - 1
+
+ local pos = 1
+ local left_child_pos = pos * 2
+ local right_child_pos = left_child_pos + 1
+
+ while (left_child_pos <= heap_size) do
+ local left_child = heap[left_child_pos]
+ if (right_child_pos <= heap_size and heap[right_child_pos][1] <
+ left_child[1]) then
+ local right_child = heap[right_child_pos]
+ if right_child[1] < value then
+ heap[right_child_pos] = e
+ heap[pos] = right_child
+ pos = right_child_pos
+ left_child_pos = pos * 2
+ right_child_pos = left_child_pos + 1
+ else
+ break
+ end
+ else
+ if left_child[1] < value then
+ heap[left_child_pos] = e
+ heap[pos] = left_child
+ pos = left_child_pos
+ left_child_pos = pos * 2
+ right_child_pos = left_child_pos + 1
+ else
+ break
+ end
+ end
+ end
+
+ return top
end
-- Deflate defines a special huffman tree, which is unique once the bit length
@@ -854,50 +910,48 @@ end
-- which is (number of symbols - 1)
-- @param max_bitlen The max huffman bit length among all symbols.
-- @return The huffman code of all symbols.
-local function GetHuffmanCodeFromBitlen(bitlen_counts, symbol_bitlens
- , max_symbol, max_bitlen)
- local huffman_code = 0
- local next_codes = {}
- local symbol_huffman_codes = {}
- for bitlen = 1, max_bitlen do
- huffman_code = (huffman_code+(bitlen_counts[bitlen-1] or 0))*2
- next_codes[bitlen] = huffman_code
- end
- for symbol = 0, max_symbol do
- local bitlen = symbol_bitlens[symbol]
- if bitlen then
- huffman_code = next_codes[bitlen]
- next_codes[bitlen] = huffman_code + 1
-
- -- Reverse the bits of huffman code,
- -- because most signifant bits of huffman code
- -- is stored first into the compressed data.
- -- @see RFC1951 Page5 Section 3.1.1
- if bitlen <= 9 then -- Have cached reverse for small bitlen.
- symbol_huffman_codes[symbol] =
- _reverse_bits_tbl[bitlen][huffman_code]
- else
- local reverse = 0
- for _ = 1, bitlen do
- reverse = reverse - reverse%2
- + (((reverse%2==1)
- or (huffman_code % 2) == 1) and 1 or 0)
- huffman_code = (huffman_code-huffman_code%2)/2
- reverse = reverse*2
- end
- symbol_huffman_codes[symbol] = (reverse-reverse%2)/2
- end
- end
- end
- return symbol_huffman_codes
+local function GetHuffmanCodeFromBitlen(bitlen_counts, symbol_bitlens,
+ max_symbol, max_bitlen)
+ local huffman_code = 0
+ local next_codes = {}
+ local symbol_huffman_codes = {}
+ for bitlen = 1, max_bitlen do
+ huffman_code = (huffman_code + (bitlen_counts[bitlen - 1] or 0)) * 2
+ next_codes[bitlen] = huffman_code
+ end
+ for symbol = 0, max_symbol do
+ local bitlen = symbol_bitlens[symbol]
+ if bitlen then
+ huffman_code = next_codes[bitlen]
+ next_codes[bitlen] = huffman_code + 1
+
+ -- Reverse the bits of huffman code,
+ -- because most signifant bits of huffman code
+ -- is stored first into the compressed data.
+ -- @see RFC1951 Page5 Section 3.1.1
+ if bitlen <= 9 then -- Have cached reverse for small bitlen.
+ symbol_huffman_codes[symbol] = _reverse_bits_tbl[bitlen][huffman_code]
+ else
+ local reverse = 0
+ for _ = 1, bitlen do
+ reverse = reverse - reverse % 2 +
+ (((reverse % 2 == 1) or (huffman_code % 2) == 1) and 1 or
+ 0)
+ huffman_code = (huffman_code - huffman_code % 2) / 2
+ reverse = reverse * 2
+ end
+ symbol_huffman_codes[symbol] = (reverse - reverse % 2) / 2
+ end
+ end
+ end
+ return symbol_huffman_codes
end
-- A helper function to sort heap elements
-- a[1], b[1] is the huffman frequency
-- a[2], b[2] is the symbol value.
local function SortByFirstThenSecond(a, b)
- return a[1] < b[1] or
- (a[1] == b[1] and a[2] < b[2])
+ return a[1] < b[1] or (a[1] == b[1] and a[2] < b[2])
end
-- Calculate the huffman bit length and huffman code.
@@ -912,128 +966,122 @@ end
-- @return a table whose key is the symbol, and the value is the huffman code.
-- @return a number indicating the maximum symbol whose bitlen is not 0.
local function GetHuffmanBitlenAndCode(symbol_counts, max_bitlen, max_symbol)
- local heap_size
- local max_non_zero_bitlen_symbol = -1
- local leafs = {}
- local heap = {}
- local symbol_bitlens = {}
- local symbol_codes = {}
- local bitlen_counts = {}
-
- --[[
+ local heap_size
+ local max_non_zero_bitlen_symbol = -1
+ local leafs = {}
+ local heap = {}
+ local symbol_bitlens = {}
+ local symbol_codes = {}
+ local bitlen_counts = {}
+
+ --[[
tree[1]: weight, temporarily used as parent and bitLengths
tree[2]: symbol
tree[3]: left child
tree[4]: right child
--]]
- local number_unique_symbols = 0
- for symbol, count in pairs(symbol_counts) do
- number_unique_symbols = number_unique_symbols + 1
- leafs[number_unique_symbols] = {count, symbol}
- end
-
- if (number_unique_symbols == 0) then
- -- no code.
- return {}, {}, -1
- elseif (number_unique_symbols == 1) then
- -- Only one code. In this case, its huffman code
- -- needs to be assigned as 0, and bit length is 1.
- -- This is the only case that the return result
- -- represents an imcomplete huffman tree.
- local symbol = leafs[1][2]
- symbol_bitlens[symbol] = 1
- symbol_codes[symbol] = 0
- return symbol_bitlens, symbol_codes, symbol
- else
- table_sort(leafs, SortByFirstThenSecond)
- heap_size = number_unique_symbols
- for i = 1, heap_size do
- heap[i] = leafs[i]
- end
-
- while (heap_size > 1) do
- -- Note: pop does not change table size of heap
- local leftChild = MinHeapPop(heap, heap_size)
- heap_size = heap_size - 1
- local rightChild = MinHeapPop(heap, heap_size)
- heap_size = heap_size - 1
- local newNode =
- {leftChild[1]+rightChild[1], -1, leftChild, rightChild}
- MinHeapPush(heap, newNode, heap_size)
- heap_size = heap_size + 1
- end
-
- -- Number of leafs whose bit length is greater than max_len.
- local number_bitlen_overflow = 0
-
- -- Calculate bit length of all nodes
- local fifo = {heap[1], 0, 0, 0} -- preallocate some spaces.
- local fifo_size = 1
- local index = 1
- heap[1][1] = 0
- while (index <= fifo_size) do -- Breath first search
- local e = fifo[index]
- local bitlen = e[1]
- local symbol = e[2]
- local left_child = e[3]
- local right_child = e[4]
- if left_child then
- fifo_size = fifo_size + 1
- fifo[fifo_size] = left_child
- left_child[1] = bitlen + 1
- end
- if right_child then
- fifo_size = fifo_size + 1
- fifo[fifo_size] = right_child
- right_child[1] = bitlen + 1
- end
- index = index + 1
-
- if (bitlen > max_bitlen) then
- number_bitlen_overflow = number_bitlen_overflow + 1
- bitlen = max_bitlen
- end
- if symbol >= 0 then
- symbol_bitlens[symbol] = bitlen
- max_non_zero_bitlen_symbol =
- (symbol > max_non_zero_bitlen_symbol)
- and symbol or max_non_zero_bitlen_symbol
- bitlen_counts[bitlen] = (bitlen_counts[bitlen] or 0) + 1
- end
- end
-
- -- Resolve bit length overflow
- -- @see ZLib/trees.c:gen_bitlen(s, desc), for reference
- if (number_bitlen_overflow > 0) then
- repeat
- local bitlen = max_bitlen - 1
- while ((bitlen_counts[bitlen] or 0) == 0) do
- bitlen = bitlen - 1
- end
- -- move one leaf down the tree
- bitlen_counts[bitlen] = bitlen_counts[bitlen] - 1
- -- move one overflow item as its brother
- bitlen_counts[bitlen+1] = (bitlen_counts[bitlen+1] or 0) + 2
- bitlen_counts[max_bitlen] = bitlen_counts[max_bitlen] - 1
- number_bitlen_overflow = number_bitlen_overflow - 2
- until (number_bitlen_overflow <= 0)
-
- index = 1
- for bitlen = max_bitlen, 1, -1 do
- local n = bitlen_counts[bitlen] or 0
- while (n > 0) do
- local symbol = leafs[index][2]
- symbol_bitlens[symbol] = bitlen
- n = n - 1
- index = index + 1
- end
- end
- end
-
- symbol_codes = GetHuffmanCodeFromBitlen(bitlen_counts, symbol_bitlens,
- max_symbol, max_bitlen)
- return symbol_bitlens, symbol_codes, max_non_zero_bitlen_symbol
- end
+ local number_unique_symbols = 0
+ for symbol, count in pairs(symbol_counts) do
+ number_unique_symbols = number_unique_symbols + 1
+ leafs[number_unique_symbols] = {count, symbol}
+ end
+
+ if (number_unique_symbols == 0) then
+ -- no code.
+ return {}, {}, -1
+ elseif (number_unique_symbols == 1) then
+ -- Only one code. In this case, its huffman code
+ -- needs to be assigned as 0, and bit length is 1.
+ -- This is the only case that the return result
+ -- represents an imcomplete huffman tree.
+ local symbol = leafs[1][2]
+ symbol_bitlens[symbol] = 1
+ symbol_codes[symbol] = 0
+ return symbol_bitlens, symbol_codes, symbol
+ else
+ table_sort(leafs, SortByFirstThenSecond)
+ heap_size = number_unique_symbols
+ for i = 1, heap_size do heap[i] = leafs[i] end
+
+ while (heap_size > 1) do
+ -- Note: pop does not change table size of heap
+ local leftChild = MinHeapPop(heap, heap_size)
+ heap_size = heap_size - 1
+ local rightChild = MinHeapPop(heap, heap_size)
+ heap_size = heap_size - 1
+ local newNode = {leftChild[1] + rightChild[1], -1, leftChild, rightChild}
+ MinHeapPush(heap, newNode, heap_size)
+ heap_size = heap_size + 1
+ end
+
+ -- Number of leafs whose bit length is greater than max_len.
+ local number_bitlen_overflow = 0
+
+ -- Calculate bit length of all nodes
+ local fifo = {heap[1], 0, 0, 0} -- preallocate some spaces.
+ local fifo_size = 1
+ local index = 1
+ heap[1][1] = 0
+ while (index <= fifo_size) do -- Breath first search
+ local e = fifo[index]
+ local bitlen = e[1]
+ local symbol = e[2]
+ local left_child = e[3]
+ local right_child = e[4]
+ if left_child then
+ fifo_size = fifo_size + 1
+ fifo[fifo_size] = left_child
+ left_child[1] = bitlen + 1
+ end
+ if right_child then
+ fifo_size = fifo_size + 1
+ fifo[fifo_size] = right_child
+ right_child[1] = bitlen + 1
+ end
+ index = index + 1
+
+ if (bitlen > max_bitlen) then
+ number_bitlen_overflow = number_bitlen_overflow + 1
+ bitlen = max_bitlen
+ end
+ if symbol >= 0 then
+ symbol_bitlens[symbol] = bitlen
+ max_non_zero_bitlen_symbol = (symbol > max_non_zero_bitlen_symbol) and
+ symbol or max_non_zero_bitlen_symbol
+ bitlen_counts[bitlen] = (bitlen_counts[bitlen] or 0) + 1
+ end
+ end
+
+ -- Resolve bit length overflow
+ -- @see ZLib/trees.c:gen_bitlen(s, desc), for reference
+ if (number_bitlen_overflow > 0) then
+ repeat
+ local bitlen = max_bitlen - 1
+ while ((bitlen_counts[bitlen] or 0) == 0) do bitlen = bitlen - 1 end
+ -- move one leaf down the tree
+ bitlen_counts[bitlen] = bitlen_counts[bitlen] - 1
+ -- move one overflow item as its brother
+ bitlen_counts[bitlen + 1] = (bitlen_counts[bitlen + 1] or 0) + 2
+ bitlen_counts[max_bitlen] = bitlen_counts[max_bitlen] - 1
+ number_bitlen_overflow = number_bitlen_overflow - 2
+ until (number_bitlen_overflow <= 0)
+
+ index = 1
+ for bitlen = max_bitlen, 1, -1 do
+ local n = bitlen_counts[bitlen] or 0
+ while (n > 0) do
+ local symbol = leafs[index][2]
+ symbol_bitlens[symbol] = bitlen
+ n = n - 1
+ index = index + 1
+ end
+ end
+ end
+
+ symbol_codes = GetHuffmanCodeFromBitlen(bitlen_counts, symbol_bitlens,
+ max_symbol, max_bitlen)
+ return symbol_bitlens, symbol_codes, max_non_zero_bitlen_symbol
+ end
end
-- Calculate the first huffman header in the dynamic huffman block
@@ -1048,82 +1096,81 @@ end
-- @return The extra bits. One entry for each rle code that needs extra bits.
-- (code == 16 or 17 or 18).
-- @return The count of appearance of each rle codes.
-local function RunLengthEncodeHuffmanBitlen(
- lcode_bitlens,
- max_non_zero_bitlen_lcode,
- dcode_bitlens,
- max_non_zero_bitlen_dcode)
- local rle_code_tblsize = 0
- local rle_codes = {}
- local rle_code_counts = {}
- local rle_extra_bits_tblsize = 0
- local rle_extra_bits = {}
- local prev = nil
- local count = 0
-
- -- If there is no distance code, assume one distance code of bit length 0.
- -- RFC1951: One distance code of zero bits means that
- -- there are no distance codes used at all (the data is all literals).
- max_non_zero_bitlen_dcode = (max_non_zero_bitlen_dcode < 0)
- and 0 or max_non_zero_bitlen_dcode
- local max_code = max_non_zero_bitlen_lcode+max_non_zero_bitlen_dcode+1
-
- for code = 0, max_code+1 do
- local len = (code <= max_non_zero_bitlen_lcode)
- and (lcode_bitlens[code] or 0)
- or ((code <= max_code)
- and (dcode_bitlens[code-max_non_zero_bitlen_lcode-1] or 0) or nil)
- if len == prev then
- count = count + 1
- if len ~= 0 and count == 6 then
- rle_code_tblsize = rle_code_tblsize + 1
- rle_codes[rle_code_tblsize] = 16
- rle_extra_bits_tblsize = rle_extra_bits_tblsize + 1
- rle_extra_bits[rle_extra_bits_tblsize] = 3
- rle_code_counts[16] = (rle_code_counts[16] or 0) + 1
- count = 0
- elseif len == 0 and count == 138 then
- rle_code_tblsize = rle_code_tblsize + 1
- rle_codes[rle_code_tblsize] = 18
- rle_extra_bits_tblsize = rle_extra_bits_tblsize + 1
- rle_extra_bits[rle_extra_bits_tblsize] = 127
- rle_code_counts[18] = (rle_code_counts[18] or 0) + 1
- count = 0
- end
- else
- if count == 1 then
- rle_code_tblsize = rle_code_tblsize + 1
- rle_codes[rle_code_tblsize] = prev
- rle_code_counts[prev] = (rle_code_counts[prev] or 0) + 1
- elseif count == 2 then
- rle_code_tblsize = rle_code_tblsize + 1
- rle_codes[rle_code_tblsize] = prev
- rle_code_tblsize = rle_code_tblsize + 1
- rle_codes[rle_code_tblsize] = prev
- rle_code_counts[prev] = (rle_code_counts[prev] or 0) + 2
- elseif count >= 3 then
- rle_code_tblsize = rle_code_tblsize + 1
- local rleCode = (prev ~= 0) and 16 or (count <= 10 and 17 or 18)
- rle_codes[rle_code_tblsize] = rleCode
- rle_code_counts[rleCode] = (rle_code_counts[rleCode] or 0) + 1
- rle_extra_bits_tblsize = rle_extra_bits_tblsize + 1
- rle_extra_bits[rle_extra_bits_tblsize] =
- (count <= 10) and (count - 3) or (count - 11)
- end
-
- prev = len
- if len and len ~= 0 then
- rle_code_tblsize = rle_code_tblsize + 1
- rle_codes[rle_code_tblsize] = len
- rle_code_counts[len] = (rle_code_counts[len] or 0) + 1
- count = 0
- else
- count = 1
- end
- end
- end
-
- return rle_codes, rle_extra_bits, rle_code_counts
+local function RunLengthEncodeHuffmanBitlen(lcode_bitlens,
+ max_non_zero_bitlen_lcode,
+ dcode_bitlens,
+ max_non_zero_bitlen_dcode)
+ local rle_code_tblsize = 0
+ local rle_codes = {}
+ local rle_code_counts = {}
+ local rle_extra_bits_tblsize = 0
+ local rle_extra_bits = {}
+ local prev = nil
+ local count = 0
+
+ -- If there is no distance code, assume one distance code of bit length 0.
+ -- RFC1951: One distance code of zero bits means that
+ -- there are no distance codes used at all (the data is all literals).
+ max_non_zero_bitlen_dcode = (max_non_zero_bitlen_dcode < 0) and 0 or
+ max_non_zero_bitlen_dcode
+ local max_code = max_non_zero_bitlen_lcode + max_non_zero_bitlen_dcode + 1
+
+ for code = 0, max_code + 1 do
+ local len = (code <= max_non_zero_bitlen_lcode) and
+ (lcode_bitlens[code] or 0) or ((code <= max_code) and
+ (dcode_bitlens[code - max_non_zero_bitlen_lcode - 1] or 0) or
+ nil)
+ if len == prev then
+ count = count + 1
+ if len ~= 0 and count == 6 then
+ rle_code_tblsize = rle_code_tblsize + 1
+ rle_codes[rle_code_tblsize] = 16
+ rle_extra_bits_tblsize = rle_extra_bits_tblsize + 1
+ rle_extra_bits[rle_extra_bits_tblsize] = 3
+ rle_code_counts[16] = (rle_code_counts[16] or 0) + 1
+ count = 0
+ elseif len == 0 and count == 138 then
+ rle_code_tblsize = rle_code_tblsize + 1
+ rle_codes[rle_code_tblsize] = 18
+ rle_extra_bits_tblsize = rle_extra_bits_tblsize + 1
+ rle_extra_bits[rle_extra_bits_tblsize] = 127
+ rle_code_counts[18] = (rle_code_counts[18] or 0) + 1
+ count = 0
+ end
+ else
+ if count == 1 then
+ rle_code_tblsize = rle_code_tblsize + 1
+ rle_codes[rle_code_tblsize] = prev
+ rle_code_counts[prev] = (rle_code_counts[prev] or 0) + 1
+ elseif count == 2 then
+ rle_code_tblsize = rle_code_tblsize + 1
+ rle_codes[rle_code_tblsize] = prev
+ rle_code_tblsize = rle_code_tblsize + 1
+ rle_codes[rle_code_tblsize] = prev
+ rle_code_counts[prev] = (rle_code_counts[prev] or 0) + 2
+ elseif count >= 3 then
+ rle_code_tblsize = rle_code_tblsize + 1
+ local rleCode = (prev ~= 0) and 16 or (count <= 10 and 17 or 18)
+ rle_codes[rle_code_tblsize] = rleCode
+ rle_code_counts[rleCode] = (rle_code_counts[rleCode] or 0) + 1
+ rle_extra_bits_tblsize = rle_extra_bits_tblsize + 1
+ rle_extra_bits[rle_extra_bits_tblsize] =
+ (count <= 10) and (count - 3) or (count - 11)
+ end
+
+ prev = len
+ if len and len ~= 0 then
+ rle_code_tblsize = rle_code_tblsize + 1
+ rle_codes[rle_code_tblsize] = len
+ rle_code_counts[len] = (rle_code_counts[len] or 0) + 1
+ count = 0
+ else
+ count = 1
+ end
+ end
+ end
+
+ return rle_codes, rle_extra_bits, rle_code_counts
end
-- Load the string into a table, in order to speed up LZ77.
@@ -1135,18 +1182,18 @@ end
-- @param offset str[index] will be loaded into t[index-offset]
-- @return t
local function LoadStringToTable(str, t, start, stop, offset)
- local i = start - offset
- while i <= stop - 15 - offset do
- t[i], t[i+1], t[i+2], t[i+3], t[i+4], t[i+5], t[i+6], t[i+7], t[i+8],
- t[i+9], t[i+10], t[i+11], t[i+12], t[i+13], t[i+14], t[i+15] =
- string_byte(str, i + offset, i + 15 + offset)
- i = i + 16
- end
- while (i <= stop - offset) do
- t[i] = string_byte(str, i + offset, i + offset)
- i = i + 1
- end
- return t
+ local i = start - offset
+ while i <= stop - 15 - offset do
+ t[i], t[i + 1], t[i + 2], t[i + 3], t[i + 4], t[i + 5], t[i + 6], t[i + 7], t[i +
+ 8], t[i + 9], t[i + 10], t[i + 11], t[i + 12], t[i + 13], t[i + 14], t[i +
+ 15] = string_byte(str, i + offset, i + 15 + offset)
+ i = i + 16
+ end
+ while (i <= stop - offset) do
+ t[i] = string_byte(str, i + offset, i + offset)
+ i = i + 1
+ end
+ return t
end
-- Do LZ77 process. This function uses the majority of the CPU time.
@@ -1192,255 +1239,248 @@ end
-- @return the extra bits of LZ77 distance deflate codes.
-- @return the count of each LZ77 distance deflate code.
local function GetBlockLZ77Result(level, string_table, hash_tables, block_start,
- block_end, offset, dictionary)
- local config = _compression_level_configs[level]
- local config_use_lazy
- , config_good_prev_length
- , config_max_lazy_match
- , config_nice_length
- , config_max_hash_chain =
- config[1], config[2], config[3], config[4], config[5]
-
- local config_max_insert_length = (not config_use_lazy)
- and config_max_lazy_match or 2147483646
- local config_good_hash_chain =
- (config_max_hash_chain-config_max_hash_chain%4/4)
-
- local hash
-
- local dict_hash_tables
- local dict_string_table
- local dict_string_len = 0
-
- if dictionary then
- dict_hash_tables = dictionary.hash_tables
- dict_string_table = dictionary.string_table
- dict_string_len = dictionary.strlen
- assert(block_start == 1)
- if block_end >= block_start and dict_string_len >= 2 then
- hash = dict_string_table[dict_string_len-1]*65536
- + dict_string_table[dict_string_len]*256 + string_table[1]
- local t = hash_tables[hash]
- if not t then t = {}; hash_tables[hash] = t end
- t[#t+1] = -1
- end
- if block_end >= block_start+1 and dict_string_len >= 1 then
- hash = dict_string_table[dict_string_len]*65536
- + string_table[1]*256 + string_table[2]
- local t = hash_tables[hash]
- if not t then t = {}; hash_tables[hash] = t end
- t[#t+1] = 0
- end
- end
-
- local dict_string_len_plus3 = dict_string_len + 3
-
- hash = (string_table[block_start-offset] or 0)*256
- + (string_table[block_start+1-offset] or 0)
-
- local lcodes = {}
- local lcode_tblsize = 0
- local lcodes_counts = {}
- local dcodes = {}
- local dcodes_tblsize = 0
- local dcodes_counts = {}
-
- local lextra_bits = {}
- local lextra_bits_tblsize = 0
- local dextra_bits = {}
- local dextra_bits_tblsize = 0
-
- local match_available = false
- local prev_len
- local prev_dist
- local cur_len = 0
- local cur_dist = 0
-
- local index = block_start
- local index_end = block_end + (config_use_lazy and 1 or 0)
-
- -- the zlib source code writes separate code for lazy evaluation and
- -- not lazy evaluation, which is easier to understand.
- -- I put them together, so it is a bit harder to understand.
- -- because I think this is easier for me to maintain it.
- while (index <= index_end) do
- local string_table_index = index - offset
- local offset_minus_three = offset - 3
- prev_len = cur_len
- prev_dist = cur_dist
- cur_len = 0
-
- hash = (hash*256+(string_table[string_table_index+2] or 0))%16777216
-
- local chain_index
- local cur_chain
- local hash_chain = hash_tables[hash]
- local chain_old_size
- if not hash_chain then
- chain_old_size = 0
- hash_chain = {}
- hash_tables[hash] = hash_chain
- if dict_hash_tables then
- cur_chain = dict_hash_tables[hash]
- chain_index = cur_chain and #cur_chain or 0
- else
- chain_index = 0
- end
- else
- chain_old_size = #hash_chain
- cur_chain = hash_chain
- chain_index = chain_old_size
- end
-
- if index <= block_end then
- hash_chain[chain_old_size+1] = index
- end
-
- if (chain_index > 0 and index + 2 <= block_end
- and (not config_use_lazy or prev_len < config_max_lazy_match)) then
-
- local depth =
- (config_use_lazy and prev_len >= config_good_prev_length)
- and config_good_hash_chain or config_max_hash_chain
-
- local max_len_minus_one = block_end - index
- max_len_minus_one = (max_len_minus_one >= 257) and 257 or max_len_minus_one
- max_len_minus_one = max_len_minus_one + string_table_index
- local string_table_index_plus_three = string_table_index + 3
-
- while chain_index >= 1 and depth > 0 do
- local prev = cur_chain[chain_index]
-
- if index - prev > 32768 then
- break
- end
- if prev < index then
- local sj = string_table_index_plus_three
-
- if prev >= -257 then
- local pj = prev - offset_minus_three
- while (sj <= max_len_minus_one
- and string_table[pj]
- == string_table[sj]) do
- sj = sj + 1
- pj = pj + 1
- end
- else
- local pj = dict_string_len_plus3 + prev
- while (sj <= max_len_minus_one
- and dict_string_table[pj]
- == string_table[sj]) do
- sj = sj + 1
- pj = pj + 1
- end
- end
- local j = sj - string_table_index
- if j > cur_len then
- cur_len = j
- cur_dist = index - prev
- end
- if cur_len >= config_nice_length then
- break
- end
- end
-
- chain_index = chain_index - 1
- depth = depth - 1
- if chain_index == 0 and prev > 0 and dict_hash_tables then
- cur_chain = dict_hash_tables[hash]
- chain_index = cur_chain and #cur_chain or 0
- end
- end
- end
-
- if not config_use_lazy then
- prev_len, prev_dist = cur_len, cur_dist
- end
- if ((not config_use_lazy or match_available)
- and (prev_len > 3 or (prev_len == 3 and prev_dist < 4096))
- and cur_len <= prev_len )then
- local code = _length_to_deflate_code[prev_len]
- local length_extra_bits_bitlen =
- _length_to_deflate_extra_bitlen[prev_len]
- local dist_code, dist_extra_bits_bitlen, dist_extra_bits
- if prev_dist <= 256 then -- have cached code for small distance.
- dist_code = _dist256_to_deflate_code[prev_dist]
- dist_extra_bits = _dist256_to_deflate_extra_bits[prev_dist]
- dist_extra_bits_bitlen =
- _dist256_to_deflate_extra_bitlen[prev_dist]
- else
- dist_code = 16
- dist_extra_bits_bitlen = 7
- local a = 384
- local b = 512
-
- while true do
- if prev_dist <= a then
- dist_extra_bits = (prev_dist-(b/2)-1) % (b/4)
- break
- elseif prev_dist <= b then
- dist_extra_bits = (prev_dist-(b/2)-1) % (b/4)
- dist_code = dist_code + 1
- break
- else
- dist_code = dist_code + 2
- dist_extra_bits_bitlen = dist_extra_bits_bitlen + 1
- a = a*2
- b = b*2
- end
- end
- end
- lcode_tblsize = lcode_tblsize + 1
- lcodes[lcode_tblsize] = code
- lcodes_counts[code] = (lcodes_counts[code] or 0) + 1
-
- dcodes_tblsize = dcodes_tblsize + 1
- dcodes[dcodes_tblsize] = dist_code
- dcodes_counts[dist_code] = (dcodes_counts[dist_code] or 0) + 1
-
- if length_extra_bits_bitlen > 0 then
- local lenExtraBits = _length_to_deflate_extra_bits[prev_len]
- lextra_bits_tblsize = lextra_bits_tblsize + 1
- lextra_bits[lextra_bits_tblsize] = lenExtraBits
- end
- if dist_extra_bits_bitlen > 0 then
- dextra_bits_tblsize = dextra_bits_tblsize + 1
- dextra_bits[dextra_bits_tblsize] = dist_extra_bits
- end
-
- for i=index+1, index+prev_len-(config_use_lazy and 2 or 1) do
- hash = (hash*256+(string_table[i-offset+2] or 0))%16777216
- if prev_len <= config_max_insert_length then
- hash_chain = hash_tables[hash]
- if not hash_chain then
- hash_chain = {}
- hash_tables[hash] = hash_chain
- end
- hash_chain[#hash_chain+1] = i
- end
- end
- index = index + prev_len - (config_use_lazy and 1 or 0)
- match_available = false
- elseif (not config_use_lazy) or match_available then
- local code = string_table[config_use_lazy
- and (string_table_index-1) or string_table_index]
- lcode_tblsize = lcode_tblsize + 1
- lcodes[lcode_tblsize] = code
- lcodes_counts[code] = (lcodes_counts[code] or 0) + 1
- index = index + 1
- else
- match_available = true
- index = index + 1
- end
- end
-
- -- Write "end of block" symbol
- lcode_tblsize = lcode_tblsize + 1
- lcodes[lcode_tblsize] = 256
- lcodes_counts[256] = (lcodes_counts[256] or 0) + 1
-
- return lcodes, lextra_bits, lcodes_counts, dcodes, dextra_bits
- , dcodes_counts
+ block_end, offset, dictionary)
+ local config = _compression_level_configs[level]
+ local config_use_lazy, config_good_prev_length, config_max_lazy_match,
+ config_nice_length, config_max_hash_chain = config[1], config[2],
+ config[3], config[4],
+ config[5]
+
+ local config_max_insert_length = (not config_use_lazy) and
+ config_max_lazy_match or 2147483646
+ local config_good_hash_chain =
+ (config_max_hash_chain - config_max_hash_chain % 4 / 4)
+
+ local hash
+
+ local dict_hash_tables
+ local dict_string_table
+ local dict_string_len = 0
+
+ if dictionary then
+ dict_hash_tables = dictionary.hash_tables
+ dict_string_table = dictionary.string_table
+ dict_string_len = dictionary.strlen
+ assert(block_start == 1)
+ if block_end >= block_start and dict_string_len >= 2 then
+ hash = dict_string_table[dict_string_len - 1] * 65536 +
+ dict_string_table[dict_string_len] * 256 + string_table[1]
+ local t = hash_tables[hash]
+ if not t then
+ t = {};
+ hash_tables[hash] = t
+ end
+ t[#t + 1] = -1
+ end
+ if block_end >= block_start + 1 and dict_string_len >= 1 then
+ hash =
+ dict_string_table[dict_string_len] * 65536 + string_table[1] * 256 +
+ string_table[2]
+ local t = hash_tables[hash]
+ if not t then
+ t = {};
+ hash_tables[hash] = t
+ end
+ t[#t + 1] = 0
+ end
+ end
+
+ local dict_string_len_plus3 = dict_string_len + 3
+
+ hash = (string_table[block_start - offset] or 0) * 256 +
+ (string_table[block_start + 1 - offset] or 0)
+
+ local lcodes = {}
+ local lcode_tblsize = 0
+ local lcodes_counts = {}
+ local dcodes = {}
+ local dcodes_tblsize = 0
+ local dcodes_counts = {}
+
+ local lextra_bits = {}
+ local lextra_bits_tblsize = 0
+ local dextra_bits = {}
+ local dextra_bits_tblsize = 0
+
+ local match_available = false
+ local prev_len
+ local prev_dist
+ local cur_len = 0
+ local cur_dist = 0
+
+ local index = block_start
+ local index_end = block_end + (config_use_lazy and 1 or 0)
+
+ -- the zlib source code writes separate code for lazy evaluation and
+ -- not lazy evaluation, which is easier to understand.
+ -- I put them together, so it is a bit harder to understand.
+ -- because I think this is easier for me to maintain it.
+ while (index <= index_end) do
+ local string_table_index = index - offset
+ local offset_minus_three = offset - 3
+ prev_len = cur_len
+ prev_dist = cur_dist
+ cur_len = 0
+
+ hash = (hash * 256 + (string_table[string_table_index + 2] or 0)) % 16777216
+
+ local chain_index
+ local cur_chain
+ local hash_chain = hash_tables[hash]
+ local chain_old_size
+ if not hash_chain then
+ chain_old_size = 0
+ hash_chain = {}
+ hash_tables[hash] = hash_chain
+ if dict_hash_tables then
+ cur_chain = dict_hash_tables[hash]
+ chain_index = cur_chain and #cur_chain or 0
+ else
+ chain_index = 0
+ end
+ else
+ chain_old_size = #hash_chain
+ cur_chain = hash_chain
+ chain_index = chain_old_size
+ end
+
+ if index <= block_end then hash_chain[chain_old_size + 1] = index end
+
+ if (chain_index > 0 and index + 2 <= block_end and
+ (not config_use_lazy or prev_len < config_max_lazy_match)) then
+
+ local depth =
+ (config_use_lazy and prev_len >= config_good_prev_length) and
+ config_good_hash_chain or config_max_hash_chain
+
+ local max_len_minus_one = block_end - index
+ max_len_minus_one = (max_len_minus_one >= 257) and 257 or
+ max_len_minus_one
+ max_len_minus_one = max_len_minus_one + string_table_index
+ local string_table_index_plus_three = string_table_index + 3
+
+ while chain_index >= 1 and depth > 0 do
+ local prev = cur_chain[chain_index]
+
+ if index - prev > 32768 then break end
+ if prev < index then
+ local sj = string_table_index_plus_three
+
+ if prev >= -257 then
+ local pj = prev - offset_minus_three
+ while (sj <= max_len_minus_one and string_table[pj] ==
+ string_table[sj]) do
+ sj = sj + 1
+ pj = pj + 1
+ end
+ else
+ local pj = dict_string_len_plus3 + prev
+ while (sj <= max_len_minus_one and dict_string_table[pj] ==
+ string_table[sj]) do
+ sj = sj + 1
+ pj = pj + 1
+ end
+ end
+ local j = sj - string_table_index
+ if j > cur_len then
+ cur_len = j
+ cur_dist = index - prev
+ end
+ if cur_len >= config_nice_length then break end
+ end
+
+ chain_index = chain_index - 1
+ depth = depth - 1
+ if chain_index == 0 and prev > 0 and dict_hash_tables then
+ cur_chain = dict_hash_tables[hash]
+ chain_index = cur_chain and #cur_chain or 0
+ end
+ end
+ end
+
+ if not config_use_lazy then prev_len, prev_dist = cur_len, cur_dist end
+ if ((not config_use_lazy or match_available) and
+ (prev_len > 3 or (prev_len == 3 and prev_dist < 4096)) and cur_len <=
+ prev_len) then
+ local code = _length_to_deflate_code[prev_len]
+ local length_extra_bits_bitlen = _length_to_deflate_extra_bitlen[prev_len]
+ local dist_code, dist_extra_bits_bitlen, dist_extra_bits
+ if prev_dist <= 256 then -- have cached code for small distance.
+ dist_code = _dist256_to_deflate_code[prev_dist]
+ dist_extra_bits = _dist256_to_deflate_extra_bits[prev_dist]
+ dist_extra_bits_bitlen = _dist256_to_deflate_extra_bitlen[prev_dist]
+ else
+ dist_code = 16
+ dist_extra_bits_bitlen = 7
+ local a = 384
+ local b = 512
+
+ while true do
+ if prev_dist <= a then
+ dist_extra_bits = (prev_dist - (b / 2) - 1) % (b / 4)
+ break
+ elseif prev_dist <= b then
+ dist_extra_bits = (prev_dist - (b / 2) - 1) % (b / 4)
+ dist_code = dist_code + 1
+ break
+ else
+ dist_code = dist_code + 2
+ dist_extra_bits_bitlen = dist_extra_bits_bitlen + 1
+ a = a * 2
+ b = b * 2
+ end
+ end
+ end
+ lcode_tblsize = lcode_tblsize + 1
+ lcodes[lcode_tblsize] = code
+ lcodes_counts[code] = (lcodes_counts[code] or 0) + 1
+
+ dcodes_tblsize = dcodes_tblsize + 1
+ dcodes[dcodes_tblsize] = dist_code
+ dcodes_counts[dist_code] = (dcodes_counts[dist_code] or 0) + 1
+
+ if length_extra_bits_bitlen > 0 then
+ local lenExtraBits = _length_to_deflate_extra_bits[prev_len]
+ lextra_bits_tblsize = lextra_bits_tblsize + 1
+ lextra_bits[lextra_bits_tblsize] = lenExtraBits
+ end
+ if dist_extra_bits_bitlen > 0 then
+ dextra_bits_tblsize = dextra_bits_tblsize + 1
+ dextra_bits[dextra_bits_tblsize] = dist_extra_bits
+ end
+
+ for i = index + 1, index + prev_len - (config_use_lazy and 2 or 1) do
+ hash = (hash * 256 + (string_table[i - offset + 2] or 0)) % 16777216
+ if prev_len <= config_max_insert_length then
+ hash_chain = hash_tables[hash]
+ if not hash_chain then
+ hash_chain = {}
+ hash_tables[hash] = hash_chain
+ end
+ hash_chain[#hash_chain + 1] = i
+ end
+ end
+ index = index + prev_len - (config_use_lazy and 1 or 0)
+ match_available = false
+ elseif (not config_use_lazy) or match_available then
+ local code = string_table[config_use_lazy and (string_table_index - 1) or
+ string_table_index]
+ lcode_tblsize = lcode_tblsize + 1
+ lcodes[lcode_tblsize] = code
+ lcodes_counts[code] = (lcodes_counts[code] or 0) + 1
+ index = index + 1
+ else
+ match_available = true
+ index = index + 1
+ end
+ end
+
+ -- Write "end of block" symbol
+ lcode_tblsize = lcode_tblsize + 1
+ lcodes[lcode_tblsize] = 256
+ lcodes_counts[256] = (lcodes_counts[256] or 0) + 1
+
+ return lcodes, lextra_bits, lcodes_counts, dcodes, dextra_bits, dcodes_counts
end
-- Get the header data of dynamic block.
@@ -1449,154 +1489,154 @@ end
-- @return a lots of stuffs.
-- @see RFC1951 Page 12
local function GetBlockDynamicHuffmanHeader(lcodes_counts, dcodes_counts)
- local lcodes_huffman_bitlens, lcodes_huffman_codes
- , max_non_zero_bitlen_lcode =
- GetHuffmanBitlenAndCode(lcodes_counts, 15, 285)
- local dcodes_huffman_bitlens, dcodes_huffman_codes
- , max_non_zero_bitlen_dcode =
- GetHuffmanBitlenAndCode(dcodes_counts, 15, 29)
-
- local rle_deflate_codes, rle_extra_bits, rle_codes_counts =
- RunLengthEncodeHuffmanBitlen(lcodes_huffman_bitlens
- ,max_non_zero_bitlen_lcode, dcodes_huffman_bitlens
- , max_non_zero_bitlen_dcode)
-
- local rle_codes_huffman_bitlens, rle_codes_huffman_codes =
- GetHuffmanBitlenAndCode(rle_codes_counts, 7, 18)
-
- local HCLEN = 0
- for i = 1, 19 do
- local symbol = _rle_codes_huffman_bitlen_order[i]
- local length = rle_codes_huffman_bitlens[symbol] or 0
- if length ~= 0 then
- HCLEN = i
- end
- end
-
- HCLEN = HCLEN - 4
- local HLIT = max_non_zero_bitlen_lcode + 1 - 257
- local HDIST = max_non_zero_bitlen_dcode + 1 - 1
- if HDIST < 0 then HDIST = 0 end
-
- return HLIT, HDIST, HCLEN, rle_codes_huffman_bitlens
- , rle_codes_huffman_codes, rle_deflate_codes, rle_extra_bits
- , lcodes_huffman_bitlens, lcodes_huffman_codes
- , dcodes_huffman_bitlens, dcodes_huffman_codes
+ local lcodes_huffman_bitlens, lcodes_huffman_codes, max_non_zero_bitlen_lcode =
+ GetHuffmanBitlenAndCode(lcodes_counts, 15, 285)
+ local dcodes_huffman_bitlens, dcodes_huffman_codes, max_non_zero_bitlen_dcode =
+ GetHuffmanBitlenAndCode(dcodes_counts, 15, 29)
+
+ local rle_deflate_codes, rle_extra_bits, rle_codes_counts =
+ RunLengthEncodeHuffmanBitlen(lcodes_huffman_bitlens,
+ max_non_zero_bitlen_lcode,
+ dcodes_huffman_bitlens,
+ max_non_zero_bitlen_dcode)
+
+ local rle_codes_huffman_bitlens, rle_codes_huffman_codes =
+ GetHuffmanBitlenAndCode(rle_codes_counts, 7, 18)
+
+ local HCLEN = 0
+ for i = 1, 19 do
+ local symbol = _rle_codes_huffman_bitlen_order[i]
+ local length = rle_codes_huffman_bitlens[symbol] or 0
+ if length ~= 0 then HCLEN = i end
+ end
+
+ HCLEN = HCLEN - 4
+ local HLIT = max_non_zero_bitlen_lcode + 1 - 257
+ local HDIST = max_non_zero_bitlen_dcode + 1 - 1
+ if HDIST < 0 then HDIST = 0 end
+
+ return HLIT, HDIST, HCLEN, rle_codes_huffman_bitlens, rle_codes_huffman_codes,
+ rle_deflate_codes, rle_extra_bits, lcodes_huffman_bitlens,
+ lcodes_huffman_codes, dcodes_huffman_bitlens, dcodes_huffman_codes
end
-- Get the size of dynamic block without writing any bits into the writer.
-- @param ... Read the source code of GetBlockDynamicHuffmanHeader()
-- @return the bit length of the dynamic block
-local function GetDynamicHuffmanBlockSize(lcodes, dcodes, HCLEN
- , rle_codes_huffman_bitlens, rle_deflate_codes
- , lcodes_huffman_bitlens, dcodes_huffman_bitlens)
-
- local block_bitlen = 17 -- 1+2+5+5+4
- block_bitlen = block_bitlen + (HCLEN+4)*3
-
- for i = 1, #rle_deflate_codes do
- local code = rle_deflate_codes[i]
- block_bitlen = block_bitlen + rle_codes_huffman_bitlens[code]
- if code >= 16 then
- block_bitlen = block_bitlen +
- ((code == 16) and 2 or (code == 17 and 3 or 7))
- end
- end
-
- local length_code_count = 0
- for i = 1, #lcodes do
- local code = lcodes[i]
- local huffman_bitlen = lcodes_huffman_bitlens[code]
- block_bitlen = block_bitlen + huffman_bitlen
- if code > 256 then -- Length code
- length_code_count = length_code_count + 1
- if code > 264 and code < 285 then -- Length code with extra bits
- local extra_bits_bitlen =
- _literal_deflate_code_to_extra_bitlen[code-256]
- block_bitlen = block_bitlen + extra_bits_bitlen
- end
- local dist_code = dcodes[length_code_count]
- local dist_huffman_bitlen = dcodes_huffman_bitlens[dist_code]
- block_bitlen = block_bitlen + dist_huffman_bitlen
-
- if dist_code > 3 then -- dist code with extra bits
- local dist_extra_bits_bitlen = (dist_code-dist_code%2)/2 - 1
- block_bitlen = block_bitlen + dist_extra_bits_bitlen
- end
- end
- end
- return block_bitlen
+local function GetDynamicHuffmanBlockSize(lcodes, dcodes, HCLEN,
+ rle_codes_huffman_bitlens,
+ rle_deflate_codes,
+ lcodes_huffman_bitlens,
+ dcodes_huffman_bitlens)
+
+ local block_bitlen = 17 -- 1+2+5+5+4
+ block_bitlen = block_bitlen + (HCLEN + 4) * 3
+
+ for i = 1, #rle_deflate_codes do
+ local code = rle_deflate_codes[i]
+ block_bitlen = block_bitlen + rle_codes_huffman_bitlens[code]
+ if code >= 16 then
+ block_bitlen = block_bitlen +
+ ((code == 16) and 2 or (code == 17 and 3 or 7))
+ end
+ end
+
+ local length_code_count = 0
+ for i = 1, #lcodes do
+ local code = lcodes[i]
+ local huffman_bitlen = lcodes_huffman_bitlens[code]
+ block_bitlen = block_bitlen + huffman_bitlen
+ if code > 256 then -- Length code
+ length_code_count = length_code_count + 1
+ if code > 264 and code < 285 then -- Length code with extra bits
+ local extra_bits_bitlen = _literal_deflate_code_to_extra_bitlen[code -
+ 256]
+ block_bitlen = block_bitlen + extra_bits_bitlen
+ end
+ local dist_code = dcodes[length_code_count]
+ local dist_huffman_bitlen = dcodes_huffman_bitlens[dist_code]
+ block_bitlen = block_bitlen + dist_huffman_bitlen
+
+ if dist_code > 3 then -- dist code with extra bits
+ local dist_extra_bits_bitlen = (dist_code - dist_code % 2) / 2 - 1
+ block_bitlen = block_bitlen + dist_extra_bits_bitlen
+ end
+ end
+ end
+ return block_bitlen
end
-- Write dynamic block.
-- @param ... Read the source code of GetBlockDynamicHuffmanHeader()
-local function CompressDynamicHuffmanBlock(WriteBits, is_last_block
- , lcodes, lextra_bits, dcodes, dextra_bits, HLIT, HDIST, HCLEN
- , rle_codes_huffman_bitlens, rle_codes_huffman_codes
- , rle_deflate_codes, rle_extra_bits
- , lcodes_huffman_bitlens, lcodes_huffman_codes
- , dcodes_huffman_bitlens, dcodes_huffman_codes)
-
- WriteBits(is_last_block and 1 or 0, 1) -- Last block identifier
- WriteBits(2, 2) -- Dynamic Huffman block identifier
-
- WriteBits(HLIT, 5)
- WriteBits(HDIST, 5)
- WriteBits(HCLEN, 4)
-
- for i = 1, HCLEN+4 do
- local symbol = _rle_codes_huffman_bitlen_order[i]
- local length = rle_codes_huffman_bitlens[symbol] or 0
- WriteBits(length, 3)
- end
-
- local rleExtraBitsIndex = 1
- for i=1, #rle_deflate_codes do
- local code = rle_deflate_codes[i]
- WriteBits(rle_codes_huffman_codes[code]
- , rle_codes_huffman_bitlens[code])
- if code >= 16 then
- local extraBits = rle_extra_bits[rleExtraBitsIndex]
- WriteBits(extraBits, (code == 16) and 2 or (code == 17 and 3 or 7))
- rleExtraBitsIndex = rleExtraBitsIndex + 1
- end
- end
-
- local length_code_count = 0
- local length_code_with_extra_count = 0
- local dist_code_with_extra_count = 0
-
- for i=1, #lcodes do
- local deflate_codee = lcodes[i]
- local huffman_code = lcodes_huffman_codes[deflate_codee]
- local huffman_bitlen = lcodes_huffman_bitlens[deflate_codee]
- WriteBits(huffman_code, huffman_bitlen)
- if deflate_codee > 256 then -- Length code
- length_code_count = length_code_count + 1
- if deflate_codee > 264 and deflate_codee < 285 then
- -- Length code with extra bits
- length_code_with_extra_count = length_code_with_extra_count + 1
- local extra_bits = lextra_bits[length_code_with_extra_count]
- local extra_bits_bitlen =
- _literal_deflate_code_to_extra_bitlen[deflate_codee-256]
- WriteBits(extra_bits, extra_bits_bitlen)
- end
- -- Write distance code
- local dist_deflate_code = dcodes[length_code_count]
- local dist_huffman_code = dcodes_huffman_codes[dist_deflate_code]
- local dist_huffman_bitlen =
- dcodes_huffman_bitlens[dist_deflate_code]
- WriteBits(dist_huffman_code, dist_huffman_bitlen)
-
- if dist_deflate_code > 3 then -- dist code with extra bits
- dist_code_with_extra_count = dist_code_with_extra_count + 1
- local dist_extra_bits = dextra_bits[dist_code_with_extra_count]
- local dist_extra_bits_bitlen =
- (dist_deflate_code-dist_deflate_code%2)/2 - 1
- WriteBits(dist_extra_bits, dist_extra_bits_bitlen)
- end
- end
- end
+local function CompressDynamicHuffmanBlock(WriteBits, is_last_block, lcodes,
+ lextra_bits, dcodes, dextra_bits,
+ HLIT, HDIST, HCLEN,
+ rle_codes_huffman_bitlens,
+ rle_codes_huffman_codes,
+ rle_deflate_codes, rle_extra_bits,
+ lcodes_huffman_bitlens,
+ lcodes_huffman_codes,
+ dcodes_huffman_bitlens,
+ dcodes_huffman_codes)
+
+ WriteBits(is_last_block and 1 or 0, 1) -- Last block identifier
+ WriteBits(2, 2) -- Dynamic Huffman block identifier
+
+ WriteBits(HLIT, 5)
+ WriteBits(HDIST, 5)
+ WriteBits(HCLEN, 4)
+
+ for i = 1, HCLEN + 4 do
+ local symbol = _rle_codes_huffman_bitlen_order[i]
+ local length = rle_codes_huffman_bitlens[symbol] or 0
+ WriteBits(length, 3)
+ end
+
+ local rleExtraBitsIndex = 1
+ for i = 1, #rle_deflate_codes do
+ local code = rle_deflate_codes[i]
+ WriteBits(rle_codes_huffman_codes[code], rle_codes_huffman_bitlens[code])
+ if code >= 16 then
+ local extraBits = rle_extra_bits[rleExtraBitsIndex]
+ WriteBits(extraBits, (code == 16) and 2 or (code == 17 and 3 or 7))
+ rleExtraBitsIndex = rleExtraBitsIndex + 1
+ end
+ end
+
+ local length_code_count = 0
+ local length_code_with_extra_count = 0
+ local dist_code_with_extra_count = 0
+
+ for i = 1, #lcodes do
+ local deflate_codee = lcodes[i]
+ local huffman_code = lcodes_huffman_codes[deflate_codee]
+ local huffman_bitlen = lcodes_huffman_bitlens[deflate_codee]
+ WriteBits(huffman_code, huffman_bitlen)
+ if deflate_codee > 256 then -- Length code
+ length_code_count = length_code_count + 1
+ if deflate_codee > 264 and deflate_codee < 285 then
+ -- Length code with extra bits
+ length_code_with_extra_count = length_code_with_extra_count + 1
+ local extra_bits = lextra_bits[length_code_with_extra_count]
+ local extra_bits_bitlen =
+ _literal_deflate_code_to_extra_bitlen[deflate_codee - 256]
+ WriteBits(extra_bits, extra_bits_bitlen)
+ end
+ -- Write distance code
+ local dist_deflate_code = dcodes[length_code_count]
+ local dist_huffman_code = dcodes_huffman_codes[dist_deflate_code]
+ local dist_huffman_bitlen = dcodes_huffman_bitlens[dist_deflate_code]
+ WriteBits(dist_huffman_code, dist_huffman_bitlen)
+
+ if dist_deflate_code > 3 then -- dist code with extra bits
+ dist_code_with_extra_count = dist_code_with_extra_count + 1
+ local dist_extra_bits = dextra_bits[dist_code_with_extra_count]
+ local dist_extra_bits_bitlen = (dist_deflate_code - dist_deflate_code %
+ 2) / 2 - 1
+ WriteBits(dist_extra_bits, dist_extra_bits_bitlen)
+ end
+ end
+ end
end
-- Get the size of fixed block without writing any bits into the writer.
@@ -1604,70 +1644,69 @@ end
-- @param decodes LZ77 distance deflate codes
-- @return the bit length of the fixed block
local function GetFixedHuffmanBlockSize(lcodes, dcodes)
- local block_bitlen = 3
- local length_code_count = 0
- for i=1, #lcodes do
- local code = lcodes[i]
- local huffman_bitlen = _fix_block_literal_huffman_bitlen[code]
- block_bitlen = block_bitlen + huffman_bitlen
- if code > 256 then -- Length code
- length_code_count = length_code_count + 1
- if code > 264 and code < 285 then -- Length code with extra bits
- local extra_bits_bitlen =
- _literal_deflate_code_to_extra_bitlen[code-256]
- block_bitlen = block_bitlen + extra_bits_bitlen
- end
- local dist_code = dcodes[length_code_count]
- block_bitlen = block_bitlen + 5
-
- if dist_code > 3 then -- dist code with extra bits
- local dist_extra_bits_bitlen =
- (dist_code-dist_code%2)/2 - 1
- block_bitlen = block_bitlen + dist_extra_bits_bitlen
- end
- end
- end
- return block_bitlen
+ local block_bitlen = 3
+ local length_code_count = 0
+ for i = 1, #lcodes do
+ local code = lcodes[i]
+ local huffman_bitlen = _fix_block_literal_huffman_bitlen[code]
+ block_bitlen = block_bitlen + huffman_bitlen
+ if code > 256 then -- Length code
+ length_code_count = length_code_count + 1
+ if code > 264 and code < 285 then -- Length code with extra bits
+ local extra_bits_bitlen = _literal_deflate_code_to_extra_bitlen[code -
+ 256]
+ block_bitlen = block_bitlen + extra_bits_bitlen
+ end
+ local dist_code = dcodes[length_code_count]
+ block_bitlen = block_bitlen + 5
+
+ if dist_code > 3 then -- dist code with extra bits
+ local dist_extra_bits_bitlen = (dist_code - dist_code % 2) / 2 - 1
+ block_bitlen = block_bitlen + dist_extra_bits_bitlen
+ end
+ end
+ end
+ return block_bitlen
end
-- Write fixed block.
-- @param lcodes literal/LZ77_length deflate codes
-- @param decodes LZ77 distance deflate codes
-local function CompressFixedHuffmanBlock(WriteBits, is_last_block,
- lcodes, lextra_bits, dcodes, dextra_bits)
- WriteBits(is_last_block and 1 or 0, 1) -- Last block identifier
- WriteBits(1, 2) -- Fixed Huffman block identifier
- local length_code_count = 0
- local length_code_with_extra_count = 0
- local dist_code_with_extra_count = 0
- for i=1, #lcodes do
- local deflate_code = lcodes[i]
- local huffman_code = _fix_block_literal_huffman_code[deflate_code]
- local huffman_bitlen = _fix_block_literal_huffman_bitlen[deflate_code]
- WriteBits(huffman_code, huffman_bitlen)
- if deflate_code > 256 then -- Length code
- length_code_count = length_code_count + 1
- if deflate_code > 264 and deflate_code < 285 then
- -- Length code with extra bits
- length_code_with_extra_count = length_code_with_extra_count + 1
- local extra_bits = lextra_bits[length_code_with_extra_count]
- local extra_bits_bitlen =
- _literal_deflate_code_to_extra_bitlen[deflate_code-256]
- WriteBits(extra_bits, extra_bits_bitlen)
- end
- -- Write distance code
- local dist_code = dcodes[length_code_count]
- local dist_huffman_code = _fix_block_dist_huffman_code[dist_code]
- WriteBits(dist_huffman_code, 5)
-
- if dist_code > 3 then -- dist code with extra bits
- dist_code_with_extra_count = dist_code_with_extra_count + 1
- local dist_extra_bits = dextra_bits[dist_code_with_extra_count]
- local dist_extra_bits_bitlen = (dist_code-dist_code%2)/2 - 1
- WriteBits(dist_extra_bits, dist_extra_bits_bitlen)
- end
- end
- end
+local function CompressFixedHuffmanBlock(WriteBits, is_last_block, lcodes,
+ lextra_bits, dcodes, dextra_bits)
+ WriteBits(is_last_block and 1 or 0, 1) -- Last block identifier
+ WriteBits(1, 2) -- Fixed Huffman block identifier
+ local length_code_count = 0
+ local length_code_with_extra_count = 0
+ local dist_code_with_extra_count = 0
+ for i = 1, #lcodes do
+ local deflate_code = lcodes[i]
+ local huffman_code = _fix_block_literal_huffman_code[deflate_code]
+ local huffman_bitlen = _fix_block_literal_huffman_bitlen[deflate_code]
+ WriteBits(huffman_code, huffman_bitlen)
+ if deflate_code > 256 then -- Length code
+ length_code_count = length_code_count + 1
+ if deflate_code > 264 and deflate_code < 285 then
+ -- Length code with extra bits
+ length_code_with_extra_count = length_code_with_extra_count + 1
+ local extra_bits = lextra_bits[length_code_with_extra_count]
+ local extra_bits_bitlen =
+ _literal_deflate_code_to_extra_bitlen[deflate_code - 256]
+ WriteBits(extra_bits, extra_bits_bitlen)
+ end
+ -- Write distance code
+ local dist_code = dcodes[length_code_count]
+ local dist_huffman_code = _fix_block_dist_huffman_code[dist_code]
+ WriteBits(dist_huffman_code, 5)
+
+ if dist_code > 3 then -- dist code with extra bits
+ dist_code_with_extra_count = dist_code_with_extra_count + 1
+ local dist_extra_bits = dextra_bits[dist_code_with_extra_count]
+ local dist_extra_bits_bitlen = (dist_code - dist_code % 2) / 2 - 1
+ WriteBits(dist_extra_bits, dist_extra_bits_bitlen)
+ end
+ end
+ end
end
-- Get the size of store block without writing any bits into the writer.
@@ -1677,37 +1716,37 @@ end
-- because store block needs to shift to byte boundary.
-- @return the bit length of the fixed block
local function GetStoreBlockSize(block_start, block_end, total_bitlen)
- assert(block_end-block_start+1 <= 65535)
- local block_bitlen = 3
- total_bitlen = total_bitlen + 3
- local padding_bitlen = (8-total_bitlen%8)%8
- block_bitlen = block_bitlen + padding_bitlen
- block_bitlen = block_bitlen + 32
- block_bitlen = block_bitlen + (block_end - block_start + 1) * 8
- return block_bitlen
+ assert(block_end - block_start + 1 <= 65535)
+ local block_bitlen = 3
+ total_bitlen = total_bitlen + 3
+ local padding_bitlen = (8 - total_bitlen % 8) % 8
+ block_bitlen = block_bitlen + padding_bitlen
+ block_bitlen = block_bitlen + 32
+ block_bitlen = block_bitlen + (block_end - block_start + 1) * 8
+ return block_bitlen
end
-- Write the store block.
-- @param ... lots of stuffs
-- @return nil
-local function CompressStoreBlock(WriteBits, WriteString, is_last_block, str
- , block_start, block_end, total_bitlen)
- assert(block_end-block_start+1 <= 65535)
- WriteBits(is_last_block and 1 or 0, 1) -- Last block identifer.
- WriteBits(0, 2) -- Store block identifier.
- total_bitlen = total_bitlen + 3
- local padding_bitlen = (8-total_bitlen%8)%8
- if padding_bitlen > 0 then
- WriteBits(_pow2[padding_bitlen]-1, padding_bitlen)
- end
- local size = block_end - block_start + 1
- WriteBits(size, 16)
-
- -- Write size's one's complement
- local comp = (255 - size % 256) + (255 - (size-size%256)/256)*256
- WriteBits(comp, 16)
-
- WriteString(str:sub(block_start, block_end))
+local function CompressStoreBlock(WriteBits, WriteString, is_last_block, str,
+ block_start, block_end, total_bitlen)
+ assert(block_end - block_start + 1 <= 65535)
+ WriteBits(is_last_block and 1 or 0, 1) -- Last block identifer.
+ WriteBits(0, 2) -- Store block identifier.
+ total_bitlen = total_bitlen + 3
+ local padding_bitlen = (8 - total_bitlen % 8) % 8
+ if padding_bitlen > 0 then
+ WriteBits(_pow2[padding_bitlen] - 1, padding_bitlen)
+ end
+ local size = block_end - block_start + 1
+ WriteBits(size, 16)
+
+ -- Write size's one's complement
+ local comp = (255 - size % 256) + (255 - (size - size % 256) / 256) * 256
+ WriteBits(comp, 16)
+
+ WriteString(str:sub(block_start, block_end))
end
-- Do the deflate
@@ -1721,195 +1760,188 @@ end
-- 64KB, then memory cleanup won't happen.
-- This function determines whether to use store/fixed/dynamic blocks by
-- calculating the block size of each block type and chooses the smallest one.
-local function Deflate(configs, WriteBits, WriteString, FlushWriter, str
- , dictionary)
- local string_table = {}
- local hash_tables = {}
- local is_last_block = nil
- local block_start
- local block_end
- local bitlen_written
- local total_bitlen = FlushWriter(_FLUSH_MODE_NO_FLUSH)
- local strlen = #str
- local offset
-
- local level
- local strategy
- if configs then
- if configs.level then
- level = configs.level
- end
- if configs.strategy then
- strategy = configs.strategy
- end
- end
-
- if not level then
- if strlen < 2048 then
- level = 7
- elseif strlen > 65536 then
- level = 3
- else
- level = 5
- end
- end
-
- while not is_last_block do
- if not block_start then
- block_start = 1
- block_end = 64*1024 - 1
- offset = 0
- else
- block_start = block_end + 1
- block_end = block_end + 32*1024
- offset = block_start - 32*1024 - 1
- end
-
- if block_end >= strlen then
- block_end = strlen
- is_last_block = true
- else
- is_last_block = false
- end
-
- local lcodes, lextra_bits, lcodes_counts, dcodes, dextra_bits
- , dcodes_counts
-
- local HLIT, HDIST, HCLEN, rle_codes_huffman_bitlens
- , rle_codes_huffman_codes, rle_deflate_codes
- , rle_extra_bits, lcodes_huffman_bitlens, lcodes_huffman_codes
- , dcodes_huffman_bitlens, dcodes_huffman_codes
-
- local dynamic_block_bitlen
- local fixed_block_bitlen
- local store_block_bitlen
-
- if level ~= 0 then
-
- -- GetBlockLZ77 needs block_start to block_end+3 to be loaded.
- LoadStringToTable(str, string_table, block_start, block_end + 3
- , offset)
- if block_start == 1 and dictionary then
- local dict_string_table = dictionary.string_table
- local dict_strlen = dictionary.strlen
- for i=0, (-dict_strlen+1)<-257
- and -257 or (-dict_strlen+1), -1 do
- string_table[i] = dict_string_table[dict_strlen+i]
- end
- end
-
- if strategy == "huffman_only" then
- lcodes = {}
- LoadStringToTable(str, lcodes, block_start, block_end
- , block_start-1)
- lextra_bits = {}
- lcodes_counts = {}
- lcodes[block_end - block_start+2] = 256 -- end of block
- for i=1, block_end - block_start+2 do
- local code = lcodes[i]
- lcodes_counts[code] = (lcodes_counts[code] or 0) + 1
- end
- dcodes = {}
- dextra_bits = {}
- dcodes_counts = {}
- else
- lcodes, lextra_bits, lcodes_counts, dcodes, dextra_bits
- , dcodes_counts = GetBlockLZ77Result(level, string_table
- , hash_tables, block_start, block_end, offset, dictionary
- )
- end
-
- HLIT, HDIST, HCLEN, rle_codes_huffman_bitlens
- , rle_codes_huffman_codes, rle_deflate_codes
- , rle_extra_bits, lcodes_huffman_bitlens, lcodes_huffman_codes
- , dcodes_huffman_bitlens, dcodes_huffman_codes =
- GetBlockDynamicHuffmanHeader(lcodes_counts, dcodes_counts)
- dynamic_block_bitlen = GetDynamicHuffmanBlockSize(
- lcodes, dcodes, HCLEN, rle_codes_huffman_bitlens
- , rle_deflate_codes, lcodes_huffman_bitlens
- , dcodes_huffman_bitlens)
- fixed_block_bitlen = GetFixedHuffmanBlockSize(lcodes, dcodes)
- end
-
- store_block_bitlen = GetStoreBlockSize(block_start, block_end
- , total_bitlen)
-
- local min_bitlen = store_block_bitlen
- min_bitlen = (fixed_block_bitlen and fixed_block_bitlen < min_bitlen)
- and fixed_block_bitlen or min_bitlen
- min_bitlen = (dynamic_block_bitlen
- and dynamic_block_bitlen < min_bitlen)
- and dynamic_block_bitlen or min_bitlen
-
- if level == 0 or (strategy ~= "fixed" and strategy ~= "dynamic" and
- store_block_bitlen == min_bitlen) then
- CompressStoreBlock(WriteBits, WriteString, is_last_block
- , str, block_start, block_end, total_bitlen)
- total_bitlen = total_bitlen + store_block_bitlen
- elseif strategy ~= "dynamic" and (
- strategy == "fixed" or fixed_block_bitlen == min_bitlen) then
- CompressFixedHuffmanBlock(WriteBits, is_last_block,
- lcodes, lextra_bits, dcodes, dextra_bits)
- total_bitlen = total_bitlen + fixed_block_bitlen
- elseif strategy == "dynamic" or dynamic_block_bitlen == min_bitlen then
- CompressDynamicHuffmanBlock(WriteBits, is_last_block, lcodes
- , lextra_bits, dcodes, dextra_bits, HLIT, HDIST, HCLEN
- , rle_codes_huffman_bitlens, rle_codes_huffman_codes
- , rle_deflate_codes, rle_extra_bits
- , lcodes_huffman_bitlens, lcodes_huffman_codes
- , dcodes_huffman_bitlens, dcodes_huffman_codes)
- total_bitlen = total_bitlen + dynamic_block_bitlen
- end
-
- if is_last_block then
- bitlen_written = FlushWriter(_FLUSH_MODE_NO_FLUSH)
- else
- bitlen_written = FlushWriter(_FLUSH_MODE_MEMORY_CLEANUP)
- end
-
- assert(bitlen_written == total_bitlen)
-
- -- Memory clean up, so memory consumption does not always grow linearly
- -- , even if input string is > 64K.
- -- Not a very efficient operation, but this operation won't happen
- -- when the input data size is less than 64K.
- if not is_last_block then
- local j
- if dictionary and block_start == 1 then
- j = 0
- while (string_table[j]) do
- string_table[j] = nil
- j = j - 1
- end
- end
- dictionary = nil
- j = 1
- for i = block_end-32767, block_end do
- string_table[j] = string_table[i-offset]
- j = j + 1
- end
-
- for k, t in pairs(hash_tables) do
- local tSize = #t
- if tSize > 0 and block_end+1 - t[1] > 32768 then
- if tSize == 1 then
- hash_tables[k] = nil
- else
- local new = {}
- local newSize = 0
- for i = 2, tSize do
- j = t[i]
- if block_end+1 - j <= 32768 then
- newSize = newSize + 1
- new[newSize] = j
- end
- end
- hash_tables[k] = new
- end
- end
- end
- end
- end
+local function Deflate(configs, WriteBits, WriteString, FlushWriter, str,
+ dictionary)
+ local string_table = {}
+ local hash_tables = {}
+ local is_last_block = nil
+ local block_start
+ local block_end
+ local bitlen_written
+ local total_bitlen = FlushWriter(_FLUSH_MODE_NO_FLUSH)
+ local strlen = #str
+ local offset
+
+ local level
+ local strategy
+ if configs then
+ if configs.level then level = configs.level end
+ if configs.strategy then strategy = configs.strategy end
+ end
+
+ if not level then
+ if strlen < 2048 then
+ level = 7
+ elseif strlen > 65536 then
+ level = 3
+ else
+ level = 5
+ end
+ end
+
+ while not is_last_block do
+ if not block_start then
+ block_start = 1
+ block_end = 64 * 1024 - 1
+ offset = 0
+ else
+ block_start = block_end + 1
+ block_end = block_end + 32 * 1024
+ offset = block_start - 32 * 1024 - 1
+ end
+
+ if block_end >= strlen then
+ block_end = strlen
+ is_last_block = true
+ else
+ is_last_block = false
+ end
+
+ local lcodes, lextra_bits, lcodes_counts, dcodes, dextra_bits, dcodes_counts
+
+ local HLIT, HDIST, HCLEN, rle_codes_huffman_bitlens,
+ rle_codes_huffman_codes, rle_deflate_codes, rle_extra_bits,
+ lcodes_huffman_bitlens, lcodes_huffman_codes, dcodes_huffman_bitlens,
+ dcodes_huffman_codes
+
+ local dynamic_block_bitlen
+ local fixed_block_bitlen
+ local store_block_bitlen
+
+ if level ~= 0 then
+
+ -- GetBlockLZ77 needs block_start to block_end+3 to be loaded.
+ LoadStringToTable(str, string_table, block_start, block_end + 3, offset)
+ if block_start == 1 and dictionary then
+ local dict_string_table = dictionary.string_table
+ local dict_strlen = dictionary.strlen
+ for i = 0, (-dict_strlen + 1) < -257 and -257 or (-dict_strlen + 1), -1 do
+ string_table[i] = dict_string_table[dict_strlen + i]
+ end
+ end
+
+ if strategy == "huffman_only" then
+ lcodes = {}
+ LoadStringToTable(str, lcodes, block_start, block_end, block_start - 1)
+ lextra_bits = {}
+ lcodes_counts = {}
+ lcodes[block_end - block_start + 2] = 256 -- end of block
+ for i = 1, block_end - block_start + 2 do
+ local code = lcodes[i]
+ lcodes_counts[code] = (lcodes_counts[code] or 0) + 1
+ end
+ dcodes = {}
+ dextra_bits = {}
+ dcodes_counts = {}
+ else
+ lcodes, lextra_bits, lcodes_counts, dcodes, dextra_bits, dcodes_counts =
+ GetBlockLZ77Result(level, string_table, hash_tables, block_start,
+ block_end, offset, dictionary)
+ end
+
+ -- LuaFormatter off
+ HLIT, HDIST, HCLEN, rle_codes_huffman_bitlens, rle_codes_huffman_codes, rle_deflate_codes,
+ rle_extra_bits, lcodes_huffman_bitlens, lcodes_huffman_codes, dcodes_huffman_bitlens, dcodes_huffman_codes =
+ -- LuaFormatter on
+ GetBlockDynamicHuffmanHeader(lcodes_counts, dcodes_counts)
+ dynamic_block_bitlen = GetDynamicHuffmanBlockSize(lcodes, dcodes, HCLEN,
+ rle_codes_huffman_bitlens,
+ rle_deflate_codes,
+ lcodes_huffman_bitlens,
+ dcodes_huffman_bitlens)
+ fixed_block_bitlen = GetFixedHuffmanBlockSize(lcodes, dcodes)
+ end
+
+ store_block_bitlen = GetStoreBlockSize(block_start, block_end, total_bitlen)
+
+ local min_bitlen = store_block_bitlen
+ min_bitlen = (fixed_block_bitlen and fixed_block_bitlen < min_bitlen) and
+ fixed_block_bitlen or min_bitlen
+ min_bitlen =
+ (dynamic_block_bitlen and dynamic_block_bitlen < min_bitlen) and
+ dynamic_block_bitlen or min_bitlen
+
+ if level == 0 or
+ (strategy ~= "fixed" and strategy ~= "dynamic" and store_block_bitlen ==
+ min_bitlen) then
+ CompressStoreBlock(WriteBits, WriteString, is_last_block, str,
+ block_start, block_end, total_bitlen)
+ total_bitlen = total_bitlen + store_block_bitlen
+ elseif strategy ~= "dynamic" and
+ (strategy == "fixed" or fixed_block_bitlen == min_bitlen) then
+ CompressFixedHuffmanBlock(WriteBits, is_last_block, lcodes, lextra_bits,
+ dcodes, dextra_bits)
+ total_bitlen = total_bitlen + fixed_block_bitlen
+ elseif strategy == "dynamic" or dynamic_block_bitlen == min_bitlen then
+ CompressDynamicHuffmanBlock(WriteBits, is_last_block, lcodes, lextra_bits,
+ dcodes, dextra_bits, HLIT, HDIST, HCLEN,
+ rle_codes_huffman_bitlens,
+ rle_codes_huffman_codes, rle_deflate_codes,
+ rle_extra_bits, lcodes_huffman_bitlens,
+ lcodes_huffman_codes, dcodes_huffman_bitlens,
+ dcodes_huffman_codes)
+ total_bitlen = total_bitlen + dynamic_block_bitlen
+ end
+
+ if is_last_block then
+ bitlen_written = FlushWriter(_FLUSH_MODE_NO_FLUSH)
+ else
+ bitlen_written = FlushWriter(_FLUSH_MODE_MEMORY_CLEANUP)
+ end
+
+ assert(bitlen_written == total_bitlen)
+
+ -- Memory clean up, so memory consumption does not always grow linearly
+ -- , even if input string is > 64K.
+ -- Not a very efficient operation, but this operation won't happen
+ -- when the input data size is less than 64K.
+ if not is_last_block then
+ local j
+ if dictionary and block_start == 1 then
+ j = 0
+ while (string_table[j]) do
+ string_table[j] = nil
+ j = j - 1
+ end
+ end
+ dictionary = nil
+ j = 1
+ for i = block_end - 32767, block_end do
+ string_table[j] = string_table[i - offset]
+ j = j + 1
+ end
+
+ for k, t in pairs(hash_tables) do
+ local tSize = #t
+ if tSize > 0 and block_end + 1 - t[1] > 32768 then
+ if tSize == 1 then
+ hash_tables[k] = nil
+ else
+ local new = {}
+ local newSize = 0
+ for i = 2, tSize do
+ j = t[i]
+ if block_end + 1 - j <= 32768 then
+ newSize = newSize + 1
+ new[newSize] = j
+ end
+ end
+ hash_tables[k] = new
+ end
+ end
+ end
+ end
+ end
end
--- The description to compression configuration table.
@@ -1923,73 +1955,72 @@ end
-- compression block. "dynamic" to only use dynamic block. "huffman_only" to
-- do no LZ77 compression. Only do huffman compression.
-
-- @see LibDeflate:CompressDeflate(str, configs)
-- @see LibDeflate:CompressDeflateWithDict(str, dictionary, configs)
local function CompressDeflateInternal(str, dictionary, configs)
- local WriteBits, WriteString, FlushWriter = CreateWriter()
- Deflate(configs, WriteBits, WriteString, FlushWriter, str, dictionary)
- local total_bitlen, result = FlushWriter(_FLUSH_MODE_OUTPUT)
- local padding_bitlen = (8-total_bitlen%8)%8
- return result, padding_bitlen
+ local WriteBits, WriteString, FlushWriter = CreateWriter()
+ Deflate(configs, WriteBits, WriteString, FlushWriter, str, dictionary)
+ local total_bitlen, result = FlushWriter(_FLUSH_MODE_OUTPUT)
+ local padding_bitlen = (8 - total_bitlen % 8) % 8
+ return result, padding_bitlen
end
-- @see LibDeflate:CompressZlib
-- @see LibDeflate:CompressZlibWithDict
local function CompressZlibInternal(str, dictionary, configs)
- local WriteBits, WriteString, FlushWriter = CreateWriter()
-
- local CM = 8 -- Compression method
- local CINFO = 7 --Window Size = 32K
- local CMF = CINFO*16+CM
- WriteBits(CMF, 8)
-
- local FDIST = dictionary and 1 or 0
- local FLEVEL = 2 -- Default compression
- local FLG = FLEVEL*64+FDIST*32
- local FCHECK = (31-(CMF*256+FLG)%31)
- -- The FCHECK value must be such that CMF and FLG,
- -- when viewed as a 16-bit unsigned integer stored
- -- in MSB order (CMF*256 + FLG), is a multiple of 31.
- FLG = FLG + FCHECK
- WriteBits(FLG, 8)
-
- if FDIST == 1 then
- local adler32 = dictionary.adler32
- local byte0 = adler32 % 256
- adler32 = (adler32 - byte0) / 256
- local byte1 = adler32 % 256
- adler32 = (adler32 - byte1) / 256
- local byte2 = adler32 % 256
- adler32 = (adler32 - byte2) / 256
- local byte3 = adler32 % 256
- WriteBits(byte3, 8)
- WriteBits(byte2, 8)
- WriteBits(byte1, 8)
- WriteBits(byte0, 8)
- end
-
- Deflate(configs, WriteBits, WriteString, FlushWriter, str, dictionary)
- FlushWriter(_FLUSH_MODE_BYTE_BOUNDARY)
-
- local adler32 = LibDeflate:Adler32(str)
-
- -- Most significant byte first
- local byte3 = adler32%256
- adler32 = (adler32 - byte3) / 256
- local byte2 = adler32%256
- adler32 = (adler32 - byte2) / 256
- local byte1 = adler32%256
- adler32 = (adler32 - byte1) / 256
- local byte0 = adler32%256
-
- WriteBits(byte0, 8)
- WriteBits(byte1, 8)
- WriteBits(byte2, 8)
- WriteBits(byte3, 8)
- local total_bitlen, result = FlushWriter(_FLUSH_MODE_OUTPUT)
- local padding_bitlen = (8-total_bitlen%8)%8
- return result, padding_bitlen
+ local WriteBits, WriteString, FlushWriter = CreateWriter()
+
+ local CM = 8 -- Compression method
+ local CINFO = 7 -- Window Size = 32K
+ local CMF = CINFO * 16 + CM
+ WriteBits(CMF, 8)
+
+ local FDIST = dictionary and 1 or 0
+ local FLEVEL = 2 -- Default compression
+ local FLG = FLEVEL * 64 + FDIST * 32
+ local FCHECK = (31 - (CMF * 256 + FLG) % 31)
+ -- The FCHECK value must be such that CMF and FLG,
+ -- when viewed as a 16-bit unsigned integer stored
+ -- in MSB order (CMF*256 + FLG), is a multiple of 31.
+ FLG = FLG + FCHECK
+ WriteBits(FLG, 8)
+
+ if FDIST == 1 then
+ local adler32 = dictionary.adler32
+ local byte0 = adler32 % 256
+ adler32 = (adler32 - byte0) / 256
+ local byte1 = adler32 % 256
+ adler32 = (adler32 - byte1) / 256
+ local byte2 = adler32 % 256
+ adler32 = (adler32 - byte2) / 256
+ local byte3 = adler32 % 256
+ WriteBits(byte3, 8)
+ WriteBits(byte2, 8)
+ WriteBits(byte1, 8)
+ WriteBits(byte0, 8)
+ end
+
+ Deflate(configs, WriteBits, WriteString, FlushWriter, str, dictionary)
+ FlushWriter(_FLUSH_MODE_BYTE_BOUNDARY)
+
+ local adler32 = LibDeflate:Adler32(str)
+
+ -- Most significant byte first
+ local byte3 = adler32 % 256
+ adler32 = (adler32 - byte3) / 256
+ local byte2 = adler32 % 256
+ adler32 = (adler32 - byte2) / 256
+ local byte1 = adler32 % 256
+ adler32 = (adler32 - byte1) / 256
+ local byte0 = adler32 % 256
+
+ WriteBits(byte0, 8)
+ WriteBits(byte1, 8)
+ WriteBits(byte2, 8)
+ WriteBits(byte3, 8)
+ local total_bitlen, result = FlushWriter(_FLUSH_MODE_OUTPUT)
+ local padding_bitlen = (8 - total_bitlen % 8) % 8
+ return result, padding_bitlen
end
--- Compress using the raw deflate format.
@@ -2006,12 +2037,11 @@ end
-- @see compression_configs
-- @see LibDeflate:DecompressDeflate
function LibDeflate:CompressDeflate(str, configs)
- local arg_valid, arg_err = IsValidArguments(str, false, nil, true, configs)
- if not arg_valid then
- error(("Usage: LibDeflate:CompressDeflate(str, configs): "
- ..arg_err), 2)
- end
- return CompressDeflateInternal(str, nil, configs)
+ local arg_valid, arg_err = IsValidArguments(str, false, nil, true, configs)
+ if not arg_valid then
+ error(("Usage: LibDeflate:CompressDeflate(str, configs): " .. arg_err), 2)
+ end
+ return CompressDeflateInternal(str, nil, configs)
end
--- Compress using the raw deflate format with a preset dictionary.
@@ -2031,14 +2061,13 @@ end
-- @see LibDeflate:CreateDictionary
-- @see LibDeflate:DecompressDeflateWithDict
function LibDeflate:CompressDeflateWithDict(str, dictionary, configs)
- local arg_valid, arg_err = IsValidArguments(str, true, dictionary
- , true, configs)
- if not arg_valid then
- error(("Usage: LibDeflate:CompressDeflateWithDict"
- .."(str, dictionary, configs): "
- ..arg_err), 2)
- end
- return CompressDeflateInternal(str, dictionary, configs)
+ local arg_valid, arg_err = IsValidArguments(str, true, dictionary, true,
+ configs)
+ if not arg_valid then
+ error(("Usage: LibDeflate:CompressDeflateWithDict" ..
+ "(str, dictionary, configs): " .. arg_err), 2)
+ end
+ return CompressDeflateInternal(str, dictionary, configs)
end
--- Compress using the zlib format.
@@ -2052,12 +2081,11 @@ end
-- @see compression_configs
-- @see LibDeflate:DecompressZlib
function LibDeflate:CompressZlib(str, configs)
- local arg_valid, arg_err = IsValidArguments(str, false, nil, true, configs)
- if not arg_valid then
- error(("Usage: LibDeflate:CompressZlib(str, configs): "
- ..arg_err), 2)
- end
- return CompressZlibInternal(str, nil, configs)
+ local arg_valid, arg_err = IsValidArguments(str, false, nil, true, configs)
+ if not arg_valid then
+ error(("Usage: LibDeflate:CompressZlib(str, configs): " .. arg_err), 2)
+ end
+ return CompressZlibInternal(str, nil, configs)
end
--- Compress using the zlib format with a preset dictionary.
@@ -2074,14 +2102,13 @@ end
-- @see LibDeflate:CreateDictionary
-- @see LibDeflate:DecompressZlibWithDict
function LibDeflate:CompressZlibWithDict(str, dictionary, configs)
- local arg_valid, arg_err = IsValidArguments(str, true, dictionary
- , true, configs)
- if not arg_valid then
- error(("Usage: LibDeflate:CompressZlibWithDict"
- .."(str, dictionary, configs): "
- ..arg_err), 2)
- end
- return CompressZlibInternal(str, dictionary, configs)
+ local arg_valid, arg_err = IsValidArguments(str, true, dictionary, true,
+ configs)
+ if not arg_valid then
+ error(("Usage: LibDeflate:CompressZlibWithDict" ..
+ "(str, dictionary, configs): " .. arg_err), 2)
+ end
+ return CompressZlibInternal(str, dictionary, configs)
end
--[[ --------------------------------------------------------------------------
@@ -2098,152 +2125,148 @@ end
5. SkipToByteBoundary()
--]]
local function CreateReader(input_string)
- local input = input_string
- local input_strlen = #input_string
- local input_next_byte_pos = 1
- local cache_bitlen = 0
- local cache = 0
-
- -- Read some bits.
- -- To improve speed, this function does not
- -- check if the input has been exhausted.
- -- Use ReaderBitlenLeft() < 0 to check it.
- -- @param bitlen the number of bits to read
- -- @return the data is read.
- local function ReadBits(bitlen)
- local rshift_mask = _pow2[bitlen]
- local code
- if bitlen <= cache_bitlen then
- code = cache % rshift_mask
- cache = (cache - code) / rshift_mask
- cache_bitlen = cache_bitlen - bitlen
- else -- Whether input has been exhausted is not checked.
- local lshift_mask = _pow2[cache_bitlen]
- local byte1, byte2, byte3, byte4 = string_byte(input
- , input_next_byte_pos, input_next_byte_pos+3)
- -- This requires lua number to be at least double ()
- cache = cache + ((byte1 or 0)+(byte2 or 0)*256
- + (byte3 or 0)*65536+(byte4 or 0)*16777216)*lshift_mask
- input_next_byte_pos = input_next_byte_pos + 4
- cache_bitlen = cache_bitlen + 32 - bitlen
- code = cache % rshift_mask
- cache = (cache - code) / rshift_mask
- end
- return code
- end
-
- -- Read some bytes from the reader.
- -- Assume reader is on the byte boundary.
- -- @param bytelen The number of bytes to be read.
- -- @param buffer The byte read will be stored into this buffer.
- -- @param buffer_size The buffer will be modified starting from
- -- buffer[buffer_size+1], ending at buffer[buffer_size+bytelen-1]
- -- @return the new buffer_size
- local function ReadBytes(bytelen, buffer, buffer_size)
- assert(cache_bitlen % 8 == 0)
-
- local byte_from_cache = (cache_bitlen/8 < bytelen)
- and (cache_bitlen/8) or bytelen
- for _=1, byte_from_cache do
- local byte = cache % 256
- buffer_size = buffer_size + 1
- buffer[buffer_size] = string_char(byte)
- cache = (cache - byte) / 256
- end
- cache_bitlen = cache_bitlen - byte_from_cache*8
- bytelen = bytelen - byte_from_cache
- if (input_strlen - input_next_byte_pos - bytelen + 1) * 8
- + cache_bitlen < 0 then
- return -1 -- out of input
- end
- for i=input_next_byte_pos, input_next_byte_pos+bytelen-1 do
- buffer_size = buffer_size + 1
- buffer[buffer_size] = string_sub(input, i, i)
- end
-
- input_next_byte_pos = input_next_byte_pos + bytelen
- return buffer_size
- end
-
- -- Decode huffman code
- -- To improve speed, this function does not check
- -- if the input has been exhausted.
- -- Use ReaderBitlenLeft() < 0 to check it.
- -- Credits for Mark Adler. This code is from puff:Decode()
- -- @see puff:Decode(...)
- -- @param huffman_bitlen_count
- -- @param huffman_symbol
- -- @param min_bitlen The minimum huffman bit length of all symbols
- -- @return The decoded deflate code.
- -- Negative value is returned if decoding fails.
- local function Decode(huffman_bitlen_counts, huffman_symbols, min_bitlen)
- local code = 0
- local first = 0
- local index = 0
- local count
- if min_bitlen > 0 then
- if cache_bitlen < 15 and input then
- local lshift_mask = _pow2[cache_bitlen]
- local byte1, byte2, byte3, byte4 =
- string_byte(input, input_next_byte_pos
- , input_next_byte_pos+3)
- -- This requires lua number to be at least double ()
- cache = cache + ((byte1 or 0)+(byte2 or 0)*256
- +(byte3 or 0)*65536+(byte4 or 0)*16777216)*lshift_mask
- input_next_byte_pos = input_next_byte_pos + 4
- cache_bitlen = cache_bitlen + 32
- end
-
- local rshift_mask = _pow2[min_bitlen]
- cache_bitlen = cache_bitlen - min_bitlen
- code = cache % rshift_mask
- cache = (cache - code) / rshift_mask
- -- Reverse the bits
- code = _reverse_bits_tbl[min_bitlen][code]
-
- count = huffman_bitlen_counts[min_bitlen]
- if code < count then
- return huffman_symbols[code]
- end
- index = count
- first = count * 2
- code = code * 2
- end
-
- for bitlen = min_bitlen+1, 15 do
- local bit
- bit = cache % 2
- cache = (cache - bit) / 2
- cache_bitlen = cache_bitlen - 1
-
- code = (bit==1) and (code + 1 - code % 2) or code
- count = huffman_bitlen_counts[bitlen] or 0
- local diff = code - first
- if diff < count then
- return huffman_symbols[index + diff]
- end
- index = index + count
- first = first + count
- first = first * 2
- code = code * 2
- end
- -- invalid literal/length or distance code
- -- in fixed or dynamic block (run out of code)
- return -10
- end
-
- local function ReaderBitlenLeft()
- return (input_strlen - input_next_byte_pos + 1) * 8 + cache_bitlen
- end
-
- local function SkipToByteBoundary()
- local skipped_bitlen = cache_bitlen%8
- local rshift_mask = _pow2[skipped_bitlen]
- cache_bitlen = cache_bitlen - skipped_bitlen
- cache = (cache - cache % rshift_mask) / rshift_mask
- end
-
- return ReadBits, ReadBytes, Decode, ReaderBitlenLeft, SkipToByteBoundary
+ local input = input_string
+ local input_strlen = #input_string
+ local input_next_byte_pos = 1
+ local cache_bitlen = 0
+ local cache = 0
+
+ -- Read some bits.
+ -- To improve speed, this function does not
+ -- check if the input has been exhausted.
+ -- Use ReaderBitlenLeft() < 0 to check it.
+ -- @param bitlen the number of bits to read
+ -- @return the data is read.
+ local function ReadBits(bitlen)
+ local rshift_mask = _pow2[bitlen]
+ local code
+ if bitlen <= cache_bitlen then
+ code = cache % rshift_mask
+ cache = (cache - code) / rshift_mask
+ cache_bitlen = cache_bitlen - bitlen
+ else -- Whether input has been exhausted is not checked.
+ local lshift_mask = _pow2[cache_bitlen]
+ local byte1, byte2, byte3, byte4 =
+ string_byte(input, input_next_byte_pos, input_next_byte_pos + 3)
+ -- This requires lua number to be at least double ()
+ cache = cache +
+ ((byte1 or 0) + (byte2 or 0) * 256 + (byte3 or 0) * 65536 +
+ (byte4 or 0) * 16777216) * lshift_mask
+ input_next_byte_pos = input_next_byte_pos + 4
+ cache_bitlen = cache_bitlen + 32 - bitlen
+ code = cache % rshift_mask
+ cache = (cache - code) / rshift_mask
+ end
+ return code
+ end
+
+ -- Read some bytes from the reader.
+ -- Assume reader is on the byte boundary.
+ -- @param bytelen The number of bytes to be read.
+ -- @param buffer The byte read will be stored into this buffer.
+ -- @param buffer_size The buffer will be modified starting from
+ -- buffer[buffer_size+1], ending at buffer[buffer_size+bytelen-1]
+ -- @return the new buffer_size
+ local function ReadBytes(bytelen, buffer, buffer_size)
+ assert(cache_bitlen % 8 == 0)
+
+ local byte_from_cache =
+ (cache_bitlen / 8 < bytelen) and (cache_bitlen / 8) or bytelen
+ for _ = 1, byte_from_cache do
+ local byte = cache % 256
+ buffer_size = buffer_size + 1
+ buffer[buffer_size] = string_char(byte)
+ cache = (cache - byte) / 256
+ end
+ cache_bitlen = cache_bitlen - byte_from_cache * 8
+ bytelen = bytelen - byte_from_cache
+ if (input_strlen - input_next_byte_pos - bytelen + 1) * 8 + cache_bitlen < 0 then
+ return -1 -- out of input
+ end
+ for i = input_next_byte_pos, input_next_byte_pos + bytelen - 1 do
+ buffer_size = buffer_size + 1
+ buffer[buffer_size] = string_sub(input, i, i)
+ end
+
+ input_next_byte_pos = input_next_byte_pos + bytelen
+ return buffer_size
+ end
+
+ -- Decode huffman code
+ -- To improve speed, this function does not check
+ -- if the input has been exhausted.
+ -- Use ReaderBitlenLeft() < 0 to check it.
+ -- Credits for Mark Adler. This code is from puff:Decode()
+ -- @see puff:Decode(...)
+ -- @param huffman_bitlen_count
+ -- @param huffman_symbol
+ -- @param min_bitlen The minimum huffman bit length of all symbols
+ -- @return The decoded deflate code.
+ -- Negative value is returned if decoding fails.
+ local function Decode(huffman_bitlen_counts, huffman_symbols, min_bitlen)
+ local code = 0
+ local first = 0
+ local index = 0
+ local count
+ if min_bitlen > 0 then
+ if cache_bitlen < 15 and input then
+ local lshift_mask = _pow2[cache_bitlen]
+ local byte1, byte2, byte3, byte4 =
+ string_byte(input, input_next_byte_pos, input_next_byte_pos + 3)
+ -- This requires lua number to be at least double ()
+ cache = cache +
+ ((byte1 or 0) + (byte2 or 0) * 256 + (byte3 or 0) * 65536 +
+ (byte4 or 0) * 16777216) * lshift_mask
+ input_next_byte_pos = input_next_byte_pos + 4
+ cache_bitlen = cache_bitlen + 32
+ end
+
+ local rshift_mask = _pow2[min_bitlen]
+ cache_bitlen = cache_bitlen - min_bitlen
+ code = cache % rshift_mask
+ cache = (cache - code) / rshift_mask
+ -- Reverse the bits
+ code = _reverse_bits_tbl[min_bitlen][code]
+
+ count = huffman_bitlen_counts[min_bitlen]
+ if code < count then return huffman_symbols[code] end
+ index = count
+ first = count * 2
+ code = code * 2
+ end
+
+ for bitlen = min_bitlen + 1, 15 do
+ local bit
+ bit = cache % 2
+ cache = (cache - bit) / 2
+ cache_bitlen = cache_bitlen - 1
+
+ code = (bit == 1) and (code + 1 - code % 2) or code
+ count = huffman_bitlen_counts[bitlen] or 0
+ local diff = code - first
+ if diff < count then return huffman_symbols[index + diff] end
+ index = index + count
+ first = first + count
+ first = first * 2
+ code = code * 2
+ end
+ -- invalid literal/length or distance code
+ -- in fixed or dynamic block (run out of code)
+ return -10
+ end
+
+ local function ReaderBitlenLeft()
+ return (input_strlen - input_next_byte_pos + 1) * 8 + cache_bitlen
+ end
+
+ local function SkipToByteBoundary()
+ local skipped_bitlen = cache_bitlen % 8
+ local rshift_mask = _pow2[skipped_bitlen]
+ cache_bitlen = cache_bitlen - skipped_bitlen
+ cache = (cache - cache % rshift_mask) / rshift_mask
+ end
+
+ return ReadBits, ReadBytes, Decode, ReaderBitlenLeft, SkipToByteBoundary
end
-- Create a deflate state, so I can pass in less arguments to functions.
@@ -2252,21 +2275,20 @@ end
-- This dictionary should be produced by LibDeflate:CreateDictionary(str)
-- @return The decomrpess state.
local function CreateDecompressState(str, dictionary)
- local ReadBits, ReadBytes, Decode, ReaderBitlenLeft
- , SkipToByteBoundary = CreateReader(str)
- local state =
- {
- ReadBits = ReadBits,
- ReadBytes = ReadBytes,
- Decode = Decode,
- ReaderBitlenLeft = ReaderBitlenLeft,
- SkipToByteBoundary = SkipToByteBoundary,
- buffer_size = 0,
- buffer = {},
- result_buffer = {},
- dictionary = dictionary,
- }
- return state
+ local ReadBits, ReadBytes, Decode, ReaderBitlenLeft, SkipToByteBoundary =
+ CreateReader(str)
+ local state = {
+ ReadBits = ReadBits,
+ ReadBytes = ReadBytes,
+ Decode = Decode,
+ ReaderBitlenLeft = ReaderBitlenLeft,
+ SkipToByteBoundary = SkipToByteBoundary,
+ buffer_size = 0,
+ buffer = {},
+ result_buffer = {},
+ dictionary = dictionary
+ }
+ return state
end
-- Get the stuffs needed to decode huffman codes
@@ -2279,47 +2301,46 @@ end
-- @return A table to convert huffman codes to deflate codes.
-- @return The minimum huffman bit length.
local function GetHuffmanForDecode(huffman_bitlens, max_symbol, max_bitlen)
- local huffman_bitlen_counts = {}
- local min_bitlen = max_bitlen
- for symbol = 0, max_symbol do
- local bitlen = huffman_bitlens[symbol] or 0
- min_bitlen = (bitlen > 0 and bitlen < min_bitlen)
- and bitlen or min_bitlen
- huffman_bitlen_counts[bitlen] = (huffman_bitlen_counts[bitlen] or 0)+1
- end
-
- if huffman_bitlen_counts[0] == max_symbol+1 then -- No Codes
- return 0, huffman_bitlen_counts, {}, 0 -- Complete, but decode will fail
- end
-
- local left = 1
- for len = 1, max_bitlen do
- left = left * 2
- left = left - (huffman_bitlen_counts[len] or 0)
- if left < 0 then
- return left -- Over-subscribed, return negative
- end
- end
-
- -- Generate offsets info symbol table for each length for sorting
- local offsets = {}
- offsets[1] = 0
- for len = 1, max_bitlen-1 do
- offsets[len + 1] = offsets[len] + (huffman_bitlen_counts[len] or 0)
- end
-
- local huffman_symbols = {}
- for symbol = 0, max_symbol do
- local bitlen = huffman_bitlens[symbol] or 0
- if bitlen ~= 0 then
- local offset = offsets[bitlen]
- huffman_symbols[offset] = symbol
- offsets[bitlen] = offsets[bitlen] + 1
- end
- end
-
- -- Return zero for complete set, positive for incomplete set.
- return left, huffman_bitlen_counts, huffman_symbols, min_bitlen
+ local huffman_bitlen_counts = {}
+ local min_bitlen = max_bitlen
+ for symbol = 0, max_symbol do
+ local bitlen = huffman_bitlens[symbol] or 0
+ min_bitlen = (bitlen > 0 and bitlen < min_bitlen) and bitlen or min_bitlen
+ huffman_bitlen_counts[bitlen] = (huffman_bitlen_counts[bitlen] or 0) + 1
+ end
+
+ if huffman_bitlen_counts[0] == max_symbol + 1 then -- No Codes
+ return 0, huffman_bitlen_counts, {}, 0 -- Complete, but decode will fail
+ end
+
+ local left = 1
+ for len = 1, max_bitlen do
+ left = left * 2
+ left = left - (huffman_bitlen_counts[len] or 0)
+ if left < 0 then
+ return left -- Over-subscribed, return negative
+ end
+ end
+
+ -- Generate offsets info symbol table for each length for sorting
+ local offsets = {}
+ offsets[1] = 0
+ for len = 1, max_bitlen - 1 do
+ offsets[len + 1] = offsets[len] + (huffman_bitlen_counts[len] or 0)
+ end
+
+ local huffman_symbols = {}
+ for symbol = 0, max_symbol do
+ local bitlen = huffman_bitlens[symbol] or 0
+ if bitlen ~= 0 then
+ local offset = offsets[bitlen]
+ huffman_symbols[offset] = symbol
+ offsets[bitlen] = offsets[bitlen] + 1
+ end
+ end
+
+ -- Return zero for complete set, positive for incomplete set.
+ return left, huffman_bitlen_counts, huffman_symbols, min_bitlen
end
-- Decode a fixed or dynamic huffman blocks, excluding last block identifier
@@ -2329,391 +2350,380 @@ end
-- @see CreateDecompressState
-- @param ... Read the source code
-- @return 0 on success, other value on failure.
-local function DecodeUntilEndOfBlock(state, lcodes_huffman_bitlens
- , lcodes_huffman_symbols, lcodes_huffman_min_bitlen
- , dcodes_huffman_bitlens, dcodes_huffman_symbols
- , dcodes_huffman_min_bitlen)
- local buffer, buffer_size, ReadBits, Decode, ReaderBitlenLeft
- , result_buffer =
- state.buffer, state.buffer_size, state.ReadBits, state.Decode
- , state.ReaderBitlenLeft, state.result_buffer
- local dictionary = state.dictionary
- local dict_string_table
- local dict_strlen
-
- local buffer_end = 1
- if dictionary and not buffer[0] then
- -- If there is a dictionary, copy the last 258 bytes into
- -- the string_table to make the copy in the main loop quicker.
- -- This is done only once per decompression.
- dict_string_table = dictionary.string_table
- dict_strlen = dictionary.strlen
- buffer_end = -dict_strlen + 1
- for i=0, (-dict_strlen+1)<-257 and -257 or (-dict_strlen+1), -1 do
- buffer[i] = _byte_to_char[dict_string_table[dict_strlen+i]]
- end
- end
-
- repeat
- local symbol = Decode(lcodes_huffman_bitlens
- , lcodes_huffman_symbols, lcodes_huffman_min_bitlen)
- if symbol < 0 or symbol > 285 then
- -- invalid literal/length or distance code in fixed or dynamic block
- return -10
- elseif symbol < 256 then -- Literal
- buffer_size = buffer_size + 1
- buffer[buffer_size] = _byte_to_char[symbol]
- elseif symbol > 256 then -- Length code
- symbol = symbol - 256
- local bitlen = _literal_deflate_code_to_base_len[symbol]
- bitlen = (symbol >= 8)
- and (bitlen
- + ReadBits(_literal_deflate_code_to_extra_bitlen[symbol]))
- or bitlen
- symbol = Decode(dcodes_huffman_bitlens, dcodes_huffman_symbols
- , dcodes_huffman_min_bitlen)
- if symbol < 0 or symbol > 29 then
- -- invalid literal/length or distance code in fixed or dynamic block
- return -10
- end
- local dist = _dist_deflate_code_to_base_dist[symbol]
- dist = (dist > 4) and (dist
- + ReadBits(_dist_deflate_code_to_extra_bitlen[symbol])) or dist
-
- local char_buffer_index = buffer_size-dist+1
- if char_buffer_index < buffer_end then
- -- distance is too far back in fixed or dynamic block
- return -11
- end
- if char_buffer_index >= -257 then
- for _=1, bitlen do
- buffer_size = buffer_size + 1
- buffer[buffer_size] = buffer[char_buffer_index]
- char_buffer_index = char_buffer_index + 1
- end
- else
- char_buffer_index = dict_strlen + char_buffer_index
- for _=1, bitlen do
- buffer_size = buffer_size + 1
- buffer[buffer_size] =
- _byte_to_char[dict_string_table[char_buffer_index]]
- char_buffer_index = char_buffer_index + 1
- end
- end
- end
-
- if ReaderBitlenLeft() < 0 then
- return 2 -- available inflate data did not terminate
- end
-
- if buffer_size >= 65536 then
- result_buffer[#result_buffer+1] =
- table_concat(buffer, "", 1, 32768)
- for i=32769, buffer_size do
- buffer[i-32768] = buffer[i]
- end
- buffer_size = buffer_size - 32768
- buffer[buffer_size+1] = nil
- -- NOTE: buffer[32769..end] and buffer[-257..0] are not cleared.
- -- This is why "buffer_size" variable is needed.
- end
- until symbol == 256
-
- state.buffer_size = buffer_size
-
- return 0
+local function DecodeUntilEndOfBlock(state, lcodes_huffman_bitlens,
+ lcodes_huffman_symbols,
+ lcodes_huffman_min_bitlen,
+ dcodes_huffman_bitlens,
+ dcodes_huffman_symbols,
+ dcodes_huffman_min_bitlen)
+ local buffer, buffer_size, ReadBits, Decode, ReaderBitlenLeft, result_buffer =
+ state.buffer, state.buffer_size, state.ReadBits, state.Decode,
+ state.ReaderBitlenLeft, state.result_buffer
+ local dictionary = state.dictionary
+ local dict_string_table
+ local dict_strlen
+
+ local buffer_end = 1
+ if dictionary and not buffer[0] then
+ -- If there is a dictionary, copy the last 258 bytes into
+ -- the string_table to make the copy in the main loop quicker.
+ -- This is done only once per decompression.
+ dict_string_table = dictionary.string_table
+ dict_strlen = dictionary.strlen
+ buffer_end = -dict_strlen + 1
+ for i = 0, (-dict_strlen + 1) < -257 and -257 or (-dict_strlen + 1), -1 do
+ buffer[i] = _byte_to_char[dict_string_table[dict_strlen + i]]
+ end
+ end
+
+ repeat
+ local symbol = Decode(lcodes_huffman_bitlens, lcodes_huffman_symbols,
+ lcodes_huffman_min_bitlen)
+ if symbol < 0 or symbol > 285 then
+ -- invalid literal/length or distance code in fixed or dynamic block
+ return -10
+ elseif symbol < 256 then -- Literal
+ buffer_size = buffer_size + 1
+ buffer[buffer_size] = _byte_to_char[symbol]
+ elseif symbol > 256 then -- Length code
+ symbol = symbol - 256
+ local bitlen = _literal_deflate_code_to_base_len[symbol]
+ bitlen = (symbol >= 8) and
+ (bitlen +
+ ReadBits(_literal_deflate_code_to_extra_bitlen[symbol])) or
+ bitlen
+ symbol = Decode(dcodes_huffman_bitlens, dcodes_huffman_symbols,
+ dcodes_huffman_min_bitlen)
+ if symbol < 0 or symbol > 29 then
+ -- invalid literal/length or distance code in fixed or dynamic block
+ return -10
+ end
+ local dist = _dist_deflate_code_to_base_dist[symbol]
+ dist = (dist > 4) and
+ (dist + ReadBits(_dist_deflate_code_to_extra_bitlen[symbol])) or
+ dist
+
+ local char_buffer_index = buffer_size - dist + 1
+ if char_buffer_index < buffer_end then
+ -- distance is too far back in fixed or dynamic block
+ return -11
+ end
+ if char_buffer_index >= -257 then
+ for _ = 1, bitlen do
+ buffer_size = buffer_size + 1
+ buffer[buffer_size] = buffer[char_buffer_index]
+ char_buffer_index = char_buffer_index + 1
+ end
+ else
+ char_buffer_index = dict_strlen + char_buffer_index
+ for _ = 1, bitlen do
+ buffer_size = buffer_size + 1
+ buffer[buffer_size] =
+ _byte_to_char[dict_string_table[char_buffer_index]]
+ char_buffer_index = char_buffer_index + 1
+ end
+ end
+ end
+
+ if ReaderBitlenLeft() < 0 then
+ return 2 -- available inflate data did not terminate
+ end
+
+ if buffer_size >= 65536 then
+ result_buffer[#result_buffer + 1] = table_concat(buffer, "", 1, 32768)
+ for i = 32769, buffer_size do buffer[i - 32768] = buffer[i] end
+ buffer_size = buffer_size - 32768
+ buffer[buffer_size + 1] = nil
+ -- NOTE: buffer[32769..end] and buffer[-257..0] are not cleared.
+ -- This is why "buffer_size" variable is needed.
+ end
+ until symbol == 256
+
+ state.buffer_size = buffer_size
+
+ return 0
end
-- Decompress a store block
-- @param state decompression state that will be modified by this function.
-- @return 0 if succeeds, other value if fails.
local function DecompressStoreBlock(state)
- local buffer, buffer_size, ReadBits, ReadBytes, ReaderBitlenLeft
- , SkipToByteBoundary, result_buffer =
- state.buffer, state.buffer_size, state.ReadBits, state.ReadBytes
- , state.ReaderBitlenLeft, state.SkipToByteBoundary, state.result_buffer
-
- SkipToByteBoundary()
- local bytelen = ReadBits(16)
- if ReaderBitlenLeft() < 0 then
- return 2 -- available inflate data did not terminate
- end
- local bytelenComp = ReadBits(16)
- if ReaderBitlenLeft() < 0 then
- return 2 -- available inflate data did not terminate
- end
-
- if bytelen % 256 + bytelenComp % 256 ~= 255 then
- return -2 -- Not one's complement
- end
- if (bytelen-bytelen % 256)/256
- + (bytelenComp-bytelenComp % 256)/256 ~= 255 then
- return -2 -- Not one's complement
- end
-
- -- Note that ReadBytes will skip to the next byte boundary first.
- buffer_size = ReadBytes(bytelen, buffer, buffer_size)
- if buffer_size < 0 then
- return 2 -- available inflate data did not terminate
- end
-
- -- memory clean up when there are enough bytes in the buffer.
- if buffer_size >= 65536 then
- result_buffer[#result_buffer+1] = table_concat(buffer, "", 1, 32768)
- for i=32769, buffer_size do
- buffer[i-32768] = buffer[i]
- end
- buffer_size = buffer_size - 32768
- buffer[buffer_size+1] = nil
- end
- state.buffer_size = buffer_size
- return 0
+ local buffer, buffer_size, ReadBits, ReadBytes, ReaderBitlenLeft,
+ SkipToByteBoundary, result_buffer = state.buffer, state.buffer_size,
+ state.ReadBits, state.ReadBytes,
+ state.ReaderBitlenLeft,
+ state.SkipToByteBoundary,
+ state.result_buffer
+
+ SkipToByteBoundary()
+ local bytelen = ReadBits(16)
+ if ReaderBitlenLeft() < 0 then
+ return 2 -- available inflate data did not terminate
+ end
+ local bytelenComp = ReadBits(16)
+ if ReaderBitlenLeft() < 0 then
+ return 2 -- available inflate data did not terminate
+ end
+
+ if bytelen % 256 + bytelenComp % 256 ~= 255 then
+ return -2 -- Not one's complement
+ end
+ if (bytelen - bytelen % 256) / 256 + (bytelenComp - bytelenComp % 256) / 256 ~=
+ 255 then
+ return -2 -- Not one's complement
+ end
+
+ -- Note that ReadBytes will skip to the next byte boundary first.
+ buffer_size = ReadBytes(bytelen, buffer, buffer_size)
+ if buffer_size < 0 then
+ return 2 -- available inflate data did not terminate
+ end
+
+ -- memory clean up when there are enough bytes in the buffer.
+ if buffer_size >= 65536 then
+ result_buffer[#result_buffer + 1] = table_concat(buffer, "", 1, 32768)
+ for i = 32769, buffer_size do buffer[i - 32768] = buffer[i] end
+ buffer_size = buffer_size - 32768
+ buffer[buffer_size + 1] = nil
+ end
+ state.buffer_size = buffer_size
+ return 0
end
-- Decompress a fixed block
-- @param state decompression state that will be modified by this function.
-- @return 0 if succeeds other value if fails.
local function DecompressFixBlock(state)
- return DecodeUntilEndOfBlock(state
- , _fix_block_literal_huffman_bitlen_count
- , _fix_block_literal_huffman_to_deflate_code, 7
- , _fix_block_dist_huffman_bitlen_count
- , _fix_block_dist_huffman_to_deflate_code, 5)
+ return DecodeUntilEndOfBlock(state, _fix_block_literal_huffman_bitlen_count,
+ _fix_block_literal_huffman_to_deflate_code, 7,
+ _fix_block_dist_huffman_bitlen_count,
+ _fix_block_dist_huffman_to_deflate_code, 5)
end
-- Decompress a dynamic block
-- @param state decompression state that will be modified by this function.
-- @return 0 if success, other value if fails.
local function DecompressDynamicBlock(state)
- local ReadBits, Decode = state.ReadBits, state.Decode
- local nlen = ReadBits(5) + 257
- local ndist = ReadBits(5) + 1
- local ncode = ReadBits(4) + 4
- if nlen > 286 or ndist > 30 then
- -- dynamic block code description: too many length or distance codes
- return -3
- end
-
- local rle_codes_huffman_bitlens = {}
-
- for i = 1, ncode do
- rle_codes_huffman_bitlens[_rle_codes_huffman_bitlen_order[i]] =
- ReadBits(3)
- end
-
- local rle_codes_err, rle_codes_huffman_bitlen_counts,
- rle_codes_huffman_symbols, rle_codes_huffman_min_bitlen =
- GetHuffmanForDecode(rle_codes_huffman_bitlens, 18, 7)
- if rle_codes_err ~= 0 then -- Require complete code set here
- -- dynamic block code description: code lengths codes incomplete
- return -4
- end
-
- local lcodes_huffman_bitlens = {}
- local dcodes_huffman_bitlens = {}
- -- Read length/literal and distance code length tables
- local index = 0
- while index < nlen + ndist do
- local symbol -- Decoded value
- local bitlen -- Last length to repeat
-
- symbol = Decode(rle_codes_huffman_bitlen_counts
- , rle_codes_huffman_symbols, rle_codes_huffman_min_bitlen)
-
- if symbol < 0 then
- return symbol -- Invalid symbol
- elseif symbol < 16 then
- if index < nlen then
- lcodes_huffman_bitlens[index] = symbol
- else
- dcodes_huffman_bitlens[index-nlen] = symbol
- end
- index = index + 1
- else
- bitlen = 0
- if symbol == 16 then
- if index == 0 then
- -- dynamic block code description: repeat lengths
- -- with no first length
- return -5
- end
- if index-1 < nlen then
- bitlen = lcodes_huffman_bitlens[index-1]
- else
- bitlen = dcodes_huffman_bitlens[index-nlen-1]
- end
- symbol = 3 + ReadBits(2)
- elseif symbol == 17 then -- Repeat zero 3..10 times
- symbol = 3 + ReadBits(3)
- else -- == 18, repeat zero 11.138 times
- symbol = 11 + ReadBits(7)
- end
- if index + symbol > nlen + ndist then
- -- dynamic block code description:
- -- repeat more than specified lengths
- return -6
- end
- while symbol > 0 do -- Repeat last or zero symbol times
- symbol = symbol - 1
- if index < nlen then
- lcodes_huffman_bitlens[index] = bitlen
- else
- dcodes_huffman_bitlens[index-nlen] = bitlen
- end
- index = index + 1
- end
- end
- end
-
- if (lcodes_huffman_bitlens[256] or 0) == 0 then
- -- dynamic block code description: missing end-of-block code
- return -9
- end
-
- local lcodes_err, lcodes_huffman_bitlen_counts
- , lcodes_huffman_symbols, lcodes_huffman_min_bitlen =
- GetHuffmanForDecode(lcodes_huffman_bitlens, nlen-1, 15)
- --dynamic block code description: invalid literal/length code lengths,
- -- Incomplete code ok only for single length 1 code
- if (lcodes_err ~=0 and (lcodes_err < 0
- or nlen ~= (lcodes_huffman_bitlen_counts[0] or 0)
- +(lcodes_huffman_bitlen_counts[1] or 0))) then
- return -7
- end
-
- local dcodes_err, dcodes_huffman_bitlen_counts
- , dcodes_huffman_symbols, dcodes_huffman_min_bitlen =
- GetHuffmanForDecode(dcodes_huffman_bitlens, ndist-1, 15)
- -- dynamic block code description: invalid distance code lengths,
- -- Incomplete code ok only for single length 1 code
- if (dcodes_err ~=0 and (dcodes_err < 0
- or ndist ~= (dcodes_huffman_bitlen_counts[0] or 0)
- + (dcodes_huffman_bitlen_counts[1] or 0))) then
- return -8
- end
-
- -- Build buffman table for literal/length codes
- return DecodeUntilEndOfBlock(state, lcodes_huffman_bitlen_counts
- , lcodes_huffman_symbols, lcodes_huffman_min_bitlen
- , dcodes_huffman_bitlen_counts, dcodes_huffman_symbols
- , dcodes_huffman_min_bitlen)
+ local ReadBits, Decode = state.ReadBits, state.Decode
+ local nlen = ReadBits(5) + 257
+ local ndist = ReadBits(5) + 1
+ local ncode = ReadBits(4) + 4
+ if nlen > 286 or ndist > 30 then
+ -- dynamic block code description: too many length or distance codes
+ return -3
+ end
+
+ local rle_codes_huffman_bitlens = {}
+
+ for i = 1, ncode do
+ rle_codes_huffman_bitlens[_rle_codes_huffman_bitlen_order[i]] = ReadBits(3)
+ end
+
+ local rle_codes_err, rle_codes_huffman_bitlen_counts,
+ rle_codes_huffman_symbols, rle_codes_huffman_min_bitlen =
+ GetHuffmanForDecode(rle_codes_huffman_bitlens, 18, 7)
+ if rle_codes_err ~= 0 then -- Require complete code set here
+ -- dynamic block code description: code lengths codes incomplete
+ return -4
+ end
+
+ local lcodes_huffman_bitlens = {}
+ local dcodes_huffman_bitlens = {}
+ -- Read length/literal and distance code length tables
+ local index = 0
+ while index < nlen + ndist do
+ local symbol -- Decoded value
+ local bitlen -- Last length to repeat
+
+ symbol = Decode(rle_codes_huffman_bitlen_counts, rle_codes_huffman_symbols,
+ rle_codes_huffman_min_bitlen)
+
+ if symbol < 0 then
+ return symbol -- Invalid symbol
+ elseif symbol < 16 then
+ if index < nlen then
+ lcodes_huffman_bitlens[index] = symbol
+ else
+ dcodes_huffman_bitlens[index - nlen] = symbol
+ end
+ index = index + 1
+ else
+ bitlen = 0
+ if symbol == 16 then
+ if index == 0 then
+ -- dynamic block code description: repeat lengths
+ -- with no first length
+ return -5
+ end
+ if index - 1 < nlen then
+ bitlen = lcodes_huffman_bitlens[index - 1]
+ else
+ bitlen = dcodes_huffman_bitlens[index - nlen - 1]
+ end
+ symbol = 3 + ReadBits(2)
+ elseif symbol == 17 then -- Repeat zero 3..10 times
+ symbol = 3 + ReadBits(3)
+ else -- == 18, repeat zero 11.138 times
+ symbol = 11 + ReadBits(7)
+ end
+ if index + symbol > nlen + ndist then
+ -- dynamic block code description:
+ -- repeat more than specified lengths
+ return -6
+ end
+ while symbol > 0 do -- Repeat last or zero symbol times
+ symbol = symbol - 1
+ if index < nlen then
+ lcodes_huffman_bitlens[index] = bitlen
+ else
+ dcodes_huffman_bitlens[index - nlen] = bitlen
+ end
+ index = index + 1
+ end
+ end
+ end
+
+ if (lcodes_huffman_bitlens[256] or 0) == 0 then
+ -- dynamic block code description: missing end-of-block code
+ return -9
+ end
+
+ local lcodes_err, lcodes_huffman_bitlen_counts, lcodes_huffman_symbols,
+ lcodes_huffman_min_bitlen = GetHuffmanForDecode(lcodes_huffman_bitlens,
+ nlen - 1, 15)
+ -- dynamic block code description: invalid literal/length code lengths,
+ -- Incomplete code ok only for single length 1 code
+ if (lcodes_err ~= 0 and
+ (lcodes_err < 0 or nlen ~= (lcodes_huffman_bitlen_counts[0] or 0) +
+ (lcodes_huffman_bitlen_counts[1] or 0))) then return -7 end
+
+ local dcodes_err, dcodes_huffman_bitlen_counts, dcodes_huffman_symbols,
+ dcodes_huffman_min_bitlen = GetHuffmanForDecode(dcodes_huffman_bitlens,
+ ndist - 1, 15)
+ -- dynamic block code description: invalid distance code lengths,
+ -- Incomplete code ok only for single length 1 code
+ if (dcodes_err ~= 0 and
+ (dcodes_err < 0 or ndist ~= (dcodes_huffman_bitlen_counts[0] or 0) +
+ (dcodes_huffman_bitlen_counts[1] or 0))) then return -8 end
+
+ -- Build buffman table for literal/length codes
+ return DecodeUntilEndOfBlock(state, lcodes_huffman_bitlen_counts,
+ lcodes_huffman_symbols,
+ lcodes_huffman_min_bitlen,
+ dcodes_huffman_bitlen_counts,
+ dcodes_huffman_symbols, dcodes_huffman_min_bitlen)
end
-- Decompress a deflate stream
-- @param state: a decompression state
-- @return the decompressed string if succeeds. nil if fails.
local function Inflate(state)
- local ReadBits = state.ReadBits
-
- local is_last_block
- while not is_last_block do
- is_last_block = (ReadBits(1) == 1)
- local block_type = ReadBits(2)
- local status
- if block_type == 0 then
- status = DecompressStoreBlock(state)
- elseif block_type == 1 then
- status = DecompressFixBlock(state)
- elseif block_type == 2 then
- status = DecompressDynamicBlock(state)
- else
- return nil, -1 -- invalid block type (type == 3)
- end
- if status ~= 0 then
- return nil, status
- end
- end
-
- state.result_buffer[#state.result_buffer+1] =
- table_concat(state.buffer, "", 1, state.buffer_size)
- local result = table_concat(state.result_buffer)
- return result
+ local ReadBits = state.ReadBits
+
+ local is_last_block
+ while not is_last_block do
+ is_last_block = (ReadBits(1) == 1)
+ local block_type = ReadBits(2)
+ local status
+ if block_type == 0 then
+ status = DecompressStoreBlock(state)
+ elseif block_type == 1 then
+ status = DecompressFixBlock(state)
+ elseif block_type == 2 then
+ status = DecompressDynamicBlock(state)
+ else
+ return nil, -1 -- invalid block type (type == 3)
+ end
+ if status ~= 0 then return nil, status end
+ end
+
+ state.result_buffer[#state.result_buffer + 1] =
+ table_concat(state.buffer, "", 1, state.buffer_size)
+ local result = table_concat(state.result_buffer)
+ return result
end
-- @see LibDeflate:DecompressDeflate(str)
-- @see LibDeflate:DecompressDeflateWithDict(str, dictionary)
local function DecompressDeflateInternal(str, dictionary)
- local state = CreateDecompressState(str, dictionary)
- local result, status = Inflate(state)
- if not result then
- return nil, status
- end
-
- local bitlen_left = state.ReaderBitlenLeft()
- local bytelen_left = (bitlen_left - bitlen_left % 8) / 8
- return result, bytelen_left
+ local state = CreateDecompressState(str, dictionary)
+ local result, status = Inflate(state)
+ if not result then return nil, status end
+
+ local bitlen_left = state.ReaderBitlenLeft()
+ local bytelen_left = (bitlen_left - bitlen_left % 8) / 8
+ return result, bytelen_left
end
-- @see LibDeflate:DecompressZlib(str)
-- @see LibDeflate:DecompressZlibWithDict(str)
local function DecompressZlibInternal(str, dictionary)
- local state = CreateDecompressState(str, dictionary)
- local ReadBits = state.ReadBits
-
- local CMF = ReadBits(8)
- if state.ReaderBitlenLeft() < 0 then
- return nil, 2 -- available inflate data did not terminate
- end
- local CM = CMF % 16
- local CINFO = (CMF - CM) / 16
- if CM ~= 8 then
- return nil, -12 -- invalid compression method
- end
- if CINFO > 7 then
- return nil, -13 -- invalid window size
- end
-
- local FLG = ReadBits(8)
- if state.ReaderBitlenLeft() < 0 then
- return nil, 2 -- available inflate data did not terminate
- end
- if (CMF*256+FLG)%31 ~= 0 then
- return nil, -14 -- invalid header checksum
- end
-
- local FDIST = ((FLG-FLG%32)/32 % 2)
- local FLEVEL = ((FLG-FLG%64)/64 % 4) -- luacheck: ignore FLEVEL
-
- if FDIST == 1 then
- if not dictionary then
- return nil, -16 -- need dictonary, but dictionary is not provided.
- end
- local byte3 = ReadBits(8)
- local byte2 = ReadBits(8)
- local byte1 = ReadBits(8)
- local byte0 = ReadBits(8)
- local actual_adler32 = byte3*16777216+byte2*65536+byte1*256+byte0
- if state.ReaderBitlenLeft() < 0 then
- return nil, 2 -- available inflate data did not terminate
- end
- if not IsEqualAdler32(actual_adler32, dictionary.adler32) then
- return nil, -17 -- dictionary adler32 does not match
- end
- end
- local result, status = Inflate(state)
- if not result then
- return nil, status
- end
- state.SkipToByteBoundary()
-
- local adler_byte0 = ReadBits(8)
- local adler_byte1 = ReadBits(8)
- local adler_byte2 = ReadBits(8)
- local adler_byte3 = ReadBits(8)
- if state.ReaderBitlenLeft() < 0 then
- return nil, 2 -- available inflate data did not terminate
- end
-
- local adler32_expected = adler_byte0*16777216
- + adler_byte1*65536 + adler_byte2*256 + adler_byte3
- local adler32_actual = LibDeflate:Adler32(result)
- if not IsEqualAdler32(adler32_expected, adler32_actual) then
- return nil, -15 -- Adler32 checksum does not match
- end
-
- local bitlen_left = state.ReaderBitlenLeft()
- local bytelen_left = (bitlen_left - bitlen_left % 8) / 8
- return result, bytelen_left
+ local state = CreateDecompressState(str, dictionary)
+ local ReadBits = state.ReadBits
+
+ local CMF = ReadBits(8)
+ if state.ReaderBitlenLeft() < 0 then
+ return nil, 2 -- available inflate data did not terminate
+ end
+ local CM = CMF % 16
+ local CINFO = (CMF - CM) / 16
+ if CM ~= 8 then
+ return nil, -12 -- invalid compression method
+ end
+ if CINFO > 7 then
+ return nil, -13 -- invalid window size
+ end
+
+ local FLG = ReadBits(8)
+ if state.ReaderBitlenLeft() < 0 then
+ return nil, 2 -- available inflate data did not terminate
+ end
+ if (CMF * 256 + FLG) % 31 ~= 0 then
+ return nil, -14 -- invalid header checksum
+ end
+
+ local FDIST = ((FLG - FLG % 32) / 32 % 2)
+ local FLEVEL = ((FLG - FLG % 64) / 64 % 4) -- luacheck: ignore FLEVEL
+
+ if FDIST == 1 then
+ if not dictionary then
+ return nil, -16 -- need dictonary, but dictionary is not provided.
+ end
+ local byte3 = ReadBits(8)
+ local byte2 = ReadBits(8)
+ local byte1 = ReadBits(8)
+ local byte0 = ReadBits(8)
+ local actual_adler32 = byte3 * 16777216 + byte2 * 65536 + byte1 * 256 +
+ byte0
+ if state.ReaderBitlenLeft() < 0 then
+ return nil, 2 -- available inflate data did not terminate
+ end
+ if not IsEqualAdler32(actual_adler32, dictionary.adler32) then
+ return nil, -17 -- dictionary adler32 does not match
+ end
+ end
+ local result, status = Inflate(state)
+ if not result then return nil, status end
+ state.SkipToByteBoundary()
+
+ local adler_byte0 = ReadBits(8)
+ local adler_byte1 = ReadBits(8)
+ local adler_byte2 = ReadBits(8)
+ local adler_byte3 = ReadBits(8)
+ if state.ReaderBitlenLeft() < 0 then
+ return nil, 2 -- available inflate data did not terminate
+ end
+
+ local adler32_expected = adler_byte0 * 16777216 + adler_byte1 * 65536 +
+ adler_byte2 * 256 + adler_byte3
+ local adler32_actual = LibDeflate:Adler32(result)
+ if not IsEqualAdler32(adler32_expected, adler32_actual) then
+ return nil, -15 -- Adler32 checksum does not match
+ end
+
+ local bitlen_left = state.ReaderBitlenLeft()
+ local bytelen_left = (bitlen_left - bitlen_left % 8) / 8
+ return result, bytelen_left
end
--- Decompress a raw deflate compressed data.
@@ -2730,12 +2740,11 @@ end
-- this return value is undefined.
-- @see LibDeflate:CompressDeflate
function LibDeflate:DecompressDeflate(str)
- local arg_valid, arg_err = IsValidArguments(str)
- if not arg_valid then
- error(("Usage: LibDeflate:DecompressDeflate(str): "
- ..arg_err), 2)
- end
- return DecompressDeflateInternal(str)
+ local arg_valid, arg_err = IsValidArguments(str)
+ if not arg_valid then
+ error(("Usage: LibDeflate:DecompressDeflate(str): " .. arg_err), 2)
+ end
+ return DecompressDeflateInternal(str)
end
--- Decompress a raw deflate compressed data with a preset dictionary.
@@ -2757,12 +2766,12 @@ end
-- this return value is undefined.
-- @see LibDeflate:CompressDeflateWithDict
function LibDeflate:DecompressDeflateWithDict(str, dictionary)
- local arg_valid, arg_err = IsValidArguments(str, true, dictionary)
- if not arg_valid then
- error(("Usage: LibDeflate:DecompressDeflateWithDict(str, dictionary): "
- ..arg_err), 2)
- end
- return DecompressDeflateInternal(str, dictionary)
+ local arg_valid, arg_err = IsValidArguments(str, true, dictionary)
+ if not arg_valid then
+ error(("Usage: LibDeflate:DecompressDeflateWithDict(str, dictionary): " ..
+ arg_err), 2)
+ end
+ return DecompressDeflateInternal(str, dictionary)
end
--- Decompress a zlib compressed data.
@@ -2779,12 +2788,11 @@ end
-- this return value is undefined.
-- @see LibDeflate:CompressZlib
function LibDeflate:DecompressZlib(str)
- local arg_valid, arg_err = IsValidArguments(str)
- if not arg_valid then
- error(("Usage: LibDeflate:DecompressZlib(str): "
- ..arg_err), 2)
- end
- return DecompressZlibInternal(str)
+ local arg_valid, arg_err = IsValidArguments(str)
+ if not arg_valid then
+ error(("Usage: LibDeflate:DecompressZlib(str): " .. arg_err), 2)
+ end
+ return DecompressZlibInternal(str)
end
--- Decompress a zlib compressed data with a preset dictionary.
@@ -2806,58 +2814,43 @@ end
-- this return value is undefined.
-- @see LibDeflate:CompressZlibWithDict
function LibDeflate:DecompressZlibWithDict(str, dictionary)
- local arg_valid, arg_err = IsValidArguments(str, true, dictionary)
- if not arg_valid then
- error(("Usage: LibDeflate:DecompressZlibWithDict(str, dictionary): "
- ..arg_err), 2)
- end
- return DecompressZlibInternal(str, dictionary)
+ local arg_valid, arg_err = IsValidArguments(str, true, dictionary)
+ if not arg_valid then
+ error(("Usage: LibDeflate:DecompressZlibWithDict(str, dictionary): " ..
+ arg_err), 2)
+ end
+ return DecompressZlibInternal(str, dictionary)
end
-- Calculate the huffman code of fixed block
do
- _fix_block_literal_huffman_bitlen = {}
- for sym=0, 143 do
- _fix_block_literal_huffman_bitlen[sym] = 8
- end
- for sym=144, 255 do
- _fix_block_literal_huffman_bitlen[sym] = 9
- end
- for sym=256, 279 do
- _fix_block_literal_huffman_bitlen[sym] = 7
- end
- for sym=280, 287 do
- _fix_block_literal_huffman_bitlen[sym] = 8
- end
-
- _fix_block_dist_huffman_bitlen = {}
- for dist=0, 31 do
- _fix_block_dist_huffman_bitlen[dist] = 5
- end
- local status
- status, _fix_block_literal_huffman_bitlen_count
- , _fix_block_literal_huffman_to_deflate_code =
- GetHuffmanForDecode(_fix_block_literal_huffman_bitlen, 287, 9)
- assert(status == 0)
- status, _fix_block_dist_huffman_bitlen_count,
- _fix_block_dist_huffman_to_deflate_code =
- GetHuffmanForDecode(_fix_block_dist_huffman_bitlen, 31, 5)
- assert(status == 0)
-
- _fix_block_literal_huffman_code =
- GetHuffmanCodeFromBitlen(_fix_block_literal_huffman_bitlen_count
- , _fix_block_literal_huffman_bitlen, 287, 9)
- _fix_block_dist_huffman_code =
- GetHuffmanCodeFromBitlen(_fix_block_dist_huffman_bitlen_count
- , _fix_block_dist_huffman_bitlen, 31, 5)
+ _fix_block_literal_huffman_bitlen = {}
+ for sym = 0, 143 do _fix_block_literal_huffman_bitlen[sym] = 8 end
+ for sym = 144, 255 do _fix_block_literal_huffman_bitlen[sym] = 9 end
+ for sym = 256, 279 do _fix_block_literal_huffman_bitlen[sym] = 7 end
+ for sym = 280, 287 do _fix_block_literal_huffman_bitlen[sym] = 8 end
+
+ _fix_block_dist_huffman_bitlen = {}
+ for dist = 0, 31 do _fix_block_dist_huffman_bitlen[dist] = 5 end
+ local status
+ status, _fix_block_literal_huffman_bitlen_count, _fix_block_literal_huffman_to_deflate_code =
+ GetHuffmanForDecode(_fix_block_literal_huffman_bitlen, 287, 9)
+ assert(status == 0)
+ status, _fix_block_dist_huffman_bitlen_count, _fix_block_dist_huffman_to_deflate_code =
+ GetHuffmanForDecode(_fix_block_dist_huffman_bitlen, 31, 5)
+ assert(status == 0)
+
+ _fix_block_literal_huffman_code = GetHuffmanCodeFromBitlen(
+ _fix_block_literal_huffman_bitlen_count,
+ _fix_block_literal_huffman_bitlen, 287, 9)
+ _fix_block_dist_huffman_code = GetHuffmanCodeFromBitlen(
+ _fix_block_dist_huffman_bitlen_count,
+ _fix_block_dist_huffman_bitlen, 31, 5)
end
--- Encoding algorithms
-- Prefix encoding algorithm
--- implemented by Galmok of European Stormrage (Horde), galmok@gmail.com
--- From LibCompress ,
--- which is licensed under GPLv2
--- The code has been modified by the author of LibDeflate.
+-- Credits to LibCompress.
+-- The code has been rewritten by the author of LibDeflate.
------------------------------------------------------------------------------
-- to be able to match any requested byte value, the search
@@ -2866,14 +2859,23 @@ end
-- "illegal" byte values:
-- 0 is replaces %z
local _gsub_escape_table = {
- ["\000"] = "%z", ["("] = "%(", [")"] = "%)", ["."] = "%.",
- ["%"] = "%%", ["+"] = "%+", ["-"] = "%-", ["*"] = "%*",
- ["?"] = "%?", ["["] = "%[", ["]"] = "%]", ["^"] = "%^",
- ["$"] = "%$",
+ ["\000"] = "%z",
+ ["("] = "%(",
+ [")"] = "%)",
+ ["."] = "%.",
+ ["%"] = "%%",
+ ["+"] = "%+",
+ ["-"] = "%-",
+ ["*"] = "%*",
+ ["?"] = "%?",
+ ["["] = "%[",
+ ["]"] = "%]",
+ ["^"] = "%^",
+ ["$"] = "%$"
}
local function escape_for_gsub(str)
- return str:gsub("([%z%(%)%.%%%+%-%*%?%[%]%^%$])", _gsub_escape_table)
+ return str:gsub("([%z%(%)%.%%%+%-%*%?%[%]%^%$])", _gsub_escape_table)
end
--- Create a custom codec with encoder and decoder.
@@ -2883,6 +2885,7 @@ end
-- localization into account. One byte (0-255) in the string is exactly one
-- character (0-255).
-- Credits to LibCompress.
+-- The code has been rewritten by the author of LibDeflate.
-- @param reserved_chars [string] The created encoder will ensure encoded
-- data does not contain any single character in reserved_chars. This parameter
-- should be non-empty.
@@ -2915,168 +2918,147 @@ end
-- -- "encoded" does not contain "\000" or "\001"
-- local decoded = codec:Decode(encoded)
-- -- assert(decoded == SOME_STRING)
-function LibDeflate:CreateCodec(reserved_chars, escape_chars
- , map_chars)
- -- select a default escape character
- if type(reserved_chars) ~= "string"
- or type(escape_chars) ~= "string"
- or type(map_chars) ~= "string" then
- error(
- "Usage: LibDeflate:CreateCodec(reserved_chars,"
- .." escape_chars, map_chars):"
- .." All arguments must be string.", 2)
- end
-
- if escape_chars == "" then
- return nil, "No escape characters supplied."
- end
- if #reserved_chars < #map_chars then
- return nil, "The number of reserved characters must be"
- .." at least as many as the number of mapped chars."
- end
- if reserved_chars == "" then
- return nil, "No characters to encode."
- end
-
- local encode_bytes = reserved_chars..escape_chars..map_chars
- -- build list of bytes not available as a suffix to a prefix byte
- local taken = {}
- for i = 1, #encode_bytes do
- local byte = string_byte(encode_bytes, i, i)
- if taken[byte] then -- Modified by LibDeflate:
- return nil, "There must be no duplicate characters in the"
- .." concatenation of reserved_chars, escape_chars and"
- .." map_chars."
- end
- taken[byte] = true
- end
-
- -- Modified by LibDeflate:
- -- Store the patterns and replacement in tables for later use.
- -- This function is modified that loadstring() lua api is no longer used.
- local decode_patterns = {}
- local decode_repls = {}
-
- -- the encoding can be a single gsub
- -- , but the decoding can require multiple gsubs
- local encode_search = {}
- local encode_translate = {}
-
- -- map single byte to single byte
- if #map_chars > 0 then
- local decode_search = {}
- local decode_translate = {}
- for i = 1, #map_chars do
- local from = string_sub(reserved_chars, i, i)
- local to = string_sub(map_chars, i, i)
- encode_translate[from] = to
- encode_search[#encode_search+1] = from
- decode_translate[to] = from
- decode_search[#decode_search+1] = to
- end
- decode_patterns[#decode_patterns+1] =
- "([".. escape_for_gsub(table_concat(decode_search)).."])"
- decode_repls[#decode_repls+1] = decode_translate
- end
-
- local escape_char_index = 1
- local escape_char = string_sub(escape_chars
- , escape_char_index, escape_char_index)
- -- map single byte to double-byte
- local r = 0 -- suffix char value to the escapeChar
-
- local decode_search = {}
- local decode_translate = {}
- for i = 1, #encode_bytes do
- local c = string_sub(encode_bytes, i, i)
- if not encode_translate[c] then
- -- this loop will update escapeChar and r
- while r >= 256 or taken[r] do
- -- Bug in LibCompress r81
- -- while r < 256 and taken[r] do
- r = r + 1
- if r > 255 then -- switch to next escapeChar
- decode_patterns[#decode_patterns+1] =
- escape_for_gsub(escape_char)
- .."(["
- .. escape_for_gsub(table_concat(decode_search)).."])"
- decode_repls[#decode_repls+1] = decode_translate
-
- escape_char_index = escape_char_index + 1
- escape_char = string_sub(escape_chars, escape_char_index
- , escape_char_index)
- r = 0
- decode_search = {}
- decode_translate = {}
-
- -- Fixes Another bug in LibCompress r82.
- -- LibCompress checks this error condition
- -- right after "if r > 255 then"
- -- This is why error case should also be tested.
- if not escape_char or escape_char == "" then
- -- actually I don't need to check
- -- "not ecape_char", but what if Lua changes
- -- the behavior of string.sub() in the future?
- -- we are out of escape chars and we need more!
- return nil, "Out of escape characters."
- end
- end
- end
-
- local char_r = _byte_to_char[r]
- encode_translate[c] = escape_char..char_r
- encode_search[#encode_search+1] = c
- decode_translate[char_r] = c
- decode_search[#decode_search+1] = char_r
- r = r + 1
- end
- if i == #encode_bytes then
- decode_patterns[#decode_patterns+1] =
- escape_for_gsub(escape_char).."(["
- .. escape_for_gsub(table_concat(decode_search)).."])"
- decode_repls[#decode_repls+1] = decode_translate
- end
- end
-
- local codec = {}
-
- local encode_pattern = "(["
- .. escape_for_gsub(table_concat(encode_search)).."])"
- local encode_repl = encode_translate
-
- function codec:Encode(str)
- if type(str) ~= "string" then
- error(("Usage: codec:Encode(str):"
- .." 'str' - string expected got '%s'."):format(type(str)), 2)
- end
- return string_gsub(str, encode_pattern, encode_repl)
- end
-
- local decode_tblsize = #decode_patterns
- local decode_fail_pattern = "(["
- .. escape_for_gsub(reserved_chars).."])"
-
- function codec:Decode(str)
- if type(str) ~= "string" then
- error(("Usage: codec:Decode(str):"
- .." 'str' - string expected got '%s'."):format(type(str)), 2)
- end
- if string_find(str, decode_fail_pattern) then
- return nil
- end
- for i = 1, decode_tblsize do
- str = string_gsub(str, decode_patterns[i], decode_repls[i])
- end
- return str
- end
-
- return codec
+function LibDeflate:CreateCodec(reserved_chars, escape_chars, map_chars)
+ if type(reserved_chars) ~= "string" or type(escape_chars) ~= "string" or
+ type(map_chars) ~= "string" then
+ error("Usage: LibDeflate:CreateCodec(reserved_chars," ..
+ " escape_chars, map_chars):" .. " All arguments must be string.", 2)
+ end
+
+ if escape_chars == "" then return nil, "No escape characters supplied." end
+ if #reserved_chars < #map_chars then
+ return nil, "The number of reserved characters must be" ..
+ " at least as many as the number of mapped chars."
+ end
+ if reserved_chars == "" then return nil, "No characters to encode." end
+
+ local encode_bytes = reserved_chars .. escape_chars .. map_chars
+ -- build list of bytes not available as a suffix to a prefix byte
+ local taken = {}
+ for i = 1, #encode_bytes do
+ local byte = string_byte(encode_bytes, i, i)
+ if taken[byte] then
+ return nil, "There must be no duplicate characters in the" ..
+ " concatenation of reserved_chars, escape_chars and" ..
+ " map_chars."
+ end
+ taken[byte] = true
+ end
+
+ local decode_patterns = {}
+ local decode_repls = {}
+
+ -- the encoding can be a single gsub
+ -- , but the decoding can require multiple gsubs
+ local encode_search = {}
+ local encode_translate = {}
+
+ -- map single byte to single byte
+ if #map_chars > 0 then
+ local decode_search = {}
+ local decode_translate = {}
+ for i = 1, #map_chars do
+ local from = string_sub(reserved_chars, i, i)
+ local to = string_sub(map_chars, i, i)
+ encode_translate[from] = to
+ encode_search[#encode_search + 1] = from
+ decode_translate[to] = from
+ decode_search[#decode_search + 1] = to
+ end
+ decode_patterns[#decode_patterns + 1] =
+ "([" .. escape_for_gsub(table_concat(decode_search)) .. "])"
+ decode_repls[#decode_repls + 1] = decode_translate
+ end
+
+ local escape_char_index = 1
+ local escape_char = string_sub(escape_chars, escape_char_index,
+ escape_char_index)
+ -- map single byte to double-byte
+ local r = 0 -- suffix char value to the escapeChar
+
+ local decode_search = {}
+ local decode_translate = {}
+ for i = 1, #encode_bytes do
+ local c = string_sub(encode_bytes, i, i)
+ if not encode_translate[c] then
+ while r >= 256 or taken[r] do
+ r = r + 1
+ if r > 255 then -- switch to next escapeChar
+ decode_patterns[#decode_patterns + 1] =
+ escape_for_gsub(escape_char) .. "([" ..
+ escape_for_gsub(table_concat(decode_search)) .. "])"
+ decode_repls[#decode_repls + 1] = decode_translate
+
+ escape_char_index = escape_char_index + 1
+ escape_char = string_sub(escape_chars, escape_char_index,
+ escape_char_index)
+ r = 0
+ decode_search = {}
+ decode_translate = {}
+
+ if not escape_char or escape_char == "" then
+ -- actually I don't need to check
+ -- "not ecape_char", but what if Lua changes
+ -- the behavior of string.sub() in the future?
+ -- we are out of escape chars and we need more!
+ return nil, "Out of escape characters."
+ end
+ end
+ end
+
+ local char_r = _byte_to_char[r]
+ encode_translate[c] = escape_char .. char_r
+ encode_search[#encode_search + 1] = c
+ decode_translate[char_r] = c
+ decode_search[#decode_search + 1] = char_r
+ r = r + 1
+ end
+ if i == #encode_bytes then
+ decode_patterns[#decode_patterns + 1] =
+ escape_for_gsub(escape_char) .. "([" ..
+ escape_for_gsub(table_concat(decode_search)) .. "])"
+ decode_repls[#decode_repls + 1] = decode_translate
+ end
+ end
+
+ local codec = {}
+
+ local encode_pattern = "([" .. escape_for_gsub(table_concat(encode_search)) ..
+ "])"
+ local encode_repl = encode_translate
+
+ function codec:Encode(str)
+ if type(str) ~= "string" then
+ error(
+ ("Usage: codec:Encode(str):" .. " 'str' - string expected got '%s'."):format(
+ type(str)), 2)
+ end
+ return string_gsub(str, encode_pattern, encode_repl)
+ end
+
+ local decode_tblsize = #decode_patterns
+ local decode_fail_pattern = "([" .. escape_for_gsub(reserved_chars) .. "])"
+
+ function codec:Decode(str)
+ if type(str) ~= "string" then
+ error(
+ ("Usage: codec:Decode(str):" .. " 'str' - string expected got '%s'."):format(
+ type(str)), 2)
+ end
+ if string_find(str, decode_fail_pattern) then return nil end
+ for i = 1, decode_tblsize do
+ str = string_gsub(str, decode_patterns[i], decode_repls[i])
+ end
+ return str
+ end
+
+ return codec
end
local _addon_channel_codec
local function GenerateWoWAddonChannelCodec()
- return LibDeflate:CreateCodec("\000", "\001", "")
+ return LibDeflate:CreateCodec("\000", "\001", "")
end
--- Encode the string to make it ready to be transmitted in World of
@@ -3086,14 +3068,14 @@ end
-- @return The encoded string.
-- @see LibDeflate:DecodeForWoWAddonChannel
function LibDeflate:EncodeForWoWAddonChannel(str)
- if type(str) ~= "string" then
- error(("Usage: LibDeflate:EncodeForWoWAddonChannel(str):"
- .." 'str' - string expected got '%s'."):format(type(str)), 2)
- end
- if not _addon_channel_codec then
- _addon_channel_codec = GenerateWoWAddonChannelCodec()
- end
- return _addon_channel_codec:Encode(str)
+ if type(str) ~= "string" then
+ error(("Usage: LibDeflate:EncodeForWoWAddonChannel(str):" ..
+ " 'str' - string expected got '%s'."):format(type(str)), 2)
+ end
+ if not _addon_channel_codec then
+ _addon_channel_codec = GenerateWoWAddonChannelCodec()
+ end
+ return _addon_channel_codec:Encode(str)
end
--- Decode the string produced by LibDeflate:EncodeForWoWAddonChannel
@@ -3101,21 +3083,19 @@ end
-- @return [string/nil] The decoded string if succeeds. nil if fails.
-- @see LibDeflate:EncodeForWoWAddonChannel
function LibDeflate:DecodeForWoWAddonChannel(str)
- if type(str) ~= "string" then
- error(("Usage: LibDeflate:DecodeForWoWAddonChannel(str):"
- .." 'str' - string expected got '%s'."):format(type(str)), 2)
- end
- if not _addon_channel_codec then
- _addon_channel_codec = GenerateWoWAddonChannelCodec()
- end
- return _addon_channel_codec:Decode(str)
+ if type(str) ~= "string" then
+ error(("Usage: LibDeflate:DecodeForWoWAddonChannel(str):" ..
+ " 'str' - string expected got '%s'."):format(type(str)), 2)
+ end
+ if not _addon_channel_codec then
+ _addon_channel_codec = GenerateWoWAddonChannelCodec()
+ end
+ return _addon_channel_codec:Decode(str)
end
-- For World of Warcraft Chat Channel Encoding
--- implemented by Galmok of European Stormrage (Horde), galmok@gmail.com
--- From LibCompress ,
--- which is licensed under GPLv2
--- The code has been modified by the author of LibDeflate.
+-- Credits to LibCompress.
+-- The code has been rewritten by the author of LibDeflate.
-- Following byte values are not allowed:
-- \000, s, S, \010, \013, \124, %
-- Because SendChatMessage will error
@@ -3136,14 +3116,11 @@ end
-- 53.5% (average with random data valued zero to 255)
-- 100% (only encoding data that encodes to two bytes)
local function GenerateWoWChatChannelCodec()
- local r = {}
- for i = 128, 255 do
- r[#r+1] = _byte_to_char[i]
- end
-
- local reserved_chars = "sS\000\010\013\124%"..table_concat(r)
- return LibDeflate:CreateCodec(reserved_chars
- , "\029\031", "\015\020")
+ local r = {}
+ for i = 128, 255 do r[#r + 1] = _byte_to_char[i] end
+
+ local reserved_chars = "sS\000\010\013\124%" .. table_concat(r)
+ return LibDeflate:CreateCodec(reserved_chars, "\029\031", "\015\020")
end
local _chat_channel_codec
@@ -3155,14 +3132,14 @@ local _chat_channel_codec
-- @return [string] The encoded string.
-- @see LibDeflate:DecodeForWoWChatChannel
function LibDeflate:EncodeForWoWChatChannel(str)
- if type(str) ~= "string" then
- error(("Usage: LibDeflate:EncodeForWoWChatChannel(str):"
- .." 'str' - string expected got '%s'."):format(type(str)), 2)
- end
- if not _chat_channel_codec then
- _chat_channel_codec = GenerateWoWChatChannelCodec()
- end
- return _chat_channel_codec:Encode(str)
+ if type(str) ~= "string" then
+ error(("Usage: LibDeflate:EncodeForWoWChatChannel(str):" ..
+ " 'str' - string expected got '%s'."):format(type(str)), 2)
+ end
+ if not _chat_channel_codec then
+ _chat_channel_codec = GenerateWoWChatChannelCodec()
+ end
+ return _chat_channel_codec:Encode(str)
end
--- Decode the string produced by LibDeflate:EncodeForWoWChatChannel.
@@ -3170,47 +3147,160 @@ end
-- @return [string/nil] The decoded string if succeeds. nil if fails.
-- @see LibDeflate:EncodeForWoWChatChannel
function LibDeflate:DecodeForWoWChatChannel(str)
- if type(str) ~= "string" then
- error(("Usage: LibDeflate:DecodeForWoWChatChannel(str):"
- .." 'str' - string expected got '%s'."):format(type(str)), 2)
- end
- if not _chat_channel_codec then
- _chat_channel_codec = GenerateWoWChatChannelCodec()
- end
- return _chat_channel_codec:Decode(str)
+ if type(str) ~= "string" then
+ error(("Usage: LibDeflate:DecodeForWoWChatChannel(str):" ..
+ " 'str' - string expected got '%s'."):format(type(str)), 2)
+ end
+ if not _chat_channel_codec then
+ _chat_channel_codec = GenerateWoWChatChannelCodec()
+ end
+ return _chat_channel_codec:Decode(str)
end
--- Credits to WeakAuras ,
--- and Galmok (galmok@gmail.com) for the 6 bit encoding algorithm.
+-- Credits to WeakAuras2 and Galmok for the 6 bit encoding algorithm.
+-- The code has been rewritten by the author of LibDeflate.
-- The result of encoding will be 25% larger than the
-- origin string, but every single byte of the encoding result will be
-- printable characters as the following.
local _byte_to_6bit_char = {
- [0]="a", "b", "c", "d", "e", "f", "g", "h",
- "i", "j", "k", "l", "m", "n", "o", "p",
- "q", "r", "s", "t", "u", "v", "w", "x",
- "y", "z", "A", "B", "C", "D", "E", "F",
- "G", "H", "I", "J", "K", "L", "M", "N",
- "O", "P", "Q", "R", "S", "T", "U", "V",
- "W", "X", "Y", "Z", "0", "1", "2", "3",
- "4", "5", "6", "7", "8", "9", "(", ")",
+ [0] = "a",
+ "b",
+ "c",
+ "d",
+ "e",
+ "f",
+ "g",
+ "h",
+ "i",
+ "j",
+ "k",
+ "l",
+ "m",
+ "n",
+ "o",
+ "p",
+ "q",
+ "r",
+ "s",
+ "t",
+ "u",
+ "v",
+ "w",
+ "x",
+ "y",
+ "z",
+ "A",
+ "B",
+ "C",
+ "D",
+ "E",
+ "F",
+ "G",
+ "H",
+ "I",
+ "J",
+ "K",
+ "L",
+ "M",
+ "N",
+ "O",
+ "P",
+ "Q",
+ "R",
+ "S",
+ "T",
+ "U",
+ "V",
+ "W",
+ "X",
+ "Y",
+ "Z",
+ "0",
+ "1",
+ "2",
+ "3",
+ "4",
+ "5",
+ "6",
+ "7",
+ "8",
+ "9",
+ "(",
+ ")"
}
local _6bit_to_byte = {
- [97]=0,[98]=1,[99]=2,[100]=3,[101]=4,[102]=5,[103]=6,[104]=7,
- [105]=8,[106]=9,[107]=10,[108]=11,[109]=12,[110]=13,[111]=14,[112]=15,
- [113]=16,[114]=17,[115]=18,[116]=19,[117]=20,[118]=21,[119]=22,[120]=23,
- [121]=24,[122]=25,[65]=26,[66]=27,[67]=28,[68]=29,[69]=30,[70]=31,
- [71]=32,[72]=33,[73]=34,[74]=35,[75]=36,[76]=37,[77]=38,[78]=39,
- [79]=40,[80]=41,[81]=42,[82]=43,[83]=44,[84]=45,[85]=46,[86]=47,
- [87]=48,[88]=49,[89]=50,[90]=51,[48]=52,[49]=53,[50]=54,[51]=55,
- [52]=56,[53]=57,[54]=58,[55]=59,[56]=60,[57]=61,[40]=62,[41]=63,
+ [97] = 0,
+ [98] = 1,
+ [99] = 2,
+ [100] = 3,
+ [101] = 4,
+ [102] = 5,
+ [103] = 6,
+ [104] = 7,
+ [105] = 8,
+ [106] = 9,
+ [107] = 10,
+ [108] = 11,
+ [109] = 12,
+ [110] = 13,
+ [111] = 14,
+ [112] = 15,
+ [113] = 16,
+ [114] = 17,
+ [115] = 18,
+ [116] = 19,
+ [117] = 20,
+ [118] = 21,
+ [119] = 22,
+ [120] = 23,
+ [121] = 24,
+ [122] = 25,
+ [65] = 26,
+ [66] = 27,
+ [67] = 28,
+ [68] = 29,
+ [69] = 30,
+ [70] = 31,
+ [71] = 32,
+ [72] = 33,
+ [73] = 34,
+ [74] = 35,
+ [75] = 36,
+ [76] = 37,
+ [77] = 38,
+ [78] = 39,
+ [79] = 40,
+ [80] = 41,
+ [81] = 42,
+ [82] = 43,
+ [83] = 44,
+ [84] = 45,
+ [85] = 46,
+ [86] = 47,
+ [87] = 48,
+ [88] = 49,
+ [89] = 50,
+ [90] = 51,
+ [48] = 52,
+ [49] = 53,
+ [50] = 54,
+ [51] = 55,
+ [52] = 56,
+ [53] = 57,
+ [54] = 58,
+ [55] = 59,
+ [56] = 60,
+ [57] = 61,
+ [40] = 62,
+ [41] = 63
}
--- Encode the string to make it printable.
--
--- Credis to WeakAuras2, this function is equivalant to the implementation
+-- Credit to WeakAuras2, this function is equivalant to the implementation
-- it is using right now.
+-- The code has been rewritten by the author of LibDeflate.
-- The encoded string will be 25% larger than the origin string. However, every
-- single byte of the encoded string will be one of 64 printable ASCII
-- characters, which are can be easier copied, pasted and displayed.
@@ -3219,48 +3309,47 @@ local _6bit_to_byte = {
-- @param str [string] The string to be encoded.
-- @return [string] The encoded string.
function LibDeflate:EncodeForPrint(str)
- if type(str) ~= "string" then
- error(("Usage: LibDeflate:EncodeForPrint(str):"
- .." 'str' - string expected got '%s'."):format(type(str)), 2)
- end
- local strlen = #str
- local strlenMinus2 = strlen - 2
- local i = 1
- local buffer = {}
- local buffer_size = 0
- while i <= strlenMinus2 do
- local x1, x2, x3 = string_byte(str, i, i+2)
- i = i + 3
- local cache = x1+x2*256+x3*65536
- local b1 = cache % 64
- cache = (cache - b1) / 64
- local b2 = cache % 64
- cache = (cache - b2) / 64
- local b3 = cache % 64
- local b4 = (cache - b3) / 64
- buffer_size = buffer_size + 1
- buffer[buffer_size] =
- _byte_to_6bit_char[b1].._byte_to_6bit_char[b2]
- .._byte_to_6bit_char[b3].._byte_to_6bit_char[b4]
- end
-
- local cache = 0
- local cache_bitlen = 0
- while i <= strlen do
- local x = string_byte(str, i, i)
- cache = cache + x * _pow2[cache_bitlen]
- cache_bitlen = cache_bitlen + 8
- i = i + 1
- end
- while cache_bitlen > 0 do
- local bit6 = cache % 64
- buffer_size = buffer_size + 1
- buffer[buffer_size] = _byte_to_6bit_char[bit6]
- cache = (cache - bit6) / 64
- cache_bitlen = cache_bitlen - 6
- end
-
- return table_concat(buffer)
+ if type(str) ~= "string" then
+ error(("Usage: LibDeflate:EncodeForPrint(str):" ..
+ " 'str' - string expected got '%s'."):format(type(str)), 2)
+ end
+ local strlen = #str
+ local strlenMinus2 = strlen - 2
+ local i = 1
+ local buffer = {}
+ local buffer_size = 0
+ while i <= strlenMinus2 do
+ local x1, x2, x3 = string_byte(str, i, i + 2)
+ i = i + 3
+ local cache = x1 + x2 * 256 + x3 * 65536
+ local b1 = cache % 64
+ cache = (cache - b1) / 64
+ local b2 = cache % 64
+ cache = (cache - b2) / 64
+ local b3 = cache % 64
+ local b4 = (cache - b3) / 64
+ buffer_size = buffer_size + 1
+ buffer[buffer_size] = _byte_to_6bit_char[b1] .. _byte_to_6bit_char[b2] ..
+ _byte_to_6bit_char[b3] .. _byte_to_6bit_char[b4]
+ end
+
+ local cache = 0
+ local cache_bitlen = 0
+ while i <= strlen do
+ local x = string_byte(str, i, i)
+ cache = cache + x * _pow2[cache_bitlen]
+ cache_bitlen = cache_bitlen + 8
+ i = i + 1
+ end
+ while cache_bitlen > 0 do
+ local bit6 = cache % 64
+ buffer_size = buffer_size + 1
+ buffer[buffer_size] = _byte_to_6bit_char[bit6]
+ cache = (cache - bit6) / 64
+ cache_bitlen = cache_bitlen - 6
+ end
+
+ return table_concat(buffer)
end
--- Decode the printable string produced by LibDeflate:EncodeForPrint.
@@ -3274,79 +3363,73 @@ end
-- @param str [string] The string to be decoded
-- @return [string/nil] The decoded string if succeeds. nil if fails.
function LibDeflate:DecodeForPrint(str)
- if type(str) ~= "string" then
- error(("Usage: LibDeflate:DecodeForPrint(str):"
- .." 'str' - string expected got '%s'."):format(type(str)), 2)
- end
- str = str:gsub("^[%c ]+", "")
- str = str:gsub("[%c ]+$", "")
-
- local strlen = #str
- if strlen == 1 then
- return nil
- end
- local strlenMinus3 = strlen - 3
- local i = 1
- local buffer = {}
- local buffer_size = 0
- while i <= strlenMinus3 do
- local x1, x2, x3, x4 = string_byte(str, i, i+3)
- x1 = _6bit_to_byte[x1]
- x2 = _6bit_to_byte[x2]
- x3 = _6bit_to_byte[x3]
- x4 = _6bit_to_byte[x4]
- if not (x1 and x2 and x3 and x4) then
- return nil
- end
- i = i + 4
- local cache = x1+x2*64+x3*4096+x4*262144
- local b1 = cache % 256
- cache = (cache - b1) / 256
- local b2 = cache % 256
- local b3 = (cache - b2) / 256
- buffer_size = buffer_size + 1
- buffer[buffer_size] =
- _byte_to_char[b1].._byte_to_char[b2].._byte_to_char[b3]
- end
-
- local cache = 0
- local cache_bitlen = 0
- while i <= strlen do
- local x = string_byte(str, i, i)
- x = _6bit_to_byte[x]
- if not x then
- return nil
- end
- cache = cache + x * _pow2[cache_bitlen]
- cache_bitlen = cache_bitlen + 6
- i = i + 1
- end
-
- while cache_bitlen >= 8 do
- local byte = cache % 256
- buffer_size = buffer_size + 1
- buffer[buffer_size] = _byte_to_char[byte]
- cache = (cache - byte) / 256
- cache_bitlen = cache_bitlen - 8
- end
-
- return table_concat(buffer)
+ if type(str) ~= "string" then
+ error(("Usage: LibDeflate:DecodeForPrint(str):" ..
+ " 'str' - string expected got '%s'."):format(type(str)), 2)
+ end
+ str = str:gsub("^[%c ]+", "")
+ str = str:gsub("[%c ]+$", "")
+
+ local strlen = #str
+ if strlen == 1 then return nil end
+ local strlenMinus3 = strlen - 3
+ local i = 1
+ local buffer = {}
+ local buffer_size = 0
+ while i <= strlenMinus3 do
+ local x1, x2, x3, x4 = string_byte(str, i, i + 3)
+ x1 = _6bit_to_byte[x1]
+ x2 = _6bit_to_byte[x2]
+ x3 = _6bit_to_byte[x3]
+ x4 = _6bit_to_byte[x4]
+ if not (x1 and x2 and x3 and x4) then return nil end
+ i = i + 4
+ local cache = x1 + x2 * 64 + x3 * 4096 + x4 * 262144
+ local b1 = cache % 256
+ cache = (cache - b1) / 256
+ local b2 = cache % 256
+ local b3 = (cache - b2) / 256
+ buffer_size = buffer_size + 1
+ buffer[buffer_size] = _byte_to_char[b1] .. _byte_to_char[b2] ..
+ _byte_to_char[b3]
+ end
+
+ local cache = 0
+ local cache_bitlen = 0
+ while i <= strlen do
+ local x = string_byte(str, i, i)
+ x = _6bit_to_byte[x]
+ if not x then return nil end
+ cache = cache + x * _pow2[cache_bitlen]
+ cache_bitlen = cache_bitlen + 6
+ i = i + 1
+ end
+
+ while cache_bitlen >= 8 do
+ local byte = cache % 256
+ buffer_size = buffer_size + 1
+ buffer[buffer_size] = _byte_to_char[byte]
+ cache = (cache - byte) / 256
+ cache_bitlen = cache_bitlen - 8
+ end
+
+ return table_concat(buffer)
end
local function InternalClearCache()
- _chat_channel_codec = nil
- _addon_channel_codec = nil
+ _chat_channel_codec = nil
+ _addon_channel_codec = nil
end
-- For test. Don't use the functions in this table for real application.
-- Stuffs in this table is subject to change.
LibDeflate.internals = {
- LoadStringToTable = LoadStringToTable,
- IsValidDictionary = IsValidDictionary,
- IsEqualAdler32 = IsEqualAdler32,
- _byte_to_6bit_char = _byte_to_6bit_char,
- _6bit_to_byte = _6bit_to_byte,
- InternalClearCache = InternalClearCache,
+ LoadStringToTable = LoadStringToTable,
+ IsValidDictionary = IsValidDictionary,
+ IsEqualAdler32 = IsEqualAdler32,
+ _byte_to_6bit_char = _byte_to_6bit_char,
+ _6bit_to_byte = _6bit_to_byte,
+ InternalClearCache = InternalClearCache
}
--[[-- Commandline options
@@ -3368,169 +3451,155 @@ the entire preset dictionary.
-- currently no plan to support stdin and stdout.
-- Because Lua in Windows does not set stdout with binary mode.
if io and os and debug and _G.arg then
- local io = io
- local os = os
- local debug = debug
- local arg = _G.arg
- local debug_info = debug.getinfo(1)
- if debug_info.source == arg[0]
- or debug_info.short_src == arg[0] then
- -- We are indeed runnning THIS file from the commandline.
- local input
- local output
- local i = 1
- local status
- local is_zlib = false
- local is_decompress = false
- local level
- local strategy
- local dictionary
- while (arg[i]) do
- local a = arg[i]
- if a == "-h" then
- print(LibDeflate._COPYRIGHT
- .."\nUsage: lua LibDeflate.lua [OPTION] [INPUT] [OUTPUT]\n"
- .." -0 store only. no compression.\n"
- .." -1 fastest compression.\n"
- .." -9 slowest and best compression.\n"
- .." -d do decompression instead of compression.\n"
- .." --dict specify the file that contains"
- .." the entire preset dictionary.\n"
- .." -h give this help.\n"
- .." --strategy "
- .." specify a special compression strategy.\n"
- .." -v print the version and copyright info.\n"
- .." --zlib use zlib format instead of raw deflate.\n")
- os.exit(0)
- elseif a == "-v" then
- print(LibDeflate._COPYRIGHT)
- os.exit(0)
- elseif a:find("^%-[0-9]$") then
- level = tonumber(a:sub(2, 2))
- elseif a == "-d" then
- is_decompress = true
- elseif a == "--dict" then
- i = i + 1
- local dict_filename = arg[i]
- if not dict_filename then
- io.stderr:write("You must speicify the dict filename")
- os.exit(1)
- end
- local dict_file, dict_status = io.open(dict_filename, "rb")
- if not dict_file then
- io.stderr:write(
- ("LibDeflate: Cannot read the dictionary file '%s': %s")
- :format(dict_filename, dict_status))
- os.exit(1)
- end
- local dict_str = dict_file:read("*all")
- dict_file:close()
- -- In your lua program, you should pass in adler32 as a CONSTANT
- -- , so it actually prevent you from modifying dictionary
- -- unintentionally during the program development. I do this
- -- here just because no convenient way to verify in commandline.
- dictionary = LibDeflate:CreateDictionary(dict_str,
- #dict_str, LibDeflate:Adler32(dict_str))
- elseif a == "--strategy" then
- -- Not sure if I should check error here
- -- If I do, redudant code.
- i = i + 1
- strategy = arg[i]
- elseif a == "--zlib" then
- is_zlib = true
- elseif a:find("^%-") then
- io.stderr:write(("LibDeflate: Invalid argument: %s")
- :format(a))
- os.exit(1)
- else
- if not input then
- input, status = io.open(a, "rb")
- if not input then
- io.stderr:write(
- ("LibDeflate: Cannot read the file '%s': %s")
- :format(a, tostring(status)))
- os.exit(1)
- end
- elseif not output then
- output, status = io.open(a, "wb")
- if not output then
- io.stderr:write(
- ("LibDeflate: Cannot write the file '%s': %s")
- :format(a, tostring(status)))
- os.exit(1)
- end
- end
- end
- i = i + 1
- end -- while (arg[i])
-
- if not input or not output then
- io.stderr:write("LibDeflate:"
- .." You must specify both input and output files.")
- os.exit(1)
- end
-
- local input_data = input:read("*all")
- local configs = {
- level = level,
- strategy = strategy,
- }
- local output_data
- if not is_decompress then
- if not is_zlib then
- if not dictionary then
- output_data =
- LibDeflate:CompressDeflate(input_data, configs)
- else
- output_data =
- LibDeflate:CompressDeflateWithDict(input_data, dictionary
- , configs)
- end
- else
- if not dictionary then
- output_data =
- LibDeflate:CompressZlib(input_data, configs)
- else
- output_data =
- LibDeflate:CompressZlibWithDict(input_data, dictionary
- , configs)
- end
- end
- else
- if not is_zlib then
- if not dictionary then
- output_data = LibDeflate:DecompressDeflate(input_data)
- else
- output_data = LibDeflate:DecompressDeflateWithDict(
- input_data, dictionary)
- end
- else
- if not dictionary then
- output_data = LibDeflate:DecompressZlib(input_data)
- else
- output_data = LibDeflate:DecompressZlibWithDict(
- input_data, dictionary)
- end
- end
- end
-
- if not output_data then
- io.stderr:write("LibDeflate: Decompress fails.")
- os.exit(1)
- end
-
- output:write(output_data)
- if input and input ~= io.stdin then
- input:close()
- end
- if output and output ~= io.stdout then
- output:close()
- end
-
- io.stderr:write(("Successfully writes %d bytes"):format(
- output_data:len()))
- os.exit(0)
- end
+ local io = io
+ local os = os
+ local debug = debug
+ local arg = _G.arg
+ local debug_info = debug.getinfo(1)
+ if debug_info.source == arg[0] or debug_info.short_src == arg[0] then
+ -- We are indeed runnning THIS file from the commandline.
+ local input
+ local output
+ local i = 1
+ local status
+ local is_zlib = false
+ local is_decompress = false
+ local level
+ local strategy
+ local dictionary
+ while (arg[i]) do
+ local a = arg[i]
+ if a == "-h" then
+ print(LibDeflate._COPYRIGHT ..
+ "\nUsage: lua LibDeflate.lua [OPTION] [INPUT] [OUTPUT]\n" ..
+ " -0 store only. no compression.\n" ..
+ " -1 fastest compression.\n" ..
+ " -9 slowest and best compression.\n" ..
+ " -d do decompression instead of compression.\n" ..
+ " --dict specify the file that contains" ..
+ " the entire preset dictionary.\n" ..
+ " -h give this help.\n" ..
+ " --strategy " ..
+ " specify a special compression strategy.\n" ..
+ " -v print the version and copyright info.\n" ..
+ " --zlib use zlib format instead of raw deflate.\n")
+ os.exit(0)
+ elseif a == "-v" then
+ print(LibDeflate._COPYRIGHT)
+ os.exit(0)
+ elseif a:find("^%-[0-9]$") then
+ level = tonumber(a:sub(2, 2))
+ elseif a == "-d" then
+ is_decompress = true
+ elseif a == "--dict" then
+ i = i + 1
+ local dict_filename = arg[i]
+ if not dict_filename then
+ io.stderr:write("You must speicify the dict filename")
+ os.exit(1)
+ end
+ local dict_file, dict_status = io.open(dict_filename, "rb")
+ if not dict_file then
+ io.stderr:write(
+ ("LibDeflate: Cannot read the dictionary file '%s': %s"):format(
+ dict_filename, dict_status))
+ os.exit(1)
+ end
+ local dict_str = dict_file:read("*all")
+ dict_file:close()
+ -- In your lua program, you should pass in adler32 as a CONSTANT
+ -- , so it actually prevent you from modifying dictionary
+ -- unintentionally during the program development. I do this
+ -- here just because no convenient way to verify in commandline.
+ dictionary = LibDeflate:CreateDictionary(dict_str, #dict_str,
+ LibDeflate:Adler32(dict_str))
+ elseif a == "--strategy" then
+ -- Not sure if I should check error here
+ -- If I do, redudant code.
+ i = i + 1
+ strategy = arg[i]
+ elseif a == "--zlib" then
+ is_zlib = true
+ elseif a:find("^%-") then
+ io.stderr:write(("LibDeflate: Invalid argument: %s"):format(a))
+ os.exit(1)
+ else
+ if not input then
+ input, status = io.open(a, "rb")
+ if not input then
+ io.stderr:write(
+ ("LibDeflate: Cannot read the file '%s': %s"):format(a, tostring(
+ status)))
+ os.exit(1)
+ end
+ elseif not output then
+ output, status = io.open(a, "wb")
+ if not output then
+ io.stderr:write(
+ ("LibDeflate: Cannot write the file '%s': %s"):format(a, tostring(
+ status)))
+ os.exit(1)
+ end
+ end
+ end
+ i = i + 1
+ end -- while (arg[i])
+
+ if not input or not output then
+ io.stderr:write("LibDeflate:" ..
+ " You must specify both input and output files.")
+ os.exit(1)
+ end
+
+ local input_data = input:read("*all")
+ local configs = {level = level, strategy = strategy}
+ local output_data
+ if not is_decompress then
+ if not is_zlib then
+ if not dictionary then
+ output_data = LibDeflate:CompressDeflate(input_data, configs)
+ else
+ output_data = LibDeflate:CompressDeflateWithDict(input_data,
+ dictionary, configs)
+ end
+ else
+ if not dictionary then
+ output_data = LibDeflate:CompressZlib(input_data, configs)
+ else
+ output_data = LibDeflate:CompressZlibWithDict(input_data, dictionary,
+ configs)
+ end
+ end
+ else
+ if not is_zlib then
+ if not dictionary then
+ output_data = LibDeflate:DecompressDeflate(input_data)
+ else
+ output_data = LibDeflate:DecompressDeflateWithDict(input_data,
+ dictionary)
+ end
+ else
+ if not dictionary then
+ output_data = LibDeflate:DecompressZlib(input_data)
+ else
+ output_data =
+ LibDeflate:DecompressZlibWithDict(input_data, dictionary)
+ end
+ end
+ end
+
+ if not output_data then
+ io.stderr:write("LibDeflate: Decompress fails.")
+ os.exit(1)
+ end
+
+ output:write(output_data)
+ if input and input ~= io.stdin then input:close() end
+ if output and output ~= io.stdout then output:close() end
+
+ io.stderr:write(("Successfully writes %d bytes"):format(output_data:len()))
+ os.exit(0)
+ end
end
return LibDeflate
diff --git a/Tukui/Libs/LibDeflate/LibDeflate.toc b/Tukui/Libs/LibDeflate/LibDeflate.toc
deleted file mode 100644
index b8729a74..00000000
--- a/Tukui/Libs/LibDeflate/LibDeflate.toc
+++ /dev/null
@@ -1,11 +0,0 @@
-## Interface: 80300
-## Title: Lib: LibDeflate
-## Notes: Compressor and decompressor with high compression ratio using DEFLATE/zlib format.
-## Author: Haoqian He (WoW: Safetyy at Illidan-US (Horde))
-## Version: 1.0.2-release
-## X-Website: https://wow.curseforge.com/projects/libdeflate
-## X-Category: Library
-## X-License: zlib
-
-LibStub\LibStub.lua
-lib.xml
diff --git a/Tukui/Libs/LibDeflate/LibStub/LibStub.lua b/Tukui/Libs/LibDeflate/LibStub/LibStub.lua
deleted file mode 100644
index cf5c8429..00000000
--- a/Tukui/Libs/LibDeflate/LibStub/LibStub.lua
+++ /dev/null
@@ -1,51 +0,0 @@
--- $Id: LibStub.lua 103 2014-10-16 03:02:50Z mikk $
--- LibStub is a simple versioning stub meant for use in Libraries. http://www.wowace.com/addons/libstub/ for more info
--- LibStub is hereby placed in the Public Domain
--- Credits: Kaelten, Cladhaire, ckknight, Mikk, Ammo, Nevcairiel, joshborke
-local LIBSTUB_MAJOR, LIBSTUB_MINOR = "LibStub", 2 -- NEVER MAKE THIS AN SVN REVISION! IT NEEDS TO BE USABLE IN ALL REPOS!
-local LibStub = _G[LIBSTUB_MAJOR]
-
--- Check to see is this version of the stub is obsolete
-if not LibStub or LibStub.minor < LIBSTUB_MINOR then
- LibStub = LibStub or {libs = {}, minors = {} }
- _G[LIBSTUB_MAJOR] = LibStub
- LibStub.minor = LIBSTUB_MINOR
-
- -- LibStub:NewLibrary(major, minor)
- -- major (string) - the major version of the library
- -- minor (string or number ) - the minor version of the library
- --
- -- returns nil if a newer or same version of the lib is already present
- -- returns empty library object or old library object if upgrade is needed
- function LibStub:NewLibrary(major, minor)
- assert(type(major) == "string", "Bad argument #2 to `NewLibrary' (string expected)")
- minor = assert(tonumber(strmatch(minor, "%d+")), "Minor version must either be a number or contain a number.")
-
- local oldminor = self.minors[major]
- if oldminor and oldminor >= minor then return nil end
- self.minors[major], self.libs[major] = minor, self.libs[major] or {}
- return self.libs[major], oldminor
- end
-
- -- LibStub:GetLibrary(major, [silent])
- -- major (string) - the major version of the library
- -- silent (boolean) - if true, library is optional, silently return nil if its not found
- --
- -- throws an error if the library can not be found (except silent is set)
- -- returns the library object if found
- function LibStub:GetLibrary(major, silent)
- if not self.libs[major] and not silent then
- error(("Cannot find a library instance of %q."):format(tostring(major)), 2)
- end
- return self.libs[major], self.minors[major]
- end
-
- -- LibStub:IterateLibraries()
- --
- -- Returns an iterator for the currently registered libraries
- function LibStub:IterateLibraries()
- return pairs(self.libs)
- end
-
- setmetatable(LibStub, { __call = LibStub.GetLibrary })
-end
diff --git a/Tukui/Libs/LibDeflate/LibStub/LibStub.toc b/Tukui/Libs/LibDeflate/LibStub/LibStub.toc
deleted file mode 100644
index 92e164f6..00000000
--- a/Tukui/Libs/LibDeflate/LibStub/LibStub.toc
+++ /dev/null
@@ -1,9 +0,0 @@
-## Interface: 70000
-## Title: Lib: LibStub
-## Notes: Universal Library Stub
-## Credits: Kaelten, Cladhaire, ckknight, Mikk, Ammo, Nevcairiel
-## X-Website: http://www.wowace.com/addons/libstub/
-## X-Category: Library
-## X-License: Public Domain
-
-LibStub.lua
diff --git a/Tukui/Libs/LibDeflate/LibStub/tests/test.lua b/Tukui/Libs/LibDeflate/LibStub/tests/test.lua
deleted file mode 100644
index 276ddabb..00000000
--- a/Tukui/Libs/LibDeflate/LibStub/tests/test.lua
+++ /dev/null
@@ -1,41 +0,0 @@
-debugstack = debug.traceback
-strmatch = string.match
-
-loadfile("../LibStub.lua")()
-
-local lib, oldMinor = LibStub:NewLibrary("Pants", 1) -- make a new thingy
-assert(lib) -- should return the library table
-assert(not oldMinor) -- should not return the old minor, since it didn't exist
-
--- the following is to create data and then be able to check if the same data exists after the fact
-function lib:MyMethod()
-end
-local MyMethod = lib.MyMethod
-lib.MyTable = {}
-local MyTable = lib.MyTable
-
-local newLib, newOldMinor = LibStub:NewLibrary("Pants", 1) -- try to register a library with the same version, should silently fail
-assert(not newLib) -- should not return since out of date
-
-local newLib, newOldMinor = LibStub:NewLibrary("Pants", 0) -- try to register a library with a previous, should silently fail
-assert(not newLib) -- should not return since out of date
-
-local newLib, newOldMinor = LibStub:NewLibrary("Pants", 2) -- register a new version
-assert(newLib) -- library table
-assert(rawequal(newLib, lib)) -- should be the same reference as the previous
-assert(newOldMinor == 1) -- should return the minor version of the previous version
-
-assert(rawequal(lib.MyMethod, MyMethod)) -- verify that values were saved
-assert(rawequal(lib.MyTable, MyTable)) -- verify that values were saved
-
-local newLib, newOldMinor = LibStub:NewLibrary("Pants", "Blah 3 Blah") -- register a new version with a string minor version (instead of a number)
-assert(newLib) -- library table
-assert(newOldMinor == 2) -- previous version was 2
-
-local newLib, newOldMinor = LibStub:NewLibrary("Pants", "Blah 4 and please ignore 15 Blah") -- register a new version with a string minor version (instead of a number)
-assert(newLib)
-assert(newOldMinor == 3) -- previous version was 3 (even though it gave a string)
-
-local newLib, newOldMinor = LibStub:NewLibrary("Pants", 5) -- register a new library, using a normal number instead of a string
-assert(newLib)
-assert(newOldMinor == 4) -- previous version was 4 (even though it gave a string)
\ No newline at end of file
diff --git a/Tukui/Libs/LibDeflate/LibStub/tests/test2.lua b/Tukui/Libs/LibDeflate/LibStub/tests/test2.lua
deleted file mode 100644
index eae71720..00000000
--- a/Tukui/Libs/LibDeflate/LibStub/tests/test2.lua
+++ /dev/null
@@ -1,27 +0,0 @@
-debugstack = debug.traceback
-strmatch = string.match
-
-loadfile("../LibStub.lua")()
-
-for major, library in LibStub:IterateLibraries() do
- -- check that MyLib doesn't exist yet, by iterating through all the libraries
- assert(major ~= "MyLib")
-end
-
-assert(not LibStub:GetLibrary("MyLib", true)) -- check that MyLib doesn't exist yet by direct checking
-assert(not pcall(LibStub.GetLibrary, LibStub, "MyLib")) -- don't silently fail, thus it should raise an error.
-local lib = LibStub:NewLibrary("MyLib", 1) -- create the lib
-assert(lib) -- check it exists
-assert(rawequal(LibStub:GetLibrary("MyLib"), lib)) -- verify that :GetLibrary("MyLib") properly equals the lib reference
-
-assert(LibStub:NewLibrary("MyLib", 2)) -- create a new version
-
-local count=0
-for major, library in LibStub:IterateLibraries() do
- -- check that MyLib exists somewhere in the libraries, by iterating through all the libraries
- if major == "MyLib" then -- we found it!
- count = count +1
- assert(rawequal(library, lib)) -- verify that the references are equal
- end
-end
-assert(count == 1) -- verify that we actually found it, and only once
diff --git a/Tukui/Libs/LibDeflate/LibStub/tests/test3.lua b/Tukui/Libs/LibDeflate/LibStub/tests/test3.lua
deleted file mode 100644
index 30f7b941..00000000
--- a/Tukui/Libs/LibDeflate/LibStub/tests/test3.lua
+++ /dev/null
@@ -1,14 +0,0 @@
-debugstack = debug.traceback
-strmatch = string.match
-
-loadfile("../LibStub.lua")()
-
-local proxy = newproxy() -- non-string
-
-assert(not pcall(LibStub.NewLibrary, LibStub, proxy, 1)) -- should error, proxy is not a string, it's userdata
-local success, ret = pcall(LibStub.GetLibrary, proxy, true)
-assert(not success or not ret) -- either error because proxy is not a string or because it's not actually registered.
-
-assert(not pcall(LibStub.NewLibrary, LibStub, "Something", "No number in here")) -- should error, minor has no string in it.
-
-assert(not LibStub:GetLibrary("Something", true)) -- shouldn't've created it from the above statement
\ No newline at end of file
diff --git a/Tukui/Libs/LibDeflate/LibStub/tests/test4.lua b/Tukui/Libs/LibDeflate/LibStub/tests/test4.lua
deleted file mode 100644
index 43eb3380..00000000
--- a/Tukui/Libs/LibDeflate/LibStub/tests/test4.lua
+++ /dev/null
@@ -1,41 +0,0 @@
-debugstack = debug.traceback
-strmatch = string.match
-
-loadfile("../LibStub.lua")()
-
-
--- Pretend like loaded libstub is old and doesn't have :IterateLibraries
-assert(LibStub.minor)
-LibStub.minor = LibStub.minor - 0.0001
-LibStub.IterateLibraries = nil
-
-loadfile("../LibStub.lua")()
-
-assert(type(LibStub.IterateLibraries)=="function")
-
-
--- Now pretend that we're the same version -- :IterateLibraries should NOT be re-created
-LibStub.IterateLibraries = 123
-
-loadfile("../LibStub.lua")()
-
-assert(LibStub.IterateLibraries == 123)
-
-
--- Now pretend that a newer version is loaded -- :IterateLibraries should NOT be re-created
-LibStub.minor = LibStub.minor + 0.0001
-
-loadfile("../LibStub.lua")()
-
-assert(LibStub.IterateLibraries == 123)
-
-
--- Again with a huge number
-LibStub.minor = LibStub.minor + 1234567890
-
-loadfile("../LibStub.lua")()
-
-assert(LibStub.IterateLibraries == 123)
-
-
-print("OK")
\ No newline at end of file
diff --git a/Tukui/Libs/LibDeflate/README.md b/Tukui/Libs/LibDeflate/README.md
deleted file mode 100644
index b6d4bfe2..00000000
--- a/Tukui/Libs/LibDeflate/README.md
+++ /dev/null
@@ -1,207 +0,0 @@
-[![Build Status](https://www.travis-ci.org/SafeteeWoW/LibDeflate.svg?branch=master)](https://www.travis-ci.org/SafeteeWoW/LibDeflate)
-[![Build status](https://ci.appveyor.com/api/projects/status/owdccv4jrc0g1s2x/branch/master?svg=true&passingText=Windows%20Build%20passing&failingText=Windows%20Build%20failing)](https://ci.appveyor.com/project/SafeteeWoW/libdeflate/branch/master)
-[![AppVeyor tests branch](https://img.shields.io/appveyor/tests/SafeteeWoW/LibDeflate/master.svg)](https://ci.appveyor.com/project/SafeteeWoW/libdeflate/branch/master)
-[![codecov.io](http://codecov.io/github/safeteeWoW/LibDeflate/branch/master/graphs/badge.svg)](http://codecov.io/github/safeteeWoW/LibDeflate)
-[![license](https://img.shields.io/github/license/SafeteeWoW/LibDeflate)](LICENSE.txt)
-[![LuaRocks](https://img.shields.io/luarocks/v/SafeteeWoW/libdeflate)](http://luarocks.org/modules/SafeteeWoW/libdeflate)
-[![GitHub issues](https://img.shields.io/github/issues/SafeteeWoW/LibDeflate)](https://github.com/SafeteeWoW/LibDeflate/issues)
-
-# LibDeflate
-## Pure Lua compressor and decompressor with high compression ratio using DEFLATE/zlib format.
-
-Copyright (C) 2018-2020 Haoqian He
-
-## Introduction
-LibDeflate is pure Lua compressor and decompressor with high compression ratio,
-which compresses almost as good as [zlib](https://github.com/madler/zlib). The
-purpose of this project is to give a reasonable good compression when you only
-have access to a pure Lua environment, without accessing to Lua C bindings or
-any external Lua libraries. LibDeflate does not have any dependencies except you
-need to have a working Lua interpreter.
-
-LibDeflate uses the following compression formats:
-1. *DEFLATE*, as defined by the specification
-[RFC1951](https://tools.ietf.org/html/rfc1951). DEFLATE is the default compression method of ZIP.
-2. *zlib*, as defined by the specification
-[RFC1950](https://tools.ietf.org/html/rfc1950).
-zlib format uses DEFLATE formats to compress data and adds several bytes as
-headers and checksum.
-
-A simple C program utilizing [zlib](https://github.com/madler/zlib) should be
-compatible with LibDeflate. If you are not sure how to write this program,
-goto the [zlib](https://github.com/madler/zlib) repository, or read
-[tests/zdeflate.c](https://github.com/SafeteeWoW/LibDeflate/blob/master/tests/zdeflate.c) in this repository.
-
-## Supported Lua Versions
-LibDeflate supports and is fully tested under Lua 5.1/5.2/5.3/5.4, LuaJIT 2.0/2.1,
-for Linux, MaxOS and Windows. Click the Travis CI(Linux/MaxOS) and
-Appveyor(Windows) badge on the top of this README for the test results. Click
-the CodeCov badge to see the test coverage (should be 100%).
-Note at the time of this release, Lua 5.4 final is not released yet.
-For Lua 5.4, This library is tested with its rc6 version.
-
-## Documentation
-[Documentation](https://safeteewow.github.io/LibDeflate/source/LibDeflate.lua.html) is hosted on Github.
-Beside run as a library, LibDeflate can also be run directly in commmandline.
-See the documentation for detail.
-
-## Limitation
-Though many performance optimization has been done in the source code, as a
-pure Lua implementation, the compression speed of LibDeflate is significantly
-slower than a C compressor. LibDeflate aims to compress small files, and it is
-suggested to not compress files with the order of several Megabytes. If you
-need to compress files hundreds of MetaBytes, please use a C compressor, or a
-Lua compressor with C binding.
-
-## Performance
-Below is a simple benchmark compared with another pure Lua compressor [LibCompress](https://www.wowace.com/projects/libcompress).
-More benchmarks can be viewed in the [documentation](https://safeteewow.github.io/LibDeflate/topics/benchmark.md.html).
-
-+ Interpreter: Lua 5.1.5
-+ Input data: [WeakAuras2 String](https://raw.githubusercontent.com/SafeteeWoW/LibDeflate/master/tests/data/warlockWeakAuras.txt), Size: 132462 bytes
-
-
-
-
-
-
LibDeflate
-
LibDeflate
-
LibDeflate
-
LibCompress
-
LibCompress
-
LibCompress
-
-
-
-
-
-
CompressDeflate Level 1
-
CompressDeflate Level 5
-
CompressDeflate Level 8
-
Compress
-
CompressLZW
-
CompressHuffman
-
-
-
compress ratio
-
3.15
-
3.68
-
3.71
-
1.36
-
1.20
-
1.36
-
-
-
compress time(ms)
-
68
-
116
-
189
-
111
-
52
-
50
-
-
-
decompress time(ms)
-
48
-
30
-
27
-
55
-
26
-
59
-
-
-
compress+decompress time(ms)
-
116
-
145
-
216
-
166
-
78
-
109
-
-
-
-
-
-LibDeflate with compression level 1 compresses as fast as LibCompress, but already produces significantly smaller data than LibCompress. High compression level takes a bit more time to get better compression.
-
-## Download And Install
-
-+ The [official repository](https://github.com/SafeteeWoW/LibDeflate) locates on Github.
-[LibDeflate.lua](https://github.com/SafeteeWoW/LibDeflate/blob/master/LibDeflate.lua) is the only file of LibDeflate. Copy the file
-to your LUA_PATH to install it.
-
-+ To download as a World of Warcraft library, goto [LibDeflate Curseforge Page](https://wow.curseforge.com/projects/libdeflate) or [LibDeflate WoWInterface Page](https://www.wowinterface.com/downloads/info25453-LibDeflate.html)
-
-+ You can also install via Luarocks using the command "luarocks install libdeflate"
-
-+ All packages files can also in downloaded in the [Github Release Page](https://github.com/SafeteeWoW/LibDeflate/releases)
-
-+ To use after installation, ```require("LibDeflate")``` (case sensitive) in your Lua interpreter,
-or ```LibStub:GetLibrary("LibDeflate")``` (case sensitive) for World of Warcraft.
-
-
-## Usage
-```
-local LibDeflate
-if LibStub then -- You are using LibDeflate as WoW addon
- LibDeflate = LibStub:GetLibrary("LibDeflate")
-else
- LibDeflate = require("LibDeflate")
-end
-
-local example_input = "12123123412345123456123456712345678123456789"
-
---- Compress using raw deflate format
-local compress_deflate = LibDeflate:CompressDeflate(example_input)
-
--- decompress
-local decompress_deflate = LibDeflate:DecompressDeflate(compress_deflate)
-
--- Check if the first return value of DecompressXXXX is non-nil to know if the
--- decompression succeeds.
-if decompress_deflate == nil then
- error("Decompression fails.")
-else
- -- Decompression succeeds.
- assert(example_input == decompress_deflate)
-end
-
-
--- To transmit through WoW addon channel, data must be encoded so NULL ("\000")
--- is not in the data.
-local data_to_trasmit_WoW_addon = LibDeflate:EncodeForWoWAddonChannel(
- compress_deflate)
--- When the receiver gets the data, decoded it first.
-local data_decoded_WoW_addon = LibDeflate:DecodeForWoWAddonChannel(
- data_to_trasmit_WoW_addon)
--- Then decomrpess it
-local decompress_deflate = LibDeflate:DecompressDeflate(data_decoded_WoW_addon)
-
-assert(decompress_deflate == example_input)
-
--- The compressed output is not printable. EncodeForPrint will convert to
--- a printable format, in case you want to export to the user to
--- copy and paste. This encoding will make the data 25% bigger.
-local printable_compressed = LibDeflate:EncodeForPrint(compress_deflate)
-
--- DecodeForPrint to convert back.
--- DecodeForPrint will remove prefixed and trailing control or space characters
--- in the string before decode it.
-assert(LibDeflate:DecodeForPrint(printable_compressed) == compress_deflate)
-```
-See Full examples in [examples/example.lua](https://github.com/SafeteeWoW/LibDeflate/blob/master/examples/example.lua)
-
-## License
-LibDeflate is licensed under the zlib license. See LICENSE.txt
-
-## Credits and Disclaimer
-
-The following projects are used to the help to test the correctness
-of this program. The code of the main program (LibDeflate.lua) does not
-use their code directly, but uses their ideas and algorithms. Their original
-licenses shall be comply when used.
-
-1. [zlib](http://www.zlib.net), by Jean-loup Gailly (compression) and Mark Adler (decompression). Licensed under [zlib License](http://www.zlib.net/zlib_license.html).
-2. [puff](https://github.com/madler/zlib/tree/master/contrib/puff), by Mark Adler. Licensed under zlib License.
-3. [LibCompress](https://www.wowace.com/projects/libcompress), by jjsheets and Galmok of European Stormrage (Horde). Licensed under GPLv2.
-4. [WeakAuras2](https://github.com/WeakAuras/WeakAuras2). Licensed under GPLv2.
\ No newline at end of file
diff --git a/Tukui/Libs/LibDeflate/changelog.md b/Tukui/Libs/LibDeflate/changelog.md
deleted file mode 100644
index caaf357a..00000000
--- a/Tukui/Libs/LibDeflate/changelog.md
+++ /dev/null
@@ -1,55 +0,0 @@
-### v1.0.2-release
-
-* Change the license to the zlib license (Formerly LGPLv3). This license is more permissive than LGPLv3.
-* Increase compression speed by up to 25% on high compression level on non-JIT lua interpreter.
-* Bump the World of Warcraft toc version to 80300
-
-### v1.0.1-release
-
-* 2019/11/18
-* No functional change
-* Bump the World of Warcraft toc version to 80205
-* No longer "Load on Demand" in Warcraft toc, because this library does not consume much memory. This makes easier to load and test this library.
-* Change the license to LGPLv3 (Formerly GPLv3)
-
-### v1.0.0-release
-
-* 2018/7/30
-* Documentation updates.
-
-### v0.9.0-beta4
-
-* 2018/5/25
-* "DecodeForPrint" always remove prefixed or trailing control or space characters before decoding. This makes this API easier to use.
-
-### v0.9.0-beta3
-
-* 2018/5/23
-* Fix an issue in "DecodeForPrint" that certain undecodable string
- could cause an Lua error.
-* Add an parameter to "DecodeForPrint". If set, remove trailing spaces in the
-input string before decode it.
-* Add input type checks for all encode/decode functions.
-
-### v0.9.0-beta2
-
-* 2018/5/22
-* API "Encode6Bit" is renamed to "EncodeForPrint"
-* API "Decode6Bit" is renamed to "DecodeForPrint"
-
-### v0.9.0-beta1
-
-* 2018/5/22
-* No change
-
-### v0.9.0-alpha2
-
-* 2018/5/21
-* Remove API LibDeflate:VerifyDictionary
-* Remove API LibDeflate:DictForWoW
-* Changed API LibDeflate:CreateDictionary
-
-### v0.9.0-alpha1
-
-* 2018/5/20
-* The first working version.
diff --git a/Tukui/Libs/LibDeflate/docs/README.md b/Tukui/Libs/LibDeflate/docs/README.md
deleted file mode 100644
index 96acf7d0..00000000
--- a/Tukui/Libs/LibDeflate/docs/README.md
+++ /dev/null
@@ -1,8 +0,0 @@
-# Generate documentation
-
-The documentation is written inside several markdown files and in the source code of .lua
-
-Steps:
-
-1. ensure "ldoc" has been installed. Install by "luarocks install ldoc"
-2. in this folder ("docs" folder in LibDeflate source tree), run "ldoc ."
diff --git a/Tukui/Libs/LibDeflate/docs/benchmark.md b/Tukui/Libs/LibDeflate/docs/benchmark.md
deleted file mode 100644
index 1940b381..00000000
--- a/Tukui/Libs/LibDeflate/docs/benchmark.md
+++ /dev/null
@@ -1,279 +0,0 @@
-# Performance Benchmark
-
-+ Operating System: Windows 10 version 1909 (Build 18363)
-+ Lua Interpreters:
- + Lua 5.1.5
- + LuaJIT 2.0.5
-+ CPU: Intel Core i7-7700K@4.2 GHz
-
----
-
-+ For LibDeflate, `CompressDeflate` is used for all compressions in this benchmark, `DecompressDeflate` is used for decompression. Different compression level configurations (Level 1, Level 5 and Level 8) are used.
-
-+ For LibCompress, `Compress`, `CompressLZW`, `CompressHuffman` are used for
-compression. `Decompress` is used to decompress all compression results.
-`Compress` runs both CompressLZW and CompressHuffman and pick the smallest result.
-
----
-
-+ Interpreter: Lua 5.1.5
-+ Input data: [WeakAuras2 String](https://raw.githubusercontent.com/SafeteeWoW/LibDeflate/master/tests/data/warlockWeakAuras.txt), Size: 132462 bytes
-
-
---[[
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU Lesser General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU Lesser General Public License for more details.
-
-You should have received a copy of the GNU Lesser General Public License
-along with this program. If not, see https://www.gnu.org/licenses/.
---]]
-
---- LibDeflate usage example
--- @author Haoqian He
--- @file example.lua
-
-local LibDeflate
-
-if LibStub then-- You are using LibDeflate as WoW addon
- LibDeflate = LibStub:GetLibrary("LibDeflate")
-else
- -- You are using LibDeflate as Lua library.
--- Setup the path to locate LibDeflate.lua,
--- if 'require("LibDeflate")' fails, for example:
--- package.path = ("?.lua;../?.lua;")..(package.path or "")
- LibDeflate = require("LibDeflate")
-end
-
-local example_input = "12123123412345123456123456712345678123456789"
-
--- Compress using raw deflate format
-local compress_deflate = LibDeflate:CompressDeflate(example_input)
-
--- decompress
-local decompress_deflate = LibDeflate:DecompressDeflate(compress_deflate)
--- Check if the first return value of DecompressXXXX is non-nil to know if the
--- decompression succeeds.
-if decompress_deflate == nilthen
- error("Decompression fails.")
-else
- -- Decompression succeeds.
-assert(example_input == decompress_deflate)
-end
-
-
--- If it is to transmit through WoW addon channel,
--- compressed data must be encoded so NULL ("\000") is not transmitted.
-local data_to_trasmit_WoW_addon = LibDeflate:EncodeForWoWAddonChannel(
- compress_deflate)
--- When the receiver gets the data, decoded it first.
-local data_decoded_WoW_addon = LibDeflate:DecodeForWoWAddonChannel(
- data_to_trasmit_WoW_addon)
--- Then decomrpess it
-assert(LibDeflate:DecompressDeflate(data_decoded_WoW_addon) == example_input)
-
--- The compressed output is not printable. EncodeForPrint will convert to
--- a printable format, in case you want to export to the user to
--- copy and paste. This encoding will make the data 25% bigger.
-local printable_compressed = LibDeflate:EncodeForPrint(compress_deflate)
-
--- DecodeForPrint to convert back.
--- DecodeForPrint will remove prefixed and trailing control or space characters
--- in the string before decode it.
-assert(LibDeflate:DecodeForPrint(printable_compressed) == compress_deflate)
-
-
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
-
---- Compress and decompress using zlib format
-local compress_zlib = LibDeflate:CompressZlib(example_input)
-local decompress_zlib = LibDeflate:DecompressZlib(compress_zlib)
-assert(decompress_zlib == example_input)
-
---- Control the compression level
--- NOTE: High compression level does not make a difference here,
--- because the input data is very small
-local compress_deflate_with_level = LibDeflate:CompressDeflate(example_input
- , {level = 9})
-local decompress_deflate_with_level = LibDeflate:DecompressDeflate(
- compress_deflate_with_level)
-assert(decompress_deflate_with_level == example_input)
-
-
--- Compress with a preset dictionary
-local dict_str = "121231234"-- example preset dictionary string.
--- print(LibDeflate:Adler32(dict_str), #dict_str)
--- 9 147325380
--- hardcode the print result above, the ensure it is not modified
--- accidenttaly during the program development.
---
--- WARNING: The compressor and decompressor must use the same dictionary.
--- You should be aware of this when tranmitting compressed data over the
--- internet.
-local dict = LibDeflate:CreateDictionary(dict_str, 9, 147325380)
-
--- Using the dictionary with raw deflate format
-local compress_deflate_with_dict = LibDeflate:CompressDeflateWithDict(
- example_input, dict)
-assert(#compress_deflate_with_dict < #compress_deflate)
-local decompress_deflate_with_dict = LibDeflate:DecompressDeflateWithDict(
- compress_deflate_with_dict, dict)
-assert(decompress_deflate_with_dict == example_input)
-
--- Using the dictionary with zlib format, specifying compression level
-local compress_zlib_with_dict = LibDeflate:CompressZlibWithDict(
- example_input, dict, {level = 9})
-assert(#compress_zlib_with_dict < #compress_zlib)
-local decompress_zlib_with_dict = LibDeflate:DecompressZlibWithDict(
- compress_zlib_with_dict, dict)
-assert(decompress_zlib_with_dict == example_input)
-
-
-
-
-
-generated by LDoc 1.4.6
-Last updated 2020-06-26 22:05:55
-
LibDeflate 1.0.2-release
-Pure Lua compressor and decompressor with high compression ratio using
-DEFLATE/zlib format.
-
-
-
-
Info:
-
-
Copyright: LibDeflate <2018-2020> Haoqian He
-
License: zlib License
-
-
This library is implemented according to the following specifications.
-Report a bug if LibDeflate is not fully compliant with those specs.
-Both compressors and decompressors have been implemented in the library.
-1. RFC1950: DEFLATE Compressed Data Format Specification version 1.3
-https://tools.ietf.org/html/rfc1951
-2. RFC1951: ZLIB Compressed Data Format Specification version 3.3
-https://tools.ietf.org/html/rfc1950
-
-
This library requires Lua 5.1/5.2/5.3/5.4 interpreter or LuaJIT v2.0+.
-This library does not have any dependencies.
-Note at the time of this release, Lua 5.4 final is not released yet.
-For Lua 5.4, This library is tested with its rc6 version.
-
-This file "LibDeflate.lua" is the only source file of
-the library.
-Submit suggestions or report bugs to
-https://github.com/safeteeWow/LibDeflate/issues
-
Author: Haoqian He (Github: SafeteeWoW; World of Warcraft: Safetyy-Illidan(US))
The description to compression configuration table.
-
-
-
-
-
-
-
-
Functions
-
-
-
-
- LibDeflate:Adler32 (str)
-
-
- Calculate the Adler-32 checksum of the string.
- See RFC1950 Page 9 https://tools.ietf.org/html/rfc1950 for the
- definition of Adler-32 checksum.
-
-
-
Parameters:
-
-
str
- [string] the input string to calcuate its Adler-32 checksum.
-
-
-
-
Returns:
-
-
- [integer] The Adler-32 checksum, which is greater or equal to 0,
- and less than 2^32 (4294967296).
-
-
-
-
-
-
-
-
- LibDeflate:CompressDeflate (str, configs)
-
-
- Compress using the raw deflate format.
-
-
-
Parameters:
-
-
str
- [string] The data to be compressed.
-
-
configs
- [table/nil] The configuration table to control the compression
- . If nil, use the default configuration.
-
-
-
-
Returns:
-
-
- [string] The compressed data.
-
- [integer] The number of bits padded at the end of output.
- 0 <= bits < 8
- This means the most significant "bits" of the last byte of the returned
- compressed data are padding bits and they don't affect decompression.
- You don't need to use this value unless you want to do some postprocessing
- to the compressed data.
- Compress using the raw deflate format with a preset dictionary.
-
-
-
Parameters:
-
-
str
- [string] The data to be compressed.
-
-
dictionary
- [table] The preset dictionary produced by
- LibDeflate:CreateDictionary
-
-
configs
- [table/nil] The configuration table to control the compression
- . If nil, use the default configuration.
-
-
-
-
Returns:
-
-
- [string] The compressed data.
-
- [integer] The number of bits padded at the end of output.
- 0 <= bits < 8
- This means the most significant "bits" of the last byte of the returned
- compressed data are padding bits and they don't affect decompression.
- You don't need to use this value unless you want to do some postprocessing
- to the compressed data.
- Create a custom codec with encoder and decoder.
- This codec is used to convert an input string to make it not contain
- some specific bytes.
- This created codec and the parameters of this function do NOT take
- localization into account. One byte (0-255) in the string is exactly one
- character (0-255).
- Credits to LibCompress.
-
-
-
Parameters:
-
-
reserved_chars
- [string] The created encoder will ensure encoded
- data does not contain any single character in reserved_chars. This parameter
- should be non-empty.
-
-
escape_chars
- [string] The escape character(s) used in the created
- codec. The codec converts any character included in reserved_chars /
- escape_chars / map_chars to (one escape char + one character not in
- reserved_chars / escape_chars / map_chars).
- You usually only need to provide a length-1 string for this parameter.
- Length-2 string is only needed when
- reserved_chars + escape_chars + map_chars is longer than 127.
- This parameter should be non-empty.
-
-
map_chars
- [string] The created encoder will map every
- reserved_chars:sub(i, i) (1 <= i <= #map_chars) to map_chars:sub(i, i).
- This parameter CAN be empty string.
-
-
-
-
Returns:
-
-
- [table/nil] If the codec cannot be created, return nil.
- If the codec can be created according to the given
- parameters, return the codec, which is a encode/decode table.
- The table contains two functions:
- t:Encode(str) returns the encoded string.
- t:Decode(str) returns the decoded string if succeeds. nil if fails.
-
- [nil/string] If the codec is successfully created, return nil.
- If not, return a string that describes the reason why the codec cannot be
- created.
-
-
-
-
-
Usage:
-
-
-- Create an encoder/decoder that maps all "\000" to "\003",
--- and escape "\001" (and "\002" and "\003") properly
-local codec = LibDeflate:CreateCodec("\000\001", "\002", "\003")
-
-local encoded = codec:Encode(SOME_STRING)
--- "encoded" does not contain "\000" or "\001"
-local decoded = codec:Decode(encoded)
--- assert(decoded == SOME_STRING)
This function is not fast, and the memory consumption of the produced
- dictionary is about 50 times of the input string. Therefore, it is suggestted
- to run this function only once in your program.
-
-
It is very important to know that if you do use a preset dictionary,
- compressors and decompressors MUST USE THE SAME dictionary. That is,
- dictionary must be created using the same string. If you update your program
- with a new dictionary, people with the old version won't be able to transmit
- data with people with the new version. Therefore, changing the dictionary
- must be very careful.
-
-
The parameters "strlen" and "adler32" add a layer of verification to ensure
- the parameter "str" is not modified unintentionally during the program
- development.
-
-
-
Parameters:
-
-
str
- [string] The string used as the preset dictionary.
- You should put stuffs that frequently appears in the dictionary
- string and preferablely put more frequently appeared stuffs toward the end
- of the string.
- Empty string and string longer than 32768 bytes are not allowed.
-
-
strlen
- [integer] The length of 'str'. Please pass in this parameter
- as a hardcoded constant, in order to verify the content of 'str'. The value
- of this parameter should be known before your program runs.
-
-
adler32
- [integer] The Adler-32 checksum of 'str'. Please pass in this
- parameter as a hardcoded constant, in order to verify the content of 'str'.
- The value of this parameter should be known before your program runs.
-
-
-
-
Returns:
-
-
- [table] The dictionary used for preset dictionary compression and
- decompression.
-
-
-
Raises:
- error if 'strlen' does not match the length of 'str',
- or if 'adler32' does not match the Adler-32 checksum of 'str'.
-
-
-
Usage:
-
-
local dict_str = "1234567890"
-
--- print(dict_str:len(), LibDeflate:Adler32(dict_str))
--- Hardcode the print result below to verify it to avoid acciently
--- modification of 'str' during the program development.
--- string length: 10, Adler-32: 187433486,
--- Don't calculate string length and its Adler-32 at run-time.
-
-local dict = LibDeflate:CreateDictionary(dict_str, 10, 187433486)
-
-
-
-
-
- LibDeflate:DecodeForPrint (str)
-
-
- Decode the printable string produced by LibDeflate:EncodeForPrint.
- "str" will have its prefixed and trailing control characters or space
- removed before it is decoded, so it is easier to use if "str" comes form
- user copy and paste with some prefixed or trailing spaces.
- Then decode fails if the string contains any characters cant be produced by
- LibDeflate:EncodeForPrint. That means, decode fails if the string contains a
- characters NOT one of 26 lowercase letters, 26 uppercase letters,
- 10 numbers digits, left parenthese, or right parenthese.
-
-
-
Parameters:
-
-
str
- [string] The string to be decoded
-
-
-
-
Returns:
-
-
- [string/nil] The decoded string if succeeds. nil if fails.
-
-
-
-
-
-
-
-
- LibDeflate:DecodeForWoWAddonChannel (str)
-
-
- Decode the string produced by LibDeflate:EncodeForWoWAddonChannel
-
-
-
Parameters:
-
-
str
- [string] The string to be decoded.
-
-
-
-
Returns:
-
-
- [string/nil] The decoded string if succeeds. nil if fails.
-
-
-
-
- [string/nil] If the decompression succeeds, return the decompressed
- data. If the decompression fails, return nil. You should check if this return
- value is non-nil to know if the decompression succeeds.
-
- [integer] If the decompression succeeds, return the number of
- unprocessed bytes in the input compressed data. This return value is a
- positive integer if the input data is a valid compressed data appended by an
- arbitary non-empty string. This return value is 0 if the input data does not
- contain any extra bytes.
- If the decompression fails (The first return value of this function is nil),
- this return value is undefined.
- Decompress a raw deflate compressed data with a preset dictionary.
-
-
-
Parameters:
-
-
str
- [string] The data to be decompressed.
-
-
dictionary
- [table] The preset dictionary used by
- LibDeflate:CompressDeflateWithDict when the compressed data is produced.
- Decompression and compression must use the same dictionary.
- Otherwise wrong decompressed data could be produced without generating any
- error.
-
-
-
-
Returns:
-
-
- [string/nil] If the decompression succeeds, return the decompressed
- data. If the decompression fails, return nil. You should check if this return
- value is non-nil to know if the decompression succeeds.
-
- [integer] If the decompression succeeds, return the number of
- unprocessed bytes in the input compressed data. This return value is a
- positive integer if the input data is a valid compressed data appended by an
- arbitary non-empty string. This return value is 0 if the input data does not
- contain any extra bytes.
- If the decompression fails (The first return value of this function is nil),
- this return value is undefined.
- [string/nil] If the decompression succeeds, return the decompressed
- data. If the decompression fails, return nil. You should check if this return
- value is non-nil to know if the decompression succeeds.
-
- [integer] If the decompression succeeds, return the number of
- unprocessed bytes in the input compressed data. This return value is a
- positive integer if the input data is a valid compressed data appended by an
- arbitary non-empty string. This return value is 0 if the input data does not
- contain any extra bytes.
- If the decompression fails (The first return value of this function is nil),
- this return value is undefined.
- Decompress a zlib compressed data with a preset dictionary.
-
-
-
Parameters:
-
-
str
- [string] The data to be decompressed
-
-
dictionary
- [table] The preset dictionary used by
- LibDeflate:CompressDeflateWithDict when the compressed data is produced.
- Decompression and compression must use the same dictionary.
- Otherwise wrong decompressed data could be produced without generating any
- error.
-
-
-
-
Returns:
-
-
- [string/nil] If the decompression succeeds, return the decompressed
- data. If the decompression fails, return nil. You should check if this return
- value is non-nil to know if the decompression succeeds.
-
- [integer] If the decompression succeeds, return the number of
- unprocessed bytes in the input compressed data. This return value is a
- positive integer if the input data is a valid compressed data appended by an
- arbitary non-empty string. This return value is 0 if the input data does not
- contain any extra bytes.
- If the decompression fails (The first return value of this function is nil),
- this return value is undefined.
Credis to WeakAuras2, this function is equivalant to the implementation
- it is using right now.
- The encoded string will be 25% larger than the origin string. However, every
- single byte of the encoded string will be one of 64 printable ASCII
- characters, which are can be easier copied, pasted and displayed.
- (26 lowercase letters, 26 uppercase letters, 10 numbers digits,
- left parenthese, or right parenthese)
-
-
-
Parameters:
-
-
str
- [string] The string to be encoded.
-
-
-
-
Returns:
-
-
- [string] The encoded string.
-
-
-
-
-
-
-
-
- LibDeflate:EncodeForWoWAddonChannel (str)
-
-
- Encode the string to make it ready to be transmitted in World of
- Warcraft addon channel.
- The encoded string is guaranteed to contain no NULL ("\000") character.
-
-
-
- Encode the string to make it ready to be transmitted in World of
- Warcraft chat channel.
- See also https://wow.gamepedia.com/ValidChatMessageCharacters
-
-
-
lua LibDeflate.lua [OPTION] [INPUT] [OUTPUT]
--0 store only. no compression.
--1 fastest compression.
--9 slowest and best compression.
--d do decompression instead of compression.
---dict <filename> specify the file that contains
-he entire preset dictionary.
--h give this help.
---strategy <fixed/huffman_only/dynamic> specify a special compression strategy.
--v print the version and copyright info.
---zlib use zlib format instead of raw deflate.
-
-
-
-
-
- compression_configs
-
-
- The description to compression configuration table.
- Any field can be nil to use its default.
- Table with keys other than those below is an invalid table.
-
-
-
Fields:
-
-
level
- The compression level ranged from 0 to 9. 0 is no compression.
- 9 is the slowest but best compression. Use nil for default level.
-
-
strategy
- The compression strategy. "fixed" to only use fixed deflate
- compression block. "dynamic" to only use dynamic block. "huffman_only" to
- do no LZ77 compression. Only do huffman compression.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-generated by LDoc 1.4.6
-Last updated 2020-06-26 22:05:55
-
Operating System: Windows 10 version 1909 (Build 18363)
-
Lua Interpreters:
-
Lua 5.1.5
-
LuaJIT 2.0.5
-
CPU: Intel Core i7-7700K@4.2 GHz
-
-
-
-
-
-
For LibDeflate, CompressDeflate is used for all compressions in this benchmark, DecompressDeflate is used for decompression. Different compression level configurations (Level 1, Level 5 and Level 8) are used.
-
For LibCompress, Compress, CompressLZW, CompressHuffman are used for
- compression. Decompress is used to decompress all compression results.
- Compress runs both CompressLZW and CompressHuffman and pick the smallest result.
Pure Lua compressor and decompressor with high compression ratio using DEFLATE/zlib format.
-
-
Copyright (C) 2018-2019 Haoqian He
-
-
-
Introduction
-
LibDeflate is pure Lua compressor and decompressor with high compression ratio,
-which compresses almost as good as zlib. The
-purpose of this project is to give a reasonable good compression when you only
-have access to a pure Lua environment, without accessing to Lua C bindings or
-any external Lua libraries. LibDeflate does not have any dependencies except you
-need to have a working Lua interpreter.
-
-
LibDeflate uses the following compression formats:
-1. DEFLATE, as defined by the specification
-RFC1951. DEFLATE is the default compression method of ZIP.
-2. zlib, as defined by the specification
-RFC1950.
-zlib format uses DEFLATE formats to compress data and adds several bytes as
-headers and checksum.
-
-
A simple C program utilizing zlib should be
-compatible with LibDeflate. If you are not sure how to write this program,
-goto the zlib repository, or read
-tests/zdeflate.c in this repository.
-
-
-
Supported Lua Versions
-
LibDeflate supports and is fully tested under Lua 5.1/5.2/5.3/5.4, LuaJIT 2.0/2.1,
-for Linux, MaxOS and Windows. Click the Travis CI(Linux/MaxOS) and
-Appveyor(Windows) badge on the top of this README for the test results. Click
-the CodeCov badge to see the test coverage (should be 100%).
-Note at the time of this release, Lua 5.4 final is not released yet.
-For Lua 5.4, This library is tested with its first beta version.
-
-
-
Documentation
-
Documentation is hosted on Github.
-Beside run as a library, LibDeflate can also be run directly in commmandline.
-See the documentation for detail.
-
-
-
Limitation
-
Though many performance optimization has been done in the source code, as a
-pure Lua implementation, the compression speed of LibDeflate is significantly
-slower than a C compressor. LibDeflate aims to compress small files, and it is
-suggested to not compress files with the order of several Megabytes. If you
-need to compress files hundreds of MetaBytes, please use a C compressor, or a
-Lua compressor with C binding.
-
-
-
Performance
-
Below is a simple benchmark compared with another pure Lua compressor LibCompress.
-More benchmarks can be viewed in the documentation.
LibDeflate with compression level 1 compresses as fast as LibCompress, but already produces significantly smaller data than LibCompress. High compression level takes a bit more time to get better compression.
-
-
-
Download And Install
-
-
-
The official repository locates on Github.
- LibDeflate.lua is the only file of LibDeflate. Copy the file
- to your LUA_PATH to install it.
You can also install via Luarocks using the command "luarocks install libdeflate"
-
To use after installation, <code>require("LibDeflate")</code> (case sensitive) in your Lua interpreter,
- or <code>LibStub:GetLibrary("LibDeflate")</code> (case sensitive) for World of Warcraft.
-
-
-
-
-
Usage
-
local LibDeflate
- if LibStub then -- You are using LibDeflate as WoW addon
- LibDeflate = LibStub:GetLibrary("LibDeflate")
- else
- LibDeflate = require("LibDeflate")
- end
-
- local example_input = "12123123412345123456123456712345678123456789"
-
- --- Compress using raw deflate format
- local compress_deflate = LibDeflate:CompressDeflate(example_input)
-
- -- decompress
- local decompress_deflate = LibDeflate:DecompressDeflate(compress_deflate)
-
- -- Check if the first return value of DecompressXXXX is non-nil to know if the
- -- decompression succeeds.
- if decompress_deflate == nil then
- error("Decompression fails.")
- else
- -- Decompression succeeds.
- assert(example_input == decompress_deflate)
- end
-
-
- -- To transmit through WoW addon channel, data must be encoded so NULL ("\000")
- -- is not in the data.
- local data_to_trasmit_WoW_addon = LibDeflate:EncodeForWoWAddonChannel(
- compress_deflate)
- -- When the receiver gets the data, decoded it first.
- local data_decoded_WoW_addon = LibDeflate:DecodeForWoWAddonChannel(
- data_to_trasmit_WoW_addon)
- -- Then decomrpess it
- local decompress_deflate = LibDeflate:DecompressDeflate(data_decoded_WoW_addon)
-
- assert(decompress_deflate == example_input)
-
- -- The compressed output is not printable. EncodeForPrint will convert to
- -- a printable format, in case you want to export to the user to
- -- copy and paste. This encoding will make the data 25% bigger.
- local printable_compressed = LibDeflate:EncodeForPrint(compress_deflate)
-
- -- DecodeForPrint to convert back.
- -- DecodeForPrint will remove prefixed and trailing control or space characters
- -- in the string before decode it.
- assert(LibDeflate:DecodeForPrint(printable_compressed) == compress_deflate)
-
LibDeflate is licensed under GNU Lesser General Public License Version 3 or later.
-
-
-
Credits and Disclaimer
-
-
The following projects are used to the help to test the correctness
-of this program. The code of the main program (LibDeflate.lua) does not
-use their code directly, but uses their ideas and algorithms. Their original
-licenses shall be comply when used.
-
-
-
zlib, by Jean-loup Gailly (compression) and Mark Adler (decompression). Licensed under zlib License.