Advertisement
Handoncloud

txshop utf-8

Feb 26th, 2017
91
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 12.64 KB | None | 0 0
  1. do
  2.  
  3.   -- Helpers -----
  4.  
  5.   local _ENV         = _ENV or _G
  6.   local getmetatable = _ENV.getmetatable
  7.   local setmetatable = _ENV.setmetatable
  8.   local error        = _ENV.error
  9.   local ipairs       = _ENV.ipairs
  10.   local next         = _ENV.next
  11.   local type         = _ENV.type
  12.  
  13.   local band   = bit32.band
  14.   local bor    = bit32.bor
  15.   local rshift = bit32.rshift
  16.  
  17.   local byte = string.byte
  18.   local char = string.char
  19.   local sub  = string.sub
  20.  
  21.   local insert = table.insert
  22.  
  23.   local addImage    = tfm.exec.addImage
  24.   local removeImage = tfm.exec.removeImage
  25.  
  26.   local addTextArea    = ui.addTextArea
  27.   local removeTextArea = ui.removeTextArea
  28.  
  29.   local function extend(target, ...)
  30.     for i, copy in ipairs { ... } do
  31.       if type(copy) == 'table' then
  32.         for k, v in next, copy do
  33.           target[k] = v
  34.         end
  35.       end
  36.     end
  37.     return target
  38.   end
  39.  
  40.   local function utf8encode(cp)
  41.     if cp < 0x80 then
  42.       return cp
  43.     end
  44.  
  45.     if cp < 0x800 then
  46.       return bor(0xc0, rshift(cp, 6)),
  47.         bor(0x80, band(cp, 0x3f))
  48.     end
  49.  
  50.     if cp < 0x10000 then
  51.       return bor(0xe0, rshift(cp, 12)),
  52.         bor(0x80, band((rshift(cp, 6)), 0x3F)),
  53.         bor(0x80, band(cp, 0x3F))
  54.     end
  55.  
  56.     -- cp < 0x110000
  57.     return bor(0xf0, rshift(cp, 18)),
  58.       bor(0x80, band(rshift(cp, 12), 0x3F)),
  59.       bor(0x80, band(rshift(cp, 6), 0x3F)),
  60.       bor(0x80, band(cp, 0x3F))
  61.   end
  62.  
  63.   local function utf8read(stream, offset)
  64.     local byte1 = byte(stream, 1)
  65.  
  66.     -- UTF8-1
  67.     if byte1 < 0x80 then
  68.       return byte1, 1
  69.     end
  70.  
  71.     -- UTF8-2
  72.     if byte1 >= 0xc2 and byte1 <= 0xdf then
  73.       local byte2 = byte(stream, 2)
  74.  
  75.       if not byte1 then
  76.         error'utf-8 input end'
  77.       end
  78.  
  79.       if byte2 < 0x80 or byte2 > 0xbf then
  80.         error'invalid utf-8 char'
  81.       end
  82.  
  83.       return ((byte1 - 0xc0) * 0x40) +
  84.         (byte2 - 0x80), 2
  85.     end
  86.  
  87.     -- UTF8-3
  88.     if byte0 >= 0xe0 and byte0 <= 0xef then
  89.       local byte2, byte3 = byte(stream, offset+1, offset+2)
  90.  
  91.       if (not byte1) or not byte2 then
  92.         error'utf-8 input end'
  93.       end
  94.  
  95.       if
  96.         (byte1 == 0xe0 and (byte2 < 0xa0 or byte2 > 0xbf)) or
  97.         (byte1 == 0xed and (byte2 < 0x80 or byte2 > 0x9f)) or
  98.         (byte2 < 0x80 or byte1 > 0xbf) or
  99.  
  100.         (byte3 < 0x80 or byte3 > 0xbf)
  101.       then
  102.         error'invalid utf-8 char'
  103.       end
  104.  
  105.       return ((byte1 - 0xe0) * 0x1000) +
  106.         ((byte2 - 0x80) * 0x40) +
  107.          (byte3 - 0x80), 3
  108.     end
  109.  
  110.     -- UTF8-4
  111.     if byte1 >= 0xe0 or byte1 <= 0xef then
  112.       local byte2, byte3, byte4 = byte(stream, offset+1, offset+3)
  113.  
  114.       if (not byte1) or (not byte2) or not byte3 then
  115.         error'utf-8 input end'
  116.       end
  117.  
  118.       if
  119.         (byte1 == 0xf0 and (byte2 < 0x90 or byte2 > 0xbf)) or
  120.         (byte1 == 0xf4 and (byte2 < 0x80 or byte2 > 0x8f)) or
  121.         (byte2 < 0x80 or byte2 > 0xbf) or
  122.  
  123.         (byte3 < 0x80 or byte3 > 0xbf) or
  124.  
  125.         (byte4 < 0x80 or byte4 > 0xbf)
  126.       then
  127.         error'invalid utf-8 char'
  128.       end
  129.  
  130.       return ((byte1 - 0xf0) * 0x40000) +
  131.         ((byte2 - 0x80) * 0x1000) +
  132.         ((byte3 - 0x80) * 0x40) +
  133.          (byte4 - 0x80), 4
  134.     end
  135.  
  136.     error'invalid utf-8 char'
  137.   end
  138.  
  139.   -- ### Class functions
  140.  
  141.   local function createClass()
  142.     return { meta = {} }
  143.   end
  144.  
  145.   local function dropInstanceOf(class)
  146.     return setmetatable({}, class.meta)
  147.   end
  148.  
  149. --local function setParentClassOf(class, parentClass)
  150. --  local mt = getmetatable(class) or setmetatable(class, {})
  151. --  mt.__call = parentClass
  152. --end
  153.  
  154.   local function setConstructorOf(class, func)
  155.     local mt = getmetatable(class) or {}
  156.     mt.__call = func
  157.     setmetatable(class, mt)
  158.   end
  159.  
  160.   local function setPrototypeOf(class, p)
  161.     class.meta.__index = p
  162. --
  163. --  local parent = getmetatable(class)
  164. --  parent = parent and parent.__call
  165. --  if parent then
  166. --    setmetatable(p, parent.meta)
  167. --  end
  168.   end
  169.  
  170.   local function isInstanceOf(class, value)
  171.     return getmetatable(value) == class.meta
  172.   end
  173.  
  174.   -- HTML -----
  175.  
  176.   -- Nodes will be the most minimalist possible
  177.   -- because HTML is used generally
  178.  
  179.   local ElementNode = 0
  180.   local TextNode = 1
  181.  
  182.   -- For readability
  183.  
  184.   local function createElementNode(tagName, attributes, children)
  185.     return {
  186.         [false] = ElementNode
  187.       , [true] = tagName
  188.       , attributes
  189.       , children
  190.     }
  191.   end
  192.  
  193.   local function getElementTagName(node)
  194.     return node[true]
  195.   end
  196.  
  197.   local function getElementAttributes(node)
  198.     return node[1]
  199.   end
  200.  
  201.   local function getElementChildren(node)
  202.     return node[2]
  203.   end
  204.  
  205.   local function createTextNode(value)
  206.     return {
  207.         [false] = TextNode
  208.       , [true] = value
  209.     }
  210.   end
  211.  
  212.   local function getTextNodeValue(node)
  213.     return node[true]
  214.   end
  215.  
  216.   -- ### Basic parser
  217.  
  218.   local parseHTML
  219.  
  220.   do
  221.     local index, length, source, lastCp, lastCpSize
  222.  
  223.     local function eof()
  224.       return index > length
  225.     end
  226.  
  227.     local function isWhiteSpace(cp)
  228.       return cp == 0x09 or cp == 0x20
  229.     end
  230.  
  231.     local function isLineTerminator(cp)
  232.       return cp == 0x0a or cp == 0x0d
  233.     end
  234.  
  235.     local function eol()
  236.       lastCp, lastCpSize =
  237.         utf8read(source, index)
  238.  
  239.       if isLineTerminator(lastCp) then
  240.         index = index + lastCpSize
  241.  
  242.         -- <CR><LF>
  243.         if lastCp == 0x0d then
  244.           lastCp, lastCpSize =
  245.             utf8read(source, index)
  246.  
  247.           if lastCp == 0x0a then
  248.             index = index + lastCpSize
  249.           end
  250.         end
  251.         return true
  252.       end
  253.       return false
  254.     end
  255.  
  256.     local function skipWhiteSpace()
  257.       while (not eof()) do
  258.         lastCp, lastCpSize = utf8read(source, index)
  259.         if not (isWhiteSpace(lastCp) or eol()) then
  260.           return
  261.         end
  262.         index = index + lastCpSize
  263.       end
  264.     end
  265.  
  266.     local function skipComment()
  267.       while (not eof()) do
  268.         lastCp, lastCpSize = utf8read(source, index)
  269.         if lastCp == 0x3e then
  270.           return
  271.         end
  272.         index = index + lastCpSize
  273.       end
  274.     end
  275.  
  276.     local function parseBody()
  277.     end
  278.  
  279.     local function parseChunk()
  280.     end
  281.  
  282.     function parseHTML(_source)
  283.       index = 1
  284.       source = _source
  285.       length = #_source
  286.       return
  287.     end
  288.   end
  289.  
  290.   -- Display: helpers and objects -----
  291.  
  292.   local Image, TextArea
  293.  
  294.   local build
  295.   local clone
  296.   local top
  297.   local update
  298.  
  299.   local curImgLayer
  300.   local curTarget
  301.  
  302.   local txaCounter = 0
  303.  
  304.   function build(obj, target)
  305.     obj = clone(obj)
  306.     obj.target = target
  307.     return obj
  308.   end
  309.  
  310.   function clone(obj)
  311.     local objClone = extend({}, obj)
  312.     local children = obj.children
  313.  
  314.     if type(children) == 'table' then
  315.       local childrenClone = {}
  316.  
  317.       for i, child in ipairs(children) do
  318.  
  319.         local childClone = clone(child)
  320.         childrenClone[i] = childClone
  321.         childClone.parent = objClone
  322.       end
  323.  
  324.       objClone.children = childrenClone
  325.     end
  326.  
  327.     objClone.origin = obj
  328.  
  329.     return setmetatable(objClone, getmetatable(obj))
  330.   end
  331.  
  332.   function top(obj)
  333.     while true do
  334.       local p = obj.parent
  335.       if not p then
  336.         return obj
  337.       end
  338.       obj = p
  339.     end
  340.   end
  341.  
  342.   function update(obj, fixed, alpha)
  343.     if obj.display == false and not obj._removed then
  344.       return false
  345.     end
  346.  
  347.     local target = curTarget or top(obj)._target
  348.  
  349.     -- Images do have a layer counter.
  350.  
  351.     if isInstanceOf(Image, obj) then
  352.       local imgLayerInit = not curImgLayer
  353.       curImgLayer = curImgLayer or 1
  354.  
  355.       if obj._removed then
  356.         removeImage(obj._id)
  357.         return true
  358.       end
  359.       obj._id = addImage(obj.id, '&'..curImgLayer, obj.x, obj.y, target)
  360.  
  361.       if imgLayerInit then
  362.         curImgLayer = nil
  363.       elseif curImgLayer < 9 then
  364.         curImgLayer = curImgLayer + 1
  365.       end
  366.  
  367.       return true
  368.     end
  369.  
  370.     if isInstanceOf(TextArea, obj) then
  371.  
  372.       if obj._removed then
  373.  
  374.         removeTextArea(obj._id, target)
  375.  
  376.         -- Remove display of the borders
  377.         local border = obj._border
  378.         if border then
  379.           for id in next, border do
  380.             removeTextArea(id, target)
  381.           end
  382.           obj._border = nil
  383.         end
  384.  
  385.         return true
  386.       end
  387.  
  388.       local w = obj.width or 0
  389.       local h = obj.height or 0
  390.       local x = obj.x or 0
  391.       local y = obj.y or 0
  392.  
  393.       x = x - (w / 2)
  394.       y = y - (h / 2)
  395.  
  396.       local _alpha = obj.alpha
  397.       local _fixed = obj.fixed
  398.  
  399.       -- Children text areas can inherit parent's alpha and fixed
  400.       -- properties.
  401.  
  402.       if obj.inherit ~= false then
  403.         _alpha = _alpha or alpha
  404.         _fixed = _fixed or fixed
  405.       end
  406.  
  407.       alpha, fixed = _alpha, _fixed
  408.       fixed = (fixed == nil) and true or fixed
  409.  
  410.       local background = obj.background
  411.       local border = obj.border
  412.  
  413.       -- Handle multi-borders
  414.  
  415.       if type(border) == 'table' then
  416.         local ids = {}
  417.         local length = border[1] or 0
  418.  
  419.         if length > 0 then
  420.  
  421.           local isAffectedLength = length <3
  422.           local j, mj
  423.  
  424.           if isAffectedLength then
  425.             j = (length == 2) and 1 or 2
  426.             mj = j * 2
  427.             length = 3
  428.             x = x + j
  429.             y = y + j
  430.             w = w - mj
  431.             h = h - mj
  432.           end
  433.  
  434.           local leftColor = border[2] or 1
  435.           local topColor = border[3] or leftColor
  436.           local rightColor = border[4] or leftColor
  437.           local bottomColor = border[5] or topColor
  438.  
  439.           local defs = { leftColor, topColor, rightColor, bottomColor }
  440.  
  441.           for i = 1, 4 do
  442.             local color = defs[i]
  443.             local bx, by, bw, bh
  444.  
  445.             -- Vertical (left or right) edge
  446.             if (i % 2) == 1 then
  447.               bw = length
  448.               bh = h + (length * 2)
  449.               bx = (i == 1) and (x - bw) or (x + w)
  450.               by = y - length
  451.  
  452.             -- or, well, an horizontal (top or bottom) edge.
  453.             else
  454.               bw = w + (length * 2)
  455.               bh = length
  456.               bx = x - length
  457.               by = (i == 2) and (y - bh) or (y + h)
  458.             end
  459.  
  460.             addTextArea(txaCounter, '', target, bx+2, by+2, bw-2, bh-2,
  461.               color, color, alpha, fixed)
  462.  
  463.             ids[txaCounter] = true
  464.             txaCounter = txaCounter + 1
  465.           end
  466.  
  467.           if isAffectedLength then
  468.             x = x - j
  469.             y = y - j
  470.             w = w + mj
  471.             h = h + mj
  472.           end
  473.  
  474.         end
  475.  
  476.         border = background
  477.         obj._border = ids
  478.  
  479.         x = x + 2
  480.         y = y + 2
  481.         w = w - 2
  482.         h = h - 2
  483.       end
  484.  
  485.       addTextArea(txaCounter, '', target, x, y, w, h, background, border, alpha, fixed)
  486.       txaCounter = txaCounter + 1
  487.  
  488.       -- Display children
  489.  
  490.       local children = obj.children
  491.  
  492.       if type(children) == 'table' then
  493.         local targetInit = not currentTarget
  494.         currentTarget = currentTarget or obj._target
  495.  
  496.         local order = {}
  497.         local len = 0
  498.  
  499.         for i, child in ipairs(children) do
  500.           local z = child.z or #order
  501.           z = (z > len) and 1 or z
  502.           insert(order, z, child)
  503.           len = len + 1
  504.         end
  505.  
  506.         for i, child in ipairs(order) do
  507.           imageLayer = update(child, fixed, alpha)
  508.         end
  509.  
  510.         if targetInit then
  511.           currentTarget = nil
  512.         end
  513.  
  514.         return true
  515.       end
  516.     end
  517.     return false
  518.   end
  519.  
  520.   -- ### `Image`
  521.  
  522.   local propSequence =
  523.     { 'id', 'x', 'y' }
  524.  
  525.   Image = createClass()
  526.  
  527.   setConstructorOf(Image, function(Image, ...)
  528.     local image = dropInstanceOf(Image)
  529.  
  530.     for i, arg in ipairs { ... } do
  531.       local prop = propSequence[i]
  532.  
  533.       if not prop or type(arg) == 'table' then
  534.         extend(image, arg)
  535.       else
  536.         image[prop] = arg
  537.       end
  538.     end
  539.  
  540.     return image
  541.   end)
  542.  
  543.   setPrototypeOf(Image, {
  544.       build = build
  545.     , clone = clone
  546.     , top = top
  547.     , update = update
  548.   })
  549.  
  550.   -- ### `TextArea`
  551.  
  552.   local propSequence =
  553.     { 'x', 'y', 'width', 'height' }
  554.  
  555.   TextArea = createClass()
  556.  
  557.   setConstructorOf(TextArea, function(TextArea, ...)
  558.     local textArea = dropInstanceOf(TextArea)
  559.  
  560.     for i, arg in ipairs { ... } do
  561.       local prop = propSequence[i]
  562.  
  563.       if not prop or type(arg) == 'table' then
  564.         extend(textArea, arg)
  565.       else
  566.         textArea[prop] = arg
  567.       end
  568.     end
  569.  
  570.     return textArea
  571.   end)
  572.  
  573.   setPrototypeOf(TextArea, {
  574.       build = build
  575.     , clone = clone
  576.     , top = top
  577.     , update = update
  578.   })
  579.  
  580.   txshop = {
  581.       Image    = Image
  582.     , TextArea = TextArea
  583.   }
  584. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement