2020-06-10 03:03:46 +02:00
|
|
|
local format = string.format
|
2020-07-06 15:31:15 +02:00
|
|
|
local strip_floats = require'luametalatex-pdf-utils'.strip_floats
|
2020-06-10 03:03:46 +02:00
|
|
|
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
|
2020-07-06 15:31:15 +02:00
|
|
|
return strip_floats(format("%f", f), "%.?0+[ %]]", "")
|
2020-06-10 03:03:46 +02:00
|
|
|
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
|