Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: vendor zzlib for unzip #1174

Merged
merged 1 commit into from
Apr 2, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 13 additions & 26 deletions lua/mason-registry/sources/github.lua
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ function GitHubRegistrySource.new(spec)
end

function GitHubRegistrySource:is_installed()
return fs.sync.file_exists(self.data_file)
return fs.sync.file_exists(self.data_file) and fs.sync.file_exists(self.info_file)
end

function GitHubRegistrySource:reload()
Expand Down Expand Up @@ -108,6 +108,8 @@ end

---@async
function GitHubRegistrySource:install()
local zzlib = require "mason-vendor.zzlib"

return Result.try(function(try)
local version = self.spec.version
if self:is_installed() and version ~= nil then
Expand All @@ -132,38 +134,23 @@ function GitHubRegistrySource:install()
log.trace("Resolved latest registry version", self, version)
end

try(fetch(settings.current.github.download_url_template:format(self.spec.repo, version, "registry.json.zip"), {
out_file = path.concat { self.root_dir, "registry.json.zip" },
}):map_err(_.always "Failed to download registry.json.zip."))

platform.when {
unix = function()
try(spawn.unzip({ "-o", "registry.json.zip", cwd = self.root_dir }):map_err(function(err)
return ("Failed to unpack registry contents: %s"):format(err.stderr)
end))
end,
win = function()
local powershell = require "mason-core.managers.powershell"
powershell
.command(
("Microsoft.PowerShell.Archive\\Expand-Archive -Force -Path %q -DestinationPath ."):format "registry.json.zip",
{
cwd = self.root_dir,
}
)
:map_err(function(err)
return ("Failed to unpack registry contents: %s"):format(err.stderr)
end)
end,
}
pcall(fs.async.unlink, path.concat { self.root_dir, "registry.json.zip" })
local zip_buffer = try(
fetch(settings.current.github.download_url_template:format(self.spec.repo, version, "registry.json.zip")):map_err(
_.always "Failed to download registry archive."
)
)
local registry_contents = try(
Result.pcall(zzlib.unzip, zip_buffer, "registry.json")
:map_err(_.always "Failed to unpack registry archive.")
)

local checksums = try(
fetch(settings.current.github.download_url_template:format(self.spec.repo, version, "checksums.txt")):map_err(
_.always "Failed to download checksums.txt."
)
)

try(Result.pcall(fs.async.write_file, self.data_file, registry_contents))
try(Result.pcall(
fs.async.write_file,
self.info_file,
Expand Down
285 changes: 285 additions & 0 deletions lua/mason-vendor/zzlib/inflate-bit32.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,285 @@
-- stylua: ignore start

-- zzlib-bit32 - zlib decompression in Lua - version using bit/bit32 libraries

-- Copyright (c) 2016-2023 Francois Galea <fgalea at free.fr>
-- This program is free software. It comes without any warranty, to
-- the extent permitted by applicable law. You can redistribute it
-- and/or modify it under the terms of the Do What The Fuck You Want
-- To Public License, Version 2, as published by Sam Hocevar. See
-- the COPYING file or http://www.wtfpl.net/ for more details.


local inflate = {}

local bit = bit32 or bit

inflate.band = bit.band
inflate.rshift = bit.rshift

function inflate.bitstream_init(file)
local bs = {
file = file, -- the open file handle
buf = nil, -- character buffer
len = nil, -- length of character buffer
pos = 1, -- position in char buffer, next to be read
b = 0, -- bit buffer
n = 0, -- number of bits in buffer
}
-- get rid of n first bits
function bs:flushb(n)
self.n = self.n - n
self.b = bit.rshift(self.b,n)
end
-- returns the next byte from the stream, excluding any half-read bytes
function bs:next_byte()
if self.pos > self.len then
self.buf = self.file:read(4096)
self.len = self.buf:len()
self.pos = 1
end
local pos = self.pos
self.pos = pos + 1
return self.buf:byte(pos)
end
-- peek a number of n bits from stream
function bs:peekb(n)
while self.n < n do
self.b = self.b + bit.lshift(self:next_byte(),self.n)
self.n = self.n + 8
end
return bit.band(self.b,bit.lshift(1,n)-1)
end
-- get a number of n bits from stream
function bs:getb(n)
local ret = bs:peekb(n)
self.n = self.n - n
self.b = bit.rshift(self.b,n)
return ret
end
-- get next variable-size of maximum size=n element from stream, according to Huffman table
function bs:getv(hufftable,n)
local e = hufftable[bs:peekb(n)]
local len = bit.band(e,15)
local ret = bit.rshift(e,4)
self.n = self.n - len
self.b = bit.rshift(self.b,len)
return ret
end
function bs:close()
if self.file then
self.file:close()
end
end
if type(file) == "string" then
bs.file = nil
bs.buf = file
else
bs.buf = file:read(4096)
end
bs.len = bs.buf:len()
return bs
end

local function hufftable_create(depths)
local nvalues = #depths
local nbits = 1
local bl_count = {}
local next_code = {}
for i=1,nvalues do
local d = depths[i]
if d > nbits then
nbits = d
end
bl_count[d] = (bl_count[d] or 0) + 1
end
local table = {}
local code = 0
bl_count[0] = 0
for i=1,nbits do
code = (code + (bl_count[i-1] or 0)) * 2
next_code[i] = code
end
for i=1,nvalues do
local len = depths[i] or 0
if len > 0 then
local e = (i-1)*16 + len
local code = next_code[len]
local rcode = 0
for j=1,len do
rcode = rcode + bit.lshift(bit.band(1,bit.rshift(code,j-1)),len-j)
end
for j=0,2^nbits-1,2^len do
table[j+rcode] = e
end
next_code[len] = next_code[len] + 1
end
end
return table,nbits
end

local function block_loop(out,bs,nlit,ndist,littable,disttable)
local lit
repeat
lit = bs:getv(littable,nlit)
if lit < 256 then
table.insert(out,lit)
elseif lit > 256 then
local nbits = 0
local size = 3
local dist = 1
if lit < 265 then
size = size + lit - 257
elseif lit < 285 then
nbits = bit.rshift(lit-261,2)
size = size + bit.lshift(bit.band(lit-261,3)+4,nbits)
else
size = 258
end
if nbits > 0 then
size = size + bs:getb(nbits)
end
local v = bs:getv(disttable,ndist)
if v < 4 then
dist = dist + v
else
nbits = bit.rshift(v-2,1)
dist = dist + bit.lshift(bit.band(v,1)+2,nbits)
dist = dist + bs:getb(nbits)
end
local p = #out-dist+1
while size > 0 do
table.insert(out,out[p])
p = p + 1
size = size - 1
end
end
until lit == 256
end

local function block_dynamic(out,bs)
local order = { 17, 18, 19, 1, 9, 8, 10, 7, 11, 6, 12, 5, 13, 4, 14, 3, 15, 2, 16 }
local hlit = 257 + bs:getb(5)
local hdist = 1 + bs:getb(5)
local hclen = 4 + bs:getb(4)
local depths = {}
for i=1,hclen do
local v = bs:getb(3)
depths[order[i]] = v
end
for i=hclen+1,19 do
depths[order[i]] = 0
end
local lengthtable,nlen = hufftable_create(depths)
local i=1
while i<=hlit+hdist do
local v = bs:getv(lengthtable,nlen)
if v < 16 then
depths[i] = v
i = i + 1
elseif v < 19 then
local nbt = {2,3,7}
local nb = nbt[v-15]
local c = 0
local n = 3 + bs:getb(nb)
if v == 16 then
c = depths[i-1]
elseif v == 18 then
n = n + 8
end
for j=1,n do
depths[i] = c
i = i + 1
end
else
error("wrong entry in depth table for literal/length alphabet: "..v);
end
end
local litdepths = {} for i=1,hlit do table.insert(litdepths,depths[i]) end
local littable,nlit = hufftable_create(litdepths)
local distdepths = {} for i=hlit+1,#depths do table.insert(distdepths,depths[i]) end
local disttable,ndist = hufftable_create(distdepths)
block_loop(out,bs,nlit,ndist,littable,disttable)
end

local function block_static(out,bs)
local cnt = { 144, 112, 24, 8 }
local dpt = { 8, 9, 7, 8 }
local depths = {}
for i=1,4 do
local d = dpt[i]
for j=1,cnt[i] do
table.insert(depths,d)
end
end
local littable,nlit = hufftable_create(depths)
depths = {}
for i=1,32 do
depths[i] = 5
end
local disttable,ndist = hufftable_create(depths)
block_loop(out,bs,nlit,ndist,littable,disttable)
end

local function block_uncompressed(out,bs)
bs:flushb(bit.band(bs.n,7))
local len = bs:getb(16)
if bs.n > 0 then
error("Unexpected.. should be zero remaining bits in buffer.")
end
local nlen = bs:getb(16)
if bit.bxor(len,nlen) ~= 65535 then
error("LEN and NLEN don't match")
end
for i=1,len do
table.insert(out,bs:next_byte())
end
end

function inflate.main(bs)
local last,type
local output = {}
repeat
local block
last = bs:getb(1)
type = bs:getb(2)
if type == 0 then
block_uncompressed(output,bs)
elseif type == 1 then
block_static(output,bs)
elseif type == 2 then
block_dynamic(output,bs)
else
error("unsupported block type")
end
until last == 1
bs:flushb(bit.band(bs.n,7))
return output
end

local crc32_table
function inflate.crc32(s,crc)
if not crc32_table then
crc32_table = {}
for i=0,255 do
local r=i
for j=1,8 do
r = bit.bxor(bit.rshift(r,1),bit.band(0xedb88320,bit.bnot(bit.band(r,1)-1)))
end
crc32_table[i] = r
end
end
crc = bit.bnot(crc or 0)
for i=1,#s do
local c = s:byte(i)
crc = bit.bxor(crc32_table[bit.bxor(c,bit.band(crc,0xff))],bit.rshift(crc,8))
end
crc = bit.bnot(crc)
if crc<0 then
-- in Lua < 5.2, sign extension was performed
crc = crc + 4294967296
end
return crc
end

return inflate
Loading