-- ListSaver Script
-- @version 1.0.2
-- @notes
--
-- Designed to work with PropLists or linear lists, this script will
-- create an XML-like representation of the list. Each item in a lingo
-- list is represented by a pair of XML elements: The first is the property
-- (for property lists) or index position (for linear lists). The next element
-- is the value for that property or index.
--
-- Elements have an 'ilk' attribute to help translate the text version of the
-- value and property back to their original Lingo type.
--
-- Note - only types such as string, symbol, integers, floats, colours, rects, points
-- which can be represented in text are handled. Instances, images, sounds etc are
-- not saved (only a text representation of them is)
--
-- Note: this uses the newer XML Xtra that came with DMX2004
-- If you are using Director MX, you can get the xtra from your
-- shockwave installation (the Xtra seems to work fine with this
-- older version of Director)
-- PUBLIC INTERFACE ---------------------------------------
on ListToXML (me, aList)
-- returns an XML-like represenation of the list which
-- can be written to a text file.
XML = [""]
XML[1] = XML[1] & return & ""
me._AppendPropListToXML(XML, aList)
XML[1] = XML[1] & return & ""
return XML[1]
end
on XMLtoList (me, XML)
-- Converts the XML-like represenation of the list generated
-- by ListToXML back into a lingo list.
if XML.ilk <> #string then return
xmlparser = new(xtra "xmlparser")
xmlparser.parseString(XML)
pList = xmlparser.makeProplist()
if voidP(pList) then return #ERROR
if pList.count = 0 then return pList
--
if symbol(pList[#attributes][#ilk]) = #list then rList = []
else rList = [:]
t = pList[#child]
me._AppendNodeToList(rList, t)
return rList
end
on SaveList (me, aList, fileNameStr)
-- Saves the input list to the specified filename
-- using setPref (shockwave compatible). Note, the filename
-- should be the base name only (no path) and must have
-- an .htm or .txt extension
s = me.ListToXML(aList)
setPref (fileNameStr, s)
end
on ReadList (me, fileNameStr)
-- Saves the input list to the specified filename
-- using setPref (shockwave compatible).
s = getPref(fileNameStr)
if voidP(s) then return VOID
else return me.XMLtoList(s)
end
-- PRIVATE ---------------------------------------
on _AppendNodeToList (me, rList, parentList)
p = "ERROR"
repeat with aNode in parentList
if aNode[#child].count then
if aNode[#attributes][#ilk] = "list" then subList = []
else subList = [:]
me._AppendNodeToList(subList, aNode[#child])
if rList.ilk = #list then rList.append(subList)
else rList.addProp(p, subList)
else
if aNode[#name] = "itemkey" then
if rList.ilk = #list then next repeat
else p = me._evalString(String(aNode[#chardata]), symbol(aNode[#attributes][#ilk]))
else
v = me._evalString(String(aNode[#chardata]), symbol(aNode[#attributes][#ilk]))
if rList.ilk = #list then rList.append(v)
else rList.addProp(p, v)
end if
end if
end repeat
end
on _AppendPropListToXML (me, XList, aList, indent)
indent = indent & TAB
isPropList = (aList.ilk = #PropList)
repeat with i = 1 to aList.count
v = aList[i]
if isPropList then
p = aList.getPropAt(i)
key = "" & p & ""
else
key = "" & i & ""
end if
XList[1] = XList[1] & return & indent & key
if listP(v) then
XList[1] = XList[1] & return & indent & ""
me._AppendPropListToXML(XList, v, indent)
XList[1] = XList[1] & return & indent & ""
else
vilk = v.ilk
v = me._ValToString(v)
v = me._EncodeXMLentities(v)
XList[1] = XList[1] & return & indent & "" & v & ""
end if
end repeat
end
on _EncodeXMLentities (me, athing)
str = string(aThing)
entities = ["&":"amp",QUOTE:"quot","<":"lt",">":"gt"]
repeat with i = 1 to entities.count
encoded = "&"&entities[i]&";"
eStr = entities.getPropAt(i)
str = me.str_replace(eStr, encoded, str)
end repeat
return str
end
on str_replace (me, stringToFind, stringToInsert, input)
output = ""
findLen = stringToFind.length - 1
repeat while input contains stringToFind
currOffset = offset(stringToFind, input)
output = output & input.char [1..currOffset]
delete the last char of output
output = output & stringToInsert
delete input.char [1.. (currOffset + findLen)]
end repeat
output = output & input
return output
end
on _ValToString (me, v)
i = v.ilk
case (i) of
#Symbol: v = "#" & (v)
#Color: v = v.hexString()
#string:
v = v --
#list, #PropList:
repeat with i = 1 to v.count
v[i] = me._ValToString(v[i])
end repeat
end case
return string(v)
end
on _evalString (me, aStr, as)
-- evaulate a string as the specified ilk
case (as) of
#integer:
return integer(aStr)
#float:
return float(aStr)
#symbol:
if aStr.length > 1 AND aStr.char[1] = "#" then delete aStr.char[1]
return symbol(aStr.word[1])
#color:
return rgb(aStr)
#string:
otherwise
test1 = value(aStr)
if not voidP(test1) then
if symbolP(test1) then
test2 = "#"&test1
if test2 = aStr then
return test1
end if
else
test2 = string(test1)
if test2 = test1 then
return test1
end if
end if
end if
end case
return aStr
end
on _isHex (me, aStr)
mx = aStr.length
vChars = "0123456789abcdef"
repeat with i = 1 to mx
if NOT(vChars contains aStr.char[i]) then return 0
end repeat
return 1
end