p[2] then
- c =s-th-(progress-p[2])/(p[3]-p[2])*(s-th)
- elseif progress>p[1] then
- c =s-th
- else
- c = (progress-p[0])/(p[1]-p[0])*(s-th)
- end
- return math.floor(c+0.5)
-end
-
-local pCalc2 = function(progress,s,th,p)
- local c
- if progress>p[3] then
- c = s-th-(progress-p[3])/(p[0]+1-p[3])*(s-th)
- elseif progress>p[2] then
- c = s-th
- elseif progress>p[1] then
- c = (progress-p[1])/(p[2]-p[1])*(s-th)
- elseif progress>p[0] then
- c = 0
- else
- c = s-th-(progress+1-p[3])/(p[0]+1-p[3])*(s-th)
- end
- return math.floor(c+0.5)
-end
-
-local pUpdate = function(self,elapsed)
- self.timer = self.timer+elapsed/self.info.period
- if self.timer>1 or self.timer <-1 then
- self.timer = self.timer%1
- end
- local progress = self.timer
- local width,height = self:GetSize()
- if width ~= self.info.width or height ~= self.info.height then
- local perimeter = 2*(width+height)
- if not (perimeter>0) then
- return
- end
- self.info.width = width
- self.info.height = height
- self.info.pTLx = {
- [0] = (height+self.info.length/2)/perimeter,
- [1] = (height+width+self.info.length/2)/perimeter,
- [2] = (2*height+width-self.info.length/2)/perimeter,
- [3] = 1-self.info.length/2/perimeter
- }
- self.info.pTLy ={
- [0] = (height-self.info.length/2)/perimeter,
- [1] = (height+width+self.info.length/2)/perimeter,
- [2] = (height*2+width+self.info.length/2)/perimeter,
- [3] = 1-self.info.length/2/perimeter
- }
- self.info.pBRx ={
- [0] = self.info.length/2/perimeter,
- [1] = (height-self.info.length/2)/perimeter,
- [2] = (height+width-self.info.length/2)/perimeter,
- [3] = (height*2+width+self.info.length/2)/perimeter
- }
- self.info.pBRy ={
- [0] = self.info.length/2/perimeter,
- [1] = (height+self.info.length/2)/perimeter,
- [2] = (height+width-self.info.length/2)/perimeter,
- [3] = (height*2+width-self.info.length/2)/perimeter
- }
- end
- if self:IsShown() then
- if not (self.masks[1]:IsShown()) then
- self.masks[1]:Show()
- self.masks[1]:SetPoint("TOPLEFT",self,"TOPLEFT",self.info.th,-self.info.th)
- self.masks[1]:SetPoint("BOTTOMRIGHT",self,"BOTTOMRIGHT",-self.info.th,self.info.th)
- end
- if self.masks[2] and not(self.masks[2]:IsShown()) then
- self.masks[2]:Show()
- self.masks[2]:SetPoint("TOPLEFT",self,"TOPLEFT",self.info.th+1,-self.info.th-1)
- self.masks[2]:SetPoint("BOTTOMRIGHT",self,"BOTTOMRIGHT",-self.info.th-1,self.info.th+1)
- end
- if self.bg and not(self.bg:IsShown()) then
- self.bg:Show()
- end
- for k,line in pairs(self.textures) do
- line:SetPoint("TOPLEFT",self,"TOPLEFT",pCalc1((progress+self.info.step*(k-1))%1,width,self.info.th,self.info.pTLx),-pCalc2((progress+self.info.step*(k-1))%1,height,self.info.th,self.info.pTLy))
- line:SetPoint("BOTTOMRIGHT",self,"TOPLEFT",self.info.th+pCalc2((progress+self.info.step*(k-1))%1,width,self.info.th,self.info.pBRx),-height+pCalc1((progress+self.info.step*(k-1))%1,height,self.info.th,self.info.pBRy))
- end
- end
-end
-
-function lib.PixelGlow_Start(r,color,N,frequency,length,th,xOffset,yOffset,border,key,frameLevel)
- if not r then
- return
- end
- if not color then
- color = {0.95,0.95,0.32,1}
- end
-
- if not(N and N>0) then
- N = 8
- end
-
- local period
- if frequency then
- if not(frequency>0 or frequency<0) then
- period = 4
- else
- period = 1/frequency
- end
- else
- period = 4
- end
- local width,height = r:GetSize()
- length = length or math.floor((width+height)*(2/N-0.1))
- length = min(length,min(width,height))
- th = th or 1
- xOffset = xOffset or 0
- yOffset = yOffset or 0
- key = key or ""
-
- addFrameAndTex(r,color,"_PixelGlow",key,N,xOffset,yOffset,textureList.white,{0,1,0,1},nil,frameLevel)
- local f = r["_PixelGlow"..key]
- if not f.masks then
- f.masks = {}
- end
- if not f.masks[1] then
- f.masks[1] = GlowMaskPool:Acquire()
- f.masks[1]:SetTexture(textureList.empty, "CLAMPTOWHITE","CLAMPTOWHITE")
- f.masks[1]:Show()
- end
- f.masks[1]:SetPoint("TOPLEFT",f,"TOPLEFT",th,-th)
- f.masks[1]:SetPoint("BOTTOMRIGHT",f,"BOTTOMRIGHT",-th,th)
-
- if not(border==false) then
- if not f.masks[2] then
- f.masks[2] = GlowMaskPool:Acquire()
- f.masks[2]:SetTexture(textureList.empty, "CLAMPTOWHITE","CLAMPTOWHITE")
- end
- f.masks[2]:SetPoint("TOPLEFT",f,"TOPLEFT",th+1,-th-1)
- f.masks[2]:SetPoint("BOTTOMRIGHT",f,"BOTTOMRIGHT",-th-1,th+1)
-
- if not f.bg then
- f.bg = GlowTexPool:Acquire()
- f.bg:SetColorTexture(0.1,0.1,0.1,0.8)
- f.bg:SetParent(f)
- f.bg:SetAllPoints(f)
- f.bg:SetDrawLayer("ARTWORK",6)
- f.bg:AddMaskTexture(f.masks[2])
- end
- else
- if f.bg then
- GlowTexPool:Release(f.bg)
- f.bg = nil
- end
- if f.masks[2] then
- GlowMaskPool:Release(f.masks[2])
- f.masks[2] = nil
- end
- end
- for _,tex in pairs(f.textures) do
- if tex:GetNumMaskTextures() < 1 then
- tex:AddMaskTexture(f.masks[1])
- end
- end
- f.timer = f.timer or 0
- f.info = f.info or {}
- f.info.step = 1/N
- f.info.period = period
- f.info.th = th
- if f.info.length ~= length then
- f.info.width = nil
- f.info.length = length
- end
- pUpdate(f, 0)
- f:SetScript("OnUpdate",pUpdate)
-end
-
-function lib.PixelGlow_Stop(r,key)
- if not r then
- return
- end
- key = key or ""
- if not r["_PixelGlow"..key] then
- return false
- else
- GlowFramePool:Release(r["_PixelGlow"..key])
- end
-end
-
-table.insert(lib.glowList, "Pixel Glow")
-lib.startList["Pixel Glow"] = lib.PixelGlow_Start
-lib.stopList["Pixel Glow"] = lib.PixelGlow_Stop
-
-
---Autocast Glow Funcitons--
-local function acUpdate(self,elapsed)
- local width,height = self:GetSize()
- if width ~= self.info.width or height ~= self.info.height then
- if width*height == 0 then return end -- Avoid division by zero
- self.info.width = width
- self.info.height = height
- self.info.perimeter = 2*(width+height)
- self.info.bottomlim = height*2+width
- self.info.rightlim = height+width
- self.info.space = self.info.perimeter/self.info.N
- end
-
- local texIndex = 0;
- for k=1,4 do
- self.timer[k] = self.timer[k]+elapsed/(self.info.period*k)
- if self.timer[k] > 1 or self.timer[k] <-1 then
- self.timer[k] = self.timer[k]%1
- end
- for i = 1,self.info.N do
- texIndex = texIndex+1
- local position = (self.info.space*i+self.info.perimeter*self.timer[k])%self.info.perimeter
- if position>self.info.bottomlim then
- self.textures[texIndex]: SetPoint("CENTER",self,"BOTTOMRIGHT",-position+self.info.bottomlim,0)
- elseif position>self.info.rightlim then
- self.textures[texIndex]: SetPoint("CENTER",self,"TOPRIGHT",0,-position+self.info.rightlim)
- elseif position>self.info.height then
- self.textures[texIndex]: SetPoint("CENTER",self,"TOPLEFT",position-self.info.height,0)
- else
- self.textures[texIndex]: SetPoint("CENTER",self,"BOTTOMLEFT",0,position)
- end
- end
- end
-end
-
-function lib.AutoCastGlow_Start(r,color,N,frequency,scale,xOffset,yOffset,key,frameLevel)
- if not r then
- return
- end
-
- if not color then
- color = {0.95,0.95,0.32,1}
- end
-
- if not(N and N>0) then
- N = 4
- end
-
- local period
- if frequency then
- if not(frequency>0 or frequency<0) then
- period = 8
- else
- period = 1/frequency
- end
- else
- period = 8
- end
- scale = scale or 1
- xOffset = xOffset or 0
- yOffset = yOffset or 0
- key = key or ""
-
- addFrameAndTex(r,color,"_AutoCastGlow",key,N*4,xOffset,yOffset,textureList.shine,shineCoords, true, frameLevel)
- local f = r["_AutoCastGlow"..key]
- local sizes = {7,6,5,4}
- for k,size in pairs(sizes) do
- for i = 1,N do
- f.textures[i+N*(k-1)]:SetSize(size*scale,size*scale)
- end
- end
- f.timer = f.timer or {0,0,0,0}
- f.info = f.info or {}
- f.info.N = N
- f.info.period = period
- f:SetScript("OnUpdate",acUpdate)
-end
-
-function lib.AutoCastGlow_Stop(r,key)
- if not r then
- return
- end
-
- key = key or ""
- if not r["_AutoCastGlow"..key] then
- return false
- else
- GlowFramePool:Release(r["_AutoCastGlow"..key])
- end
-end
-
-table.insert(lib.glowList, "Autocast Shine")
-lib.startList["Autocast Shine"] = lib.AutoCastGlow_Start
-lib.stopList["Autocast Shine"] = lib.AutoCastGlow_Stop
-
---Action Button Glow--
-local function ButtonGlowResetter(framePool,frame)
- frame:SetScript("OnUpdate",nil)
- local parent = frame:GetParent()
- if parent._ButtonGlow then
- parent._ButtonGlow = nil
- end
- frame:Hide()
- frame:ClearAllPoints()
-end
-local ButtonGlowPool = CreateFramePool("Frame",GlowParent,nil,ButtonGlowResetter)
-lib.ButtonGlowPool = ButtonGlowPool
-
-local function CreateScaleAnim(group, target, order, duration, x, y, delay)
- local scale = group:CreateAnimation("Scale")
- scale:SetChildKey(target)
- scale:SetOrder(order)
- scale:SetDuration(duration)
- scale:SetScale(x, y)
-
- if delay then
- scale:SetStartDelay(delay)
- end
-end
-
-local function CreateAlphaAnim(group, target, order, duration, fromAlpha, toAlpha, delay, appear)
- local alpha = group:CreateAnimation("Alpha")
- alpha:SetChildKey(target)
- alpha:SetOrder(order)
- alpha:SetDuration(duration)
- alpha:SetFromAlpha(fromAlpha)
- alpha:SetToAlpha(toAlpha)
- if delay then
- alpha:SetStartDelay(delay)
- end
- if appear then
- table.insert(group.appear, alpha)
- else
- table.insert(group.fade, alpha)
- end
-end
-
-local function AnimIn_OnPlay(group)
- local frame = group:GetParent()
- local frameWidth, frameHeight = frame:GetSize()
- frame.spark:SetSize(frameWidth, frameHeight)
- frame.spark:SetAlpha(not(frame.color) and 1.0 or 0.3*frame.color[4])
- frame.innerGlow:SetSize(frameWidth / 2, frameHeight / 2)
- frame.innerGlow:SetAlpha(not(frame.color) and 1.0 or frame.color[4])
- frame.innerGlowOver:SetAlpha(not(frame.color) and 1.0 or frame.color[4])
- frame.outerGlow:SetSize(frameWidth * 2, frameHeight * 2)
- frame.outerGlow:SetAlpha(not(frame.color) and 1.0 or frame.color[4])
- frame.outerGlowOver:SetAlpha(not(frame.color) and 1.0 or frame.color[4])
- frame.ants:SetSize(frameWidth * 0.85, frameHeight * 0.85)
- frame.ants:SetAlpha(0)
- frame:Show()
-end
-
-local function AnimIn_OnFinished(group)
- local frame = group:GetParent()
- local frameWidth, frameHeight = frame:GetSize()
- frame.spark:SetAlpha(0)
- frame.innerGlow:SetAlpha(0)
- frame.innerGlow:SetSize(frameWidth, frameHeight)
- frame.innerGlowOver:SetAlpha(0.0)
- frame.outerGlow:SetSize(frameWidth, frameHeight)
- frame.outerGlowOver:SetAlpha(0.0)
- frame.outerGlowOver:SetSize(frameWidth, frameHeight)
- frame.ants:SetAlpha(not(frame.color) and 1.0 or frame.color[4])
-end
-
-local function AnimIn_OnStop(group)
- local frame = group:GetParent()
- local frameWidth, frameHeight = frame:GetSize()
- frame.spark:SetAlpha(0)
- frame.innerGlow:SetAlpha(0)
- frame.innerGlowOver:SetAlpha(0.0)
- frame.outerGlowOver:SetAlpha(0.0)
-end
-
-local function bgHide(self)
- if self.animOut:IsPlaying() then
- self.animOut:Stop()
- ButtonGlowPool:Release(self)
- end
-end
-
-local function bgUpdate(self, elapsed)
- AnimateTexCoords(self.ants, 256, 256, 48, 48, 22, elapsed, self.throttle);
- local cooldown = self:GetParent().cooldown;
- if(cooldown and cooldown:IsShown() and cooldown:GetCooldownDuration() > 3000) then
- self:SetAlpha(0.5);
- else
- self:SetAlpha(1.0);
- end
-end
-
-local function configureButtonGlow(f,alpha)
- f.spark = f:CreateTexture(nil, "BACKGROUND")
- f.spark:SetPoint("CENTER")
- f.spark:SetAlpha(0)
- f.spark:SetTexture([[Interface\SpellActivationOverlay\IconAlert]])
- f.spark:SetTexCoord(0.00781250, 0.61718750, 0.00390625, 0.26953125)
-
- -- inner glow
- f.innerGlow = f:CreateTexture(nil, "ARTWORK")
- f.innerGlow:SetPoint("CENTER")
- f.innerGlow:SetAlpha(0)
- f.innerGlow:SetTexture([[Interface\SpellActivationOverlay\IconAlert]])
- f.innerGlow:SetTexCoord(0.00781250, 0.50781250, 0.27734375, 0.52734375)
-
- -- inner glow over
- f.innerGlowOver = f:CreateTexture(nil, "ARTWORK")
- f.innerGlowOver:SetPoint("TOPLEFT", f.innerGlow, "TOPLEFT")
- f.innerGlowOver:SetPoint("BOTTOMRIGHT", f.innerGlow, "BOTTOMRIGHT")
- f.innerGlowOver:SetAlpha(0)
- f.innerGlowOver:SetTexture([[Interface\SpellActivationOverlay\IconAlert]])
- f.innerGlowOver:SetTexCoord(0.00781250, 0.50781250, 0.53515625, 0.78515625)
-
- -- outer glow
- f.outerGlow = f:CreateTexture(nil, "ARTWORK")
- f.outerGlow:SetPoint("CENTER")
- f.outerGlow:SetAlpha(0)
- f.outerGlow:SetTexture([[Interface\SpellActivationOverlay\IconAlert]])
- f.outerGlow:SetTexCoord(0.00781250, 0.50781250, 0.27734375, 0.52734375)
-
- -- outer glow over
- f.outerGlowOver = f:CreateTexture(nil, "ARTWORK")
- f.outerGlowOver:SetPoint("TOPLEFT", f.outerGlow, "TOPLEFT")
- f.outerGlowOver:SetPoint("BOTTOMRIGHT", f.outerGlow, "BOTTOMRIGHT")
- f.outerGlowOver:SetAlpha(0)
- f.outerGlowOver:SetTexture([[Interface\SpellActivationOverlay\IconAlert]])
- f.outerGlowOver:SetTexCoord(0.00781250, 0.50781250, 0.53515625, 0.78515625)
-
- -- ants
- f.ants = f:CreateTexture(nil, "OVERLAY")
- f.ants:SetPoint("CENTER")
- f.ants:SetAlpha(0)
- f.ants:SetTexture([[Interface\SpellActivationOverlay\IconAlertAnts]])
-
- f.animIn = f:CreateAnimationGroup()
- f.animIn.appear = {}
- f.animIn.fade = {}
- CreateScaleAnim(f.animIn, "spark", 1, 0.2, 1.5, 1.5)
- CreateAlphaAnim(f.animIn, "spark", 1, 0.2, 0, alpha, nil, true)
- CreateScaleAnim(f.animIn, "innerGlow", 1, 0.3, 2, 2)
- CreateScaleAnim(f.animIn, "innerGlowOver", 1, 0.3, 2, 2)
- CreateAlphaAnim(f.animIn, "innerGlowOver", 1, 0.3, alpha, 0, nil, false)
- CreateScaleAnim(f.animIn, "outerGlow", 1, 0.3, 0.5, 0.5)
- CreateScaleAnim(f.animIn, "outerGlowOver", 1, 0.3, 0.5, 0.5)
- CreateAlphaAnim(f.animIn, "outerGlowOver", 1, 0.3, alpha, 0, nil, false)
- CreateScaleAnim(f.animIn, "spark", 1, 0.2, 2/3, 2/3, 0.2)
- CreateAlphaAnim(f.animIn, "spark", 1, 0.2, alpha, 0, 0.2, false)
- CreateAlphaAnim(f.animIn, "innerGlow", 1, 0.2, alpha, 0, 0.3, false)
- CreateAlphaAnim(f.animIn, "ants", 1, 0.2, 0, alpha, 0.3, true)
- f.animIn:SetScript("OnPlay", AnimIn_OnPlay)
- f.animIn:SetScript("OnStop", AnimIn_OnStop)
- f.animIn:SetScript("OnFinished", AnimIn_OnFinished)
-
- f.animOut = f:CreateAnimationGroup()
- f.animOut.appear = {}
- f.animOut.fade = {}
- CreateAlphaAnim(f.animOut, "outerGlowOver", 1, 0.2, 0, alpha, nil, true)
- CreateAlphaAnim(f.animOut, "ants", 1, 0.2, alpha, 0, nil, false)
- CreateAlphaAnim(f.animOut, "outerGlowOver", 2, 0.2, alpha, 0, nil, false)
- CreateAlphaAnim(f.animOut, "outerGlow", 2, 0.2, alpha, 0, nil, false)
- f.animOut:SetScript("OnFinished", function(self) ButtonGlowPool:Release(self:GetParent()) end)
-
- f:SetScript("OnHide", bgHide)
-end
-
-local function updateAlphaAnim(f,alpha)
- for _,anim in pairs(f.animIn.appear) do
- anim:SetToAlpha(alpha)
- end
- for _,anim in pairs(f.animIn.fade) do
- anim:SetFromAlpha(alpha)
- end
- for _,anim in pairs(f.animOut.appear) do
- anim:SetToAlpha(alpha)
- end
- for _,anim in pairs(f.animOut.fade) do
- anim:SetFromAlpha(alpha)
- end
-end
-
-local ButtonGlowTextures = {["spark"] = true,["innerGlow"] = true,["innerGlowOver"] = true,["outerGlow"] = true,["outerGlowOver"] = true,["ants"] = true}
-
-function lib.ButtonGlow_Start(r,color,frequency,frameLevel)
- if not r then
- return
- end
- frameLevel = frameLevel or 8;
- local throttle
- if frequency and frequency > 0 then
- throttle = 0.25/frequency*0.01
- else
- throttle = 0.01
- end
- if r._ButtonGlow then
- local f = r._ButtonGlow
- local width,height = r:GetSize()
- f:SetFrameLevel(r:GetFrameLevel()+frameLevel)
- f:SetSize(width*1.4 , height*1.4)
- f:SetPoint("TOPLEFT", r, "TOPLEFT", -width * 0.2, height * 0.2)
- f:SetPoint("BOTTOMRIGHT", r, "BOTTOMRIGHT", width * 0.2, -height * 0.2)
- f.ants:SetSize(width*1.4*0.85, height*1.4*0.85)
- AnimIn_OnFinished(f.animIn)
- if f.animOut:IsPlaying() then
- f.animOut:Stop()
- f.animIn:Play()
- end
-
- if not(color) then
- for texture in pairs(ButtonGlowTextures) do
- f[texture]:SetDesaturated(nil)
- f[texture]:SetVertexColor(1,1,1)
- local alpha = math.min(f[texture]:GetAlpha()/(f.color and f.color[4] or 1), 1)
- f[texture]:SetAlpha(alpha)
- updateAlphaAnim(f, 1)
- end
- f.color = false
- else
- for texture in pairs(ButtonGlowTextures) do
- f[texture]:SetDesaturated(1)
- f[texture]:SetVertexColor(color[1],color[2],color[3])
- local alpha = math.min(f[texture]:GetAlpha()/(f.color and f.color[4] or 1)*color[4], 1)
- f[texture]:SetAlpha(alpha)
- updateAlphaAnim(f,color and color[4] or 1)
- end
- f.color = color
- end
- f.throttle = throttle
- else
- local f, new = ButtonGlowPool:Acquire()
- if new then
- configureButtonGlow(f,color and color[4] or 1)
- else
- updateAlphaAnim(f,color and color[4] or 1)
- end
- r._ButtonGlow = f
- local width,height = r:GetSize()
- f:SetParent(r)
- f:SetFrameLevel(r:GetFrameLevel()+frameLevel)
- f:SetSize(width * 1.4, height * 1.4)
- f:SetPoint("TOPLEFT", r, "TOPLEFT", -width * 0.2, height * 0.2)
- f:SetPoint("BOTTOMRIGHT", r, "BOTTOMRIGHT", width * 0.2, -height * 0.2)
- if not(color) then
- f.color = false
- for texture in pairs(ButtonGlowTextures) do
- f[texture]:SetDesaturated(nil)
- f[texture]:SetVertexColor(1,1,1)
- end
- else
- f.color = color
- for texture in pairs(ButtonGlowTextures) do
- f[texture]:SetDesaturated(1)
- f[texture]:SetVertexColor(color[1],color[2],color[3])
- end
- end
- f.throttle = throttle
- f:SetScript("OnUpdate", bgUpdate)
-
- f.animIn:Play()
-
- if Masque and Masque.UpdateSpellAlert and (not r.overlay or not issecurevariable(r, "overlay")) then
- local old_overlay = r.overlay
- r.overlay = f
- Masque:UpdateSpellAlert(r)
- r.overlay = old_overlay
- end
- end
-end
-
-function lib.ButtonGlow_Stop(r)
- if r._ButtonGlow then
- if r._ButtonGlow.animIn:IsPlaying() then
- r._ButtonGlow.animIn:Stop()
- ButtonGlowPool:Release(r._ButtonGlow)
- elseif r:IsVisible() then
- r._ButtonGlow.animOut:Play()
- else
- ButtonGlowPool:Release(r._ButtonGlow)
- end
- end
-end
-
-table.insert(lib.glowList, "Action Button Glow")
-lib.startList["Action Button Glow"] = lib.ButtonGlow_Start
-lib.stopList["Action Button Glow"] = lib.ButtonGlow_Stop
-
-
--- ProcGlow
-
-local function ProcGlowResetter(framePool, frame)
- frame:Hide()
- frame:ClearAllPoints()
- frame:SetScript("OnShow", nil)
- frame:SetScript("OnHide", nil)
- local parent = frame:GetParent()
- if frame.key and parent[frame.key] then
- parent[frame.key] = nil
- end
-end
-
-local ProcGlowPool = CreateFramePool("Frame", GlowParent, nil, ProcGlowResetter)
-lib.ProcGlowPool = ProcGlowPool
-
-local function InitProcGlow(f)
- f.ProcStart = f:CreateTexture(nil, "ARTWORK")
- f.ProcStart:SetBlendMode("ADD")
- f.ProcStart:SetAtlas("UI-HUD-ActionBar-Proc-Start-Flipbook")
- f.ProcStart:SetAlpha(1)
- f.ProcStart:SetSize(150, 150)
- f.ProcStart:SetPoint("CENTER")
-
- f.ProcLoop = f:CreateTexture(nil, "ARTWORK")
- f.ProcLoop:SetAtlas("UI-HUD-ActionBar-Proc-Loop-Flipbook")
- f.ProcLoop:SetAlpha(0)
- f.ProcLoop:SetAllPoints()
-
- f.ProcLoopAnim = f:CreateAnimationGroup()
- f.ProcLoopAnim:SetLooping("REPEAT")
- f.ProcLoopAnim:SetToFinalAlpha(true)
-
- local alphaRepeat = f.ProcLoopAnim:CreateAnimation("Alpha")
- alphaRepeat:SetChildKey("ProcLoop")
- alphaRepeat:SetFromAlpha(1)
- alphaRepeat:SetToAlpha(1)
- alphaRepeat:SetDuration(.001)
- alphaRepeat:SetOrder(0)
- f.ProcLoopAnim.alphaRepeat = alphaRepeat
-
- local flipbookRepeat = f.ProcLoopAnim:CreateAnimation("FlipBook")
- flipbookRepeat:SetChildKey("ProcLoop")
- flipbookRepeat:SetDuration(1)
- flipbookRepeat:SetOrder(1)
- flipbookRepeat:SetFlipBookRows(6)
- flipbookRepeat:SetFlipBookColumns(5)
- flipbookRepeat:SetFlipBookFrames(30)
- flipbookRepeat:SetFlipBookFrameWidth(0)
- flipbookRepeat:SetFlipBookFrameHeight(0)
- f.ProcLoopAnim.flipbookRepeat = flipbookRepeat
-
- f.ProcStartAnim = f:CreateAnimationGroup()
- f.ProcStartAnim:SetToFinalAlpha(true)
-
- local flipbookStartAlphaIn = f.ProcStartAnim:CreateAnimation("Alpha")
- flipbookStartAlphaIn:SetChildKey("ProcStart")
- flipbookStartAlphaIn:SetDuration(.001)
- flipbookStartAlphaIn:SetOrder(0)
- flipbookStartAlphaIn:SetFromAlpha(1)
- flipbookStartAlphaIn:SetToAlpha(1)
-
- local flipbookStart = f.ProcStartAnim:CreateAnimation("FlipBook")
- flipbookStart:SetChildKey("ProcStart")
- flipbookStart:SetDuration(0.7)
- flipbookStart:SetOrder(1)
- flipbookStart:SetFlipBookRows(6)
- flipbookStart:SetFlipBookColumns(5)
- flipbookStart:SetFlipBookFrames(30)
- flipbookStart:SetFlipBookFrameWidth(0)
- flipbookStart:SetFlipBookFrameHeight(0)
-
- local flipbookStartAlphaOut = f.ProcStartAnim:CreateAnimation("Alpha")
- flipbookStartAlphaOut:SetChildKey("ProcStart")
- flipbookStartAlphaOut:SetDuration(.001)
- flipbookStartAlphaOut:SetOrder(2)
- flipbookStartAlphaOut:SetFromAlpha(1)
- flipbookStartAlphaOut:SetToAlpha(0)
-
- f.ProcStartAnim.flipbookStart = flipbookStart
- f.ProcStartAnim:SetScript("OnFinished", function(self)
- self:GetParent().ProcLoopAnim:Play()
- self:GetParent().ProcLoop:Show()
- end)
-
-end
-
-local function SetupProcGlow(f, options)
- f.key = "_ProcGlow" .. options.key -- for resetter
- f:SetScript("OnHide", function(self)
- if self.ProcStartAnim:IsPlaying() then
- self.ProcStartAnim:Stop()
- end
- if self.ProcLoopAnim:IsPlaying() then
- self.ProcLoopAnim:Stop()
- end
- end)
- f:SetScript("OnShow", function(self)
- if self.startAnim then
- if not self.ProcStartAnim:IsPlaying() and not self.ProcLoopAnim:IsPlaying() then
- --[[
-to future me:
-i wish you'r ok, if you wonder where are this constants coming from, check:
-https://github.com/Gethe/wow-ui-source/blob/eb4459c679a1bd8919cad92934ea83c4f5e77e8b/Interface/FrameXML/ActionButton.lua#L816
-https://github.com/Gethe/wow-ui-source/blob/d8e8ebf572c3b28237cf83e8fc5c0583b5453a2b/Interface/FrameXML/ActionButtonTemplate.xml#L5-L14
- ]]
- local width, height = self:GetSize()
- self.ProcStart:SetSize((width / 42 * 150) / 1.4, (height / 42 * 150) / 1.4)
- self.ProcStart:Show()
- self.ProcLoop:Hide()
- self.ProcStartAnim:Play()
- end
- else
- if not self.ProcLoopAnim:IsPlaying() then
- self.ProcStart:Hide()
- self.ProcLoop:Show()
- self.ProcLoopAnim:Play()
- end
- end
- end)
- if not options.color then
- f.ProcStart:SetDesaturated(nil)
- f.ProcStart:SetVertexColor(1, 1, 1, 1)
- f.ProcLoop:SetDesaturated(nil)
- f.ProcLoop:SetVertexColor(1, 1, 1, 1)
- else
- f.ProcStart:SetDesaturated(1)
- f.ProcStart:SetVertexColor(options.color[1], options.color[2], options.color[3], options.color[4])
- f.ProcLoop:SetDesaturated(1)
- f.ProcLoop:SetVertexColor(options.color[1], options.color[2], options.color[3], options.color[4])
- end
- f.ProcLoopAnim.flipbookRepeat:SetDuration(options.duration)
- f.startAnim = options.startAnim
-end
-
-local ProcGlowDefaults = {
- frameLevel = 8,
- color = nil,
- startAnim = true,
- xOffset = 0,
- yOffset = 0,
- duration = 1,
- key = ""
-}
-
-function lib.ProcGlow_Start(r, options)
- if not r then
- return
- end
- options = options or {}
- setmetatable(options, { __index = ProcGlowDefaults })
- local key = "_ProcGlow" .. options.key
- local f, new
- if r[key] then
- f = r[key]
- else
- f, new = ProcGlowPool:Acquire()
- if new then
- InitProcGlow(f)
- end
- r[key] = f
- end
- f:SetParent(r)
- f:SetFrameLevel(r:GetFrameLevel() + options.frameLevel)
-
- local width, height = r:GetSize()
- local xOffset = options.xOffset + width * 0.2
- local yOffset = options.yOffset + height * 0.2
- f:SetPoint("TOPLEFT", r, "TOPLEFT", -xOffset, yOffset)
- f:SetPoint("BOTTOMRIGHT", r, "BOTTOMRIGHT", xOffset, -yOffset)
-
- SetupProcGlow(f, options)
- f:Show()
-end
-
-function lib.ProcGlow_Stop(r, key)
- key = key or ""
- local f = r["_ProcGlow" .. key]
- if f then
- ProcGlowPool:Release(f)
- end
-end
-
-table.insert(lib.glowList, "Proc Glow")
-lib.startList["Proc Glow"] = lib.ProcGlow_Start
-lib.stopList["Proc Glow"] = lib.ProcGlow_Stop
diff --git a/ElvUI_Libraries/Core/LibDataBroker/LibDataBroker-1.1.lua b/ElvUI_Libraries/Core/LibDataBroker/LibDataBroker-1.1.lua
deleted file mode 100644
index f47c0cd73e..0000000000
--- a/ElvUI_Libraries/Core/LibDataBroker/LibDataBroker-1.1.lua
+++ /dev/null
@@ -1,90 +0,0 @@
-
-assert(LibStub, "LibDataBroker-1.1 requires LibStub")
-assert(LibStub:GetLibrary("CallbackHandler-1.0", true), "LibDataBroker-1.1 requires CallbackHandler-1.0")
-
-local lib, oldminor = LibStub:NewLibrary("LibDataBroker-1.1", 4)
-if not lib then return end
-oldminor = oldminor or 0
-
-
-lib.callbacks = lib.callbacks or LibStub:GetLibrary("CallbackHandler-1.0"):New(lib)
-lib.attributestorage, lib.namestorage, lib.proxystorage = lib.attributestorage or {}, lib.namestorage or {}, lib.proxystorage or {}
-local attributestorage, namestorage, callbacks = lib.attributestorage, lib.namestorage, lib.callbacks
-
-if oldminor < 2 then
- lib.domt = {
- __metatable = "access denied",
- __index = function(self, key) return attributestorage[self] and attributestorage[self][key] end,
- }
-end
-
-if oldminor < 3 then
- lib.domt.__newindex = function(self, key, value)
- if not attributestorage[self] then attributestorage[self] = {} end
- if attributestorage[self][key] == value then return end
- attributestorage[self][key] = value
- local name = namestorage[self]
- if not name then return end
- callbacks:Fire("LibDataBroker_AttributeChanged", name, key, value, self)
- callbacks:Fire("LibDataBroker_AttributeChanged_"..name, name, key, value, self)
- callbacks:Fire("LibDataBroker_AttributeChanged_"..name.."_"..key, name, key, value, self)
- callbacks:Fire("LibDataBroker_AttributeChanged__"..key, name, key, value, self)
- end
-end
-
-if oldminor < 2 then
- function lib:NewDataObject(name, dataobj)
- if self.proxystorage[name] then return end
-
- if dataobj then
- assert(type(dataobj) == "table", "Invalid dataobj, must be nil or a table")
- self.attributestorage[dataobj] = {}
- for i,v in pairs(dataobj) do
- self.attributestorage[dataobj][i] = v
- dataobj[i] = nil
- end
- end
- dataobj = setmetatable(dataobj or {}, self.domt)
- self.proxystorage[name], self.namestorage[dataobj] = dataobj, name
- self.callbacks:Fire("LibDataBroker_DataObjectCreated", name, dataobj)
- return dataobj
- end
-end
-
-if oldminor < 1 then
- function lib:DataObjectIterator()
- return pairs(self.proxystorage)
- end
-
- function lib:GetDataObjectByName(dataobjectname)
- return self.proxystorage[dataobjectname]
- end
-
- function lib:GetNameByDataObject(dataobject)
- return self.namestorage[dataobject]
- end
-end
-
-if oldminor < 4 then
- local next = pairs(attributestorage)
- function lib:pairs(dataobject_or_name)
- local t = type(dataobject_or_name)
- assert(t == "string" or t == "table", "Usage: ldb:pairs('dataobjectname') or ldb:pairs(dataobject)")
-
- local dataobj = self.proxystorage[dataobject_or_name] or dataobject_or_name
- assert(attributestorage[dataobj], "Data object not found")
-
- return next, attributestorage[dataobj], nil
- end
-
- local ipairs_iter = ipairs(attributestorage)
- function lib:ipairs(dataobject_or_name)
- local t = type(dataobject_or_name)
- assert(t == "string" or t == "table", "Usage: ldb:ipairs('dataobjectname') or ldb:ipairs(dataobject)")
-
- local dataobj = self.proxystorage[dataobject_or_name] or dataobject_or_name
- assert(attributestorage[dataobj], "Data object not found")
-
- return ipairs_iter, attributestorage[dataobj], 0
- end
-end
diff --git a/ElvUI_Libraries/Core/LibDeflate/LibDeflate.lua b/ElvUI_Libraries/Core/LibDeflate/LibDeflate.lua
index cc00b096d4..02b36ab29a 100644
--- a/ElvUI_Libraries/Core/LibDeflate/LibDeflate.lua
+++ b/ElvUI_Libraries/Core/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
@@ -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
-- 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
--
--- 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