local plistParser = {}
function plistParser.nextTag(s, i)
return string.find(s, "<(%/?)([%w:]+)(%/?)>", i)
end
function plistParser.array(s, i)
local arr, nextTag, array, dictionary = {}, plistParser.nextTag, plistParser.array, plistParser.dictionary
local ni, j, c, label, empty
while true do
ni, j, c, label, empty = nextTag(s, i)
assert(ni)
if c == "" then
if empty == "/" then
if label == "dict" or label == "array" then
arr[#arr+1] = {}
else
arr[#arr+1] = (label == "true") and true or false
end
elseif label == "array" then
arr[#arr+1], i, j = array(s, j+1)
elseif label == "dict" then
arr[#arr+1], i, j = dictionary(s, j+1)
else
i = j + 1
ni, j, c, label, empty = nextTag(s, i)
local val = string.sub(s, i, ni-1)
if label == "integer" or label == "real" then
arr[#arr+1] = tonumber(val)
else
arr[#arr+1] = val
end
end
elseif c == "/" then
assert(label == "array")
return arr, j+1, j
end
i = j + 1
end
end
function plistParser.dictionary(s, i)
local dict, nextTag, array, dictionary = {}, plistParser.nextTag, plistParser.array, plistParser.dictionary
local ni, j, c, label, empty
while true do
ni, j, c, label, empty = nextTag(s, i)
assert(ni)
if c == "" then
if label == "key" then
i = j + 1
ni, j, c, label, empty = nextTag(s, i)
assert(c == "/" and label == "key")
local key = string.sub(s, i, ni-1)
i = j + 1
ni, j, c, label, empty = nextTag(s, i)
if empty == "/" then
if label == "dict" or label == "array" then
dict[key] = {}
else
dict[key] = (label == "true") and true or false
end
else
if label == "dict" then
local dictData = nil;
dictData, i, j = dictionary(s, j+1)
local position = string.find(key,"New item");
if position then
table.insert(dict,dictData);
dump(dictData);
else
dict[key] = dictData;
end
elseif label == "array" then
dict[key], i, j = array(s, j+1)
else
i = j + 1
ni, j, c, label, empty = nextTag(s, i)
local val = string.sub(s, i, ni-1)
if label == "integer" or label == "real" then
dict[key] = tonumber(val)
else
local position = string.find(key,"New item");
if position then
table.insert(dict,val);
else
dict[key] = val
end
end
end
end
end
elseif c == "/" then
assert(label == "dict")
return dict, j+1, j
end
i = j + 1
end
end
function plistParse(s)
local i, ni, tag, version, empty = 0
local label = 0;
while label ~= "plist" do
ni, i, label, version = string.find(s, "<([%w:]+)(.-)>", i+1)
assert(ni)
end
ni, i, _, label, empty = plistParser.nextTag(s, i)
if empty == "/" then
return {}
elseif label == "dict" then
return plistParser.dictionary(s, i+1)
elseif label == "array" then
return plistParser.array(s, i+1)
end
end
function plistParser.nextTag(s, i)
return string.find(s, "<(%/?)([%w:]+)(%/?)>", i)
end
function plistParser.array(s, i)
local arr, nextTag, array, dictionary = {}, plistParser.nextTag, plistParser.array, plistParser.dictionary
local ni, j, c, label, empty
while true do
ni, j, c, label, empty = nextTag(s, i)
assert(ni)
if c == "" then
if empty == "/" then
if label == "dict" or label == "array" then
arr[#arr+1] = {}
else
arr[#arr+1] = (label == "true") and true or false
end
elseif label == "array" then
arr[#arr+1], i, j = array(s, j+1)
elseif label == "dict" then
arr[#arr+1], i, j = dictionary(s, j+1)
else
i = j + 1
ni, j, c, label, empty = nextTag(s, i)
local val = string.sub(s, i, ni-1)
if label == "integer" or label == "real" then
arr[#arr+1] = tonumber(val)
else
arr[#arr+1] = val
end
end
elseif c == "/" then
assert(label == "array")
return arr, j+1, j
end
i = j + 1
end
end
function plistParser.dictionary(s, i)
local dict, nextTag, array, dictionary = {}, plistParser.nextTag, plistParser.array, plistParser.dictionary
local ni, j, c, label, empty
while true do
ni, j, c, label, empty = nextTag(s, i)
assert(ni)
if c == "" then
if label == "key" then
i = j + 1
ni, j, c, label, empty = nextTag(s, i)
assert(c == "/" and label == "key")
local key = string.sub(s, i, ni-1)
i = j + 1
ni, j, c, label, empty = nextTag(s, i)
if empty == "/" then
if label == "dict" or label == "array" then
dict[key] = {}
else
dict[key] = (label == "true") and true or false
end
else
if label == "dict" then
local dictData = nil;
dictData, i, j = dictionary(s, j+1)
local position = string.find(key,"New item");
if position then
table.insert(dict,dictData);
dump(dictData);
else
dict[key] = dictData;
end
elseif label == "array" then
dict[key], i, j = array(s, j+1)
else
i = j + 1
ni, j, c, label, empty = nextTag(s, i)
local val = string.sub(s, i, ni-1)
if label == "integer" or label == "real" then
dict[key] = tonumber(val)
else
local position = string.find(key,"New item");
if position then
table.insert(dict,val);
else
dict[key] = val
end
end
end
end
end
elseif c == "/" then
assert(label == "dict")
return dict, j+1, j
end
i = j + 1
end
end
function plistParse(s)
local i, ni, tag, version, empty = 0
local label = 0;
while label ~= "plist" do
ni, i, label, version = string.find(s, "<([%w:]+)(.-)>", i+1)
assert(ni)
end
ni, i, _, label, empty = plistParser.nextTag(s, i)
if empty == "/" then
return {}
elseif label == "dict" then
return plistParser.dictionary(s, i+1)
elseif label == "array" then
return plistParser.array(s, i+1)
end
end