luametalatex/luametalatex-pdfe-deepcopy.lua

91 lines
2.7 KiB
Lua

local format = string.format
local strip_floats = require'luametalatex-pdf-utils'.strip_floats
local pdfe = pdfe
local l = lpeg
local regularchar = 1-l.S'\0\t\n\r\f ()<>[]{}/%#'
local escapednamechar = l.P(1)/function(s)
return format("#%02X")
end
local nameescape = l.Cs(l.Cc'/' * (regularchar + escapednamechar)^0)
local deepcopy_lookup deepcopy_lookup = {
function(_, pdf) -- 1: null
return 'null'
end,
function(_, pdf, b) -- 2: boolean
return b == 1 and 'true' or 'false'
end,
function(_, pdf, i) -- 3: integer
return format("%d", i)
end,
function(_, pdf, f) -- 4: number
return strip_floats(format("%f", f), "%.?0+[ %]]", "")
end,
function(_, pdf, name) -- 5: name
return nameescape:match(name)
end,
function(_, pdf, string, hex) -- 6: string
return hex and format("<%s>", string) or format("(%s)", string)
end,
function(references, pdf, array, size) -- 7: array
local a = {}
for i=1,size do
local type, value, detail = pdfe.getfromarray(array, i)
a[i] = deepcopy_lookup[type](references, pdf, value, detail)
end
return '[' .. table.concat(a, ' ') .. ']'
end,
function(references, pdf, dict, size) -- 8: dict
local a = {}
for i=1,size do
local key, type, value, detail = pdfe.getfromdictionary(dict, i)
a[2*i-1] = nameescape:match(key)
a[2*i] = deepcopy_lookup[type](references, pdf, value, detail)
end
return '<<' .. table.concat(a, ' ') .. '>>'
end,
nil, -- 9: stream (can only appear as a reference
function(references, pdf, ref, num)
local new = references[-num]
if not new then
new = pdf:getobj()
references[-num] = new
references[#references+1] = {ref, num}
end
return format("%i 0 R", new)
end,
}
local references = setmetatable({}, {__index = function(t, n)
local v = {}
t[n] = v
return v
end})
return function(file, id, pdf, type, value, detail)
local references = references[id]
local res = deepcopy_lookup[type](references, pdf, value, detail)
local i, r = 1, references[1]
while r do
local type, value, detail, more = pdfe.getfromreference(r[1])
if type == 9 then
local a,j = {}, 0
for i=1,more do
local key, type, value, detail = pdfe.getfromdictionary(detail, i)
if key == 'Length' then
j=2
else
a[2*i-1-j] = nameescape:match(key)
a[2*i-j] = deepcopy_lookup[type](references, pdf, value, detail)
end
end
pdf:stream(references[-r[2]], table.concat(a, ' '), value(false), false, true)
else
pdf:indirect(references[-r[2]], deepcopy_lookup[type](references, pdf, value, detail))
end
i = i+1
r = references[i]
end
for i=1,#references do references[i] = nil end
return res
end