LaTeX format for LuaMetaTeX
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

90 lines
2.7 KiB

  1. local format = string.format
  2. local strip_floats = require'luametalatex-pdf-utils'.strip_floats
  3. local pdfe = pdfe
  4. local l = lpeg
  5. local regularchar = 1-l.S'\0\t\n\r\f ()<>[]{}/%#'
  6. local escapednamechar = l.P(1)/function(s)
  7. return format("#%02X")
  8. end
  9. local nameescape = l.Cs(l.Cc'/' * (regularchar + escapednamechar)^0)
  10. local deepcopy_lookup deepcopy_lookup = {
  11. function(_, pdf) -- 1: null
  12. return 'null'
  13. end,
  14. function(_, pdf, b) -- 2: boolean
  15. return b == 1 and 'true' or 'false'
  16. end,
  17. function(_, pdf, i) -- 3: integer
  18. return format("%d", i)
  19. end,
  20. function(_, pdf, f) -- 4: number
  21. return strip_floats(format("%f", f), "%.?0+[ %]]", "")
  22. end,
  23. function(_, pdf, name) -- 5: name
  24. return nameescape:match(name)
  25. end,
  26. function(_, pdf, string, hex) -- 6: string
  27. return hex and format("<%s>", string) or format("(%s)", string)
  28. end,
  29. function(references, pdf, array, size) -- 7: array
  30. local a = {}
  31. for i=1,size do
  32. local type, value, detail = pdfe.getfromarray(array, i)
  33. a[i] = deepcopy_lookup[type](references, pdf, value, detail)
  34. end
  35. return '[' .. table.concat(a, ' ') .. ']'
  36. end,
  37. function(references, pdf, dict, size) -- 8: dict
  38. local a = {}
  39. for i=1,size do
  40. local key, type, value, detail = pdfe.getfromdictionary(dict, i)
  41. a[2*i-1] = nameescape:match(key)
  42. a[2*i] = deepcopy_lookup[type](references, pdf, value, detail)
  43. end
  44. return '<<' .. table.concat(a, ' ') .. '>>'
  45. end,
  46. nil, -- 9: stream (can only appear as a reference
  47. function(references, pdf, ref, num)
  48. local new = references[-num]
  49. if not new then
  50. new = pdf:getobj()
  51. references[-num] = new
  52. references[#references+1] = {ref, num}
  53. end
  54. return format("%i 0 R", new)
  55. end,
  56. }
  57. local references = setmetatable({}, {__index = function(t, n)
  58. local v = {}
  59. t[n] = v
  60. return v
  61. end})
  62. return function(file, id, pdf, type, value, detail)
  63. local references = references[id]
  64. local res = deepcopy_lookup[type](references, pdf, value, detail)
  65. local i, r = 1, references[1]
  66. while r do
  67. local type, value, detail, more = pdfe.getfromreference(r[1])
  68. if type == 9 then
  69. local a,j = {}, 0
  70. for i=1,more do
  71. local key, type, value, detail = pdfe.getfromdictionary(detail, i)
  72. if key == 'Length' then
  73. j=2
  74. else
  75. a[2*i-1-j] = nameescape:match(key)
  76. a[2*i-j] = deepcopy_lookup[type](references, pdf, value, detail)
  77. end
  78. end
  79. pdf:stream(references[-r[2]], table.concat(a, ' '), value(false), false, true)
  80. else
  81. pdf:indirect(references[-r[2]], deepcopy_lookup[type](references, pdf, value, detail))
  82. end
  83. i = i+1
  84. r = references[i]
  85. end
  86. for i=1,#references do references[i] = nil end
  87. return res
  88. end