Advertisement
Alakazard12

Lua port of PHP serialize

May 11th, 2013
361
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 8.46 KB | None | 0 0
  1. -- #!/usr/bin/env lua
  2.  
  3. --[[
  4.   @file
  5.   Lua port of PHP serialization functions.
  6.  
  7.   Port based on PHPSerialize and PHPUnserialize by Scott Hurring
  8.   http://hurring.com/scott/code/python/serialize/v0.4
  9.  
  10.   @version v0.1 BETA
  11.   @author Fernando P. García; fernando at develcuy dot com
  12.   @copyright Copyright (c) 2009 Fernando P. García
  13.   @license http://opensource.org/licenses/gpl-license.php GNU Public License
  14.  
  15.   $Id$
  16. ]]
  17.  
  18. local _serialize_key, _read_chars, _read_until, _unknown_type
  19.  
  20. function _serialize_key(data)
  21.   --[[
  22.   Serialize a key, which follows different rules than when
  23.   serializing values.  Many thanks to Todd DeLuca for pointing
  24.   out that keys are serialized differently than values!
  25.  
  26.   From http://us2.php.net/manual/en/language.types.array.php
  27.   A key may be either an integer or a string.
  28.   If a key is the standard representation of an integer, it will be
  29.   interpreted as such (i.e. "8" will be interpreted as int 8,
  30.   while "08" will be interpreted as "08").
  31.   Floats in key are truncated to integer.
  32.   ]]
  33.  
  34.   -- Integer, Long, Float
  35.   if type(data) == 'number' then
  36.     return 'i:' .. tonumber(data) .. ';'
  37.  
  38.   -- Boolean => integer
  39.   elseif type(data) == 'boolean' then
  40.     if data then
  41.       return 'i:1;'
  42.     else
  43.       return 'i:0;'
  44.     end
  45.  
  46.   -- String => string or String => int (if string looks like int)
  47.   elseif type(data) == 'string' then
  48.     if tonumber(data) == nil then
  49.       return 's:' .. string.len(data) .. ':"' .. data .. '";'
  50.     else
  51.       return 'i:' .. tonumber(data) .. ';'
  52.     end
  53.  
  54.   -- None / NULL => empty string
  55.   elseif type(data) == 'nil' then
  56.     return 's:0:"";'
  57.  
  58.   -- I dont know how to serialize this
  59.   else
  60.     error('Unknown / Unhandled key  type (' .. type(data) .. ')!')
  61.   end
  62. end
  63.  
  64. function serialize(data)
  65.   --[[
  66.   Serialize a value.
  67.   ]]
  68.  
  69.   local i, out, key, value
  70.  
  71.   -- Numbers
  72.   if type(data) == 'number' then
  73.     -- Integer => integer
  74.     if  math.floor(data) == data then
  75.       return 'i:' .. data .. ';'
  76.     -- Float, Long => double
  77.     else
  78.       return 'd:' .. data .. ';'
  79.     end
  80.  
  81.   -- String => string or String => int (if string looks like int)
  82.   -- Thanks to Todd DeLuca for noticing that PHP strings that
  83.   -- look like integers are serialized as ints by PHP
  84.   elseif type(data) == 'string' then
  85.     if tonumber(data) == nil then
  86.       return 's:' .. string.len(data) .. ':"' .. data .. '";'
  87.     else
  88.       return 'i:' .. tonumber(data) .. ';'
  89.     end
  90.  
  91.   -- Nil / NULL
  92.   elseif type(data) == 'nil' then
  93.     return 'N;'
  94.  
  95.   -- Tuple and List => array
  96.   -- The 'a' array type is the only kind of list supported by PHP.
  97.   -- array keys are automagically numbered up from 0
  98.   elseif type(data) == 'table' then
  99.     i = 0
  100.     out = {}
  101.     -- All arrays must have keys
  102.     for key, value in pairs(data) do
  103.       table.insert(out, _serialize_key(key))
  104.       table.insert(out, serialize(value))
  105.       i = i + 1
  106.     end
  107.     return 'a:' .. i .. ':{' .. table.concat(out) .. '}'
  108.  
  109.   -- Boolean => bool
  110.   elseif type(data) == 'boolean' then
  111.     if data then
  112.       return 'b:1;'
  113.     else
  114.       return 'b:0;'
  115.     end
  116.  
  117.   --~ TODO:
  118.   --~ -- Table + Functions => stdClass
  119.   --~ elseif type(data) == 'function' then
  120.  
  121.   --~ # I dont know how to serialize this
  122.   else
  123.    error('Unknown / Unhandled data type (' .. type(data) .. ')!')
  124.   end
  125. end
  126.  
  127. function _read_until(data, offset, stopchar)
  128.   --[[
  129.   Read from data[offset] until you encounter some char 'stopchar'.
  130.   ]]
  131.  
  132.   local buf = {}
  133.   local char = string.sub(data, offset + 1, offset + 1)
  134.   local i = 2
  135.   while not (char == stopchar) do
  136.     -- Consumed all the characters and havent found ';'
  137.     if i + offset > string.len(data) then
  138.       error('Invalid')
  139.     end
  140.     table.insert(buf, char)
  141.     char = string.sub(data, offset + i, offset + i)
  142.     i = i + 1
  143.   end
  144.   -- (chars_read, data)
  145.   return i - 2, table.concat(buf)
  146. end
  147.  
  148. function _read_chars(data, offset, length)
  149.   --[[
  150.   Read 'length' number of chars from data[offset].
  151.   ]]
  152.  
  153.   local buf = {}, char
  154.   -- Account for the starting quote char
  155.   -- offset += 1
  156.   for i = 0, length -1 do
  157.     char = string.sub(data, offset + i, offset + i)
  158.     table.insert(buf, char)
  159.   end
  160.  
  161.   -- (chars_read, data)
  162.   return length, table.concat(buf)
  163. end
  164.  
  165. function unserialize(data, offset)
  166.   offset = offset or 0
  167.  
  168.   --[[
  169.   Find the next token and unserialize it.
  170.   Recurse on array.
  171.  
  172.   offset = raw offset from start of data
  173.   --]]
  174.  
  175.   local buf, dtype, dataoffset, typeconvert, datalength, chars, readdata, i,
  176.          key, value, keys, properties, otchars, otype, property
  177.  
  178.   buf = {}
  179.   dtype = string.lower(string.sub(data, offset + 1, offset + 1))
  180.  
  181.   -- 't:' = 2 chars
  182.   dataoffset = offset + 2
  183.   typeconvert = function(x) return x end
  184.   datalength = 0
  185.   chars = datalength
  186.  
  187.   -- int or double => Number
  188.   if dtype == 'i' or dtype == 'd' then
  189.     typeconvert = function(x) return tonumber(x) end
  190.     chars, readdata = _read_until(data, dataoffset, ';')
  191.     -- +1 for end semicolon
  192.     dataoffset = dataoffset + chars + 1
  193.  
  194.   -- bool => Boolean
  195.   elseif dtype == 'b' then
  196.     typeconvert = function(x) return tonumber(x) == 1 end
  197.     chars, readdata = _read_until(data, dataoffset, ';')
  198.     -- +1 for end semicolon
  199.     dataoffset = dataoffset + chars + 1
  200.  
  201.   -- n => None
  202.   elseif dtype == 'n' then
  203.     readdata = nil
  204.  
  205.   -- s => String
  206.   elseif dtype == 's' then
  207.     chars, stringlength = _read_until(data, dataoffset, ':')
  208.     -- +2 for colons around length field
  209.     dataoffset = dataoffset + chars + 2
  210.  
  211.     -- +1 for start quote
  212.     chars, readdata = _read_chars(data, dataoffset + 1, tonumber(stringlength))
  213.     -- +2 for endquote semicolon
  214.     dataoffset = dataoffset + chars + 2
  215.  
  216.     --[[
  217.     TODO
  218.     review original: if chars != int(stringlength) != int(readdata):
  219.     ]]
  220.     if not (chars == tonumber(stringlength)) then
  221.       error('String length mismatch')
  222.     end
  223.  
  224.   -- array => Table
  225.   -- If you originally serialized a Tuple or List, it will
  226.   -- be unserialized as a Dict.  PHP doesn't have tuples or lists,
  227.   -- only arrays - so everything has to get converted into an array
  228.   -- when serializing and the original type of the array is lost
  229.   elseif dtype == 'a' then
  230.     readdata = {}
  231.  
  232.     -- How many keys does this list have?
  233.     chars, keys = _read_until(data, dataoffset, ':')
  234.     -- +2 for colons around length field
  235.     dataoffset = dataoffset + chars + 2
  236.  
  237.     -- Loop through and fetch this number of key/value pairs
  238.     for i = 0, tonumber(keys) - 1 do
  239.       -- Read the key
  240.       key, ktype, kchars = unserialize(data, dataoffset)
  241.       dataoffset = dataoffset + kchars
  242.  
  243.       -- Read value of the key
  244.       value, vtype, vchars = unserialize(data, dataoffset)
  245.       -- Cound ending bracket of nested array
  246.       if vtype == 'a' then
  247.         vchars = vchars + 1
  248.       end
  249.       dataoffset = dataoffset + vchars
  250.  
  251.       -- Set the list element
  252.       readdata[key] = value
  253.     end
  254.   -- object => Table
  255.   elseif dtype == 'p' then
  256.     readdata = {}
  257.  
  258.     -- How log is the type of this object?
  259.     chars, otchars = _read_until(data, dataoffset, ':')
  260.     dataoffset = dataoffset + chars + 2
  261.  
  262.     -- Which type is this object?
  263.     otype = string.sub(data, dataoffset + 1, dataoffset + otchars)
  264.     dataoffset = dataoffset + otchars + 2
  265.  
  266.     if otype == 'stdClass' then
  267.       -- How many properties does this list have?
  268.       chars, properties = _read_until(data, dataoffset, ':')
  269.  
  270.       -- +2 for colons around length field
  271.       dataoffset = dataoffset + chars + 2
  272.  
  273.       -- Loop through and fetch this number of key/value pairs
  274.       for i = 0, tonumber(properties) - 1 do
  275.         -- Read the key
  276.         property, ktype, kchars = unserialize(data, dataoffset)
  277.         dataoffset = dataoffset + kchars
  278.  
  279.         -- Read value of the key
  280.         value, vtype, vchars = unserialize(data, dataoffset)
  281.         -- Cound ending bracket of nested array
  282.         if vtype == 'a' then
  283.           vchars = vchars + 1
  284.         end
  285.         dataoffset = dataoffset + vchars
  286.  
  287.         -- Set the list element
  288.         readdata[property] = value
  289.       end
  290.     else
  291.       _unknown_type(dtype)
  292.     end
  293.   else
  294.     _unknown_type(dtype)
  295.   end
  296.  
  297.   --~ return (dtype, dataoffset-offset, typeconvert(readdata))
  298.   return typeconvert(readdata), dtype, dataoffset - offset
  299. end
  300.  
  301. -- I don't know how to unserialize this
  302. function _unknown_type(type_)
  303.   error('Unknown / Unhandled data type (' .. type_ .. ')!', 2)
  304. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement