mirror of
https://github.com/0x5eal/luau-unzip.git
synced 2025-04-10 17:20:53 +01:00
fix: avoid duplicate directory entries with trailing slash
Fixed a bug in the directory tree builder where for directories there would be two entries, where one would have a trailing slash, and the other wouldn't. The directory without the trailing slash would get linked to its children in the entries lookup table, while the one with the trailing slash would exist as a "ghost directory" with no children. The fix involved sorting the entries to first handle directories, and linking to the existing parent directory entries for children.
This commit is contained in:
parent
7724af0467
commit
ccc7228278
1 changed files with 53 additions and 35 deletions
|
@ -165,10 +165,9 @@ function ZipReader.parseCentralDirectory(self: ZipReader): ()
|
||||||
local crc = buffer.readu32(self.data, pos + 16)
|
local crc = buffer.readu32(self.data, pos + 16)
|
||||||
local size = buffer.readu32(self.data, pos + 24)
|
local size = buffer.readu32(self.data, pos + 24)
|
||||||
local offset = buffer.readu32(self.data, pos + 42)
|
local offset = buffer.readu32(self.data, pos + 42)
|
||||||
|
local name = buffer.readstring(self.data, pos + 46, nameLength)
|
||||||
|
|
||||||
local nameBuffer = buffer.create(nameLength)
|
print("got name:", name)
|
||||||
buffer.copy(nameBuffer, 0, self.data, pos + 46, nameLength)
|
|
||||||
local name = buffer.tostring(nameBuffer)
|
|
||||||
|
|
||||||
local entry = ZipEntry.new(name, size, offset, timestamp, crc)
|
local entry = ZipEntry.new(name, size, offset, timestamp, crc)
|
||||||
table.insert(self.entries, entry)
|
table.insert(self.entries, entry)
|
||||||
|
@ -178,43 +177,62 @@ function ZipReader.parseCentralDirectory(self: ZipReader): ()
|
||||||
end
|
end
|
||||||
|
|
||||||
function ZipReader.buildDirectoryTree(self: ZipReader): ()
|
function ZipReader.buildDirectoryTree(self: ZipReader): ()
|
||||||
for _, entry in self.entries do
|
-- Sort entries to process directories first; I could either handle
|
||||||
local parts = {}
|
-- directories and files in separate passes over the entries, or sort
|
||||||
-- Split entry path into individual components
|
-- the entries so I handled the directories first -- I decided to do
|
||||||
-- e.g. "folder/subfolder/file.txt" -> {"folder", "subfolder", "file.txt"}
|
-- the latter
|
||||||
for part in string.gmatch(entry.name, "([^/]+)/?") do
|
table.sort(self.entries, function(a, b)
|
||||||
table.insert(parts, part)
|
if a.isDirectory ~= b.isDirectory then
|
||||||
end
|
return a.isDirectory
|
||||||
|
end
|
||||||
|
return a.name < b.name
|
||||||
|
end)
|
||||||
|
|
||||||
-- Start from root directory
|
for _, entry in self.entries do
|
||||||
local current = self.root
|
local parts = {}
|
||||||
local path = ""
|
-- Split entry path into individual components
|
||||||
|
-- e.g. "folder/subfolder/file.txt" -> {"folder", "subfolder", "file.txt"}
|
||||||
|
for part in string.gmatch(entry.name, "([^/]+)/?") do
|
||||||
|
table.insert(parts, part)
|
||||||
|
end
|
||||||
|
|
||||||
-- Process each path component
|
-- Start from root directory
|
||||||
for i, part in parts do
|
local current = self.root
|
||||||
path ..= part
|
local path = ""
|
||||||
if i < #parts then
|
|
||||||
-- Create missing directory entries for intermediate paths
|
|
||||||
if not self.directories[path] then
|
|
||||||
local dir = ZipEntry.new(path, 0, 0, entry.timestamp, 0)
|
|
||||||
dir.isDirectory = true
|
|
||||||
dir.parent = current
|
|
||||||
|
|
||||||
-- Track directory in both lookup table and parent's children
|
-- Process each path component
|
||||||
self.directories[path] = dir
|
for i, part in parts do
|
||||||
table.insert(current.children, dir)
|
path ..= part
|
||||||
end
|
|
||||||
|
|
||||||
-- Move deeper into the tree
|
if i < #parts or entry.isDirectory then
|
||||||
current = self.directories[path]
|
-- Create missing directory entries for intermediate paths
|
||||||
continue
|
if not self.directories[path] then
|
||||||
end
|
if entry.isDirectory and i == #parts then
|
||||||
|
-- Existing directory entry, reuse it
|
||||||
|
self.directories[path] = entry
|
||||||
|
else
|
||||||
|
-- Create new directory entry for intermediate paths or undefined
|
||||||
|
-- parent directories in the ZIP
|
||||||
|
local dir = ZipEntry.new(path .. "/", 0, 0, entry.timestamp, 0)
|
||||||
|
dir.isDirectory = true
|
||||||
|
dir.parent = current
|
||||||
|
self.directories[path] = dir
|
||||||
|
end
|
||||||
|
|
||||||
-- Link file entry to its parent directory
|
-- Track directory in both lookup table and parent's children
|
||||||
entry.parent = current
|
table.insert(current.children, self.directories[path])
|
||||||
table.insert(current.children, entry)
|
end
|
||||||
end
|
|
||||||
end
|
-- Move deeper into the tree
|
||||||
|
current = self.directories[path]
|
||||||
|
continue
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Link file entry to its parent directory
|
||||||
|
entry.parent = current
|
||||||
|
table.insert(current.children, entry)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function ZipReader.findEntry(self: ZipReader, path: string): ZipEntry
|
function ZipReader.findEntry(self: ZipReader, path: string): ZipEntry
|
||||||
|
|
Loading…
Add table
Reference in a new issue