-- XML Object Storage v1.0
-- Copyright 2004 Dave Miller, DMiller Studios
-- davmil@tenet.edu
-- Version History:
-- v20040215 - First Release
-- Requires a text member named "decoder" in a cast somewhere.
-- This also requires the Director MX 2004 XML parser Xtra
-- This is a group of scripts that allow one to store various Director objects as a giant string.
-- And as if that weren't handy enough, it also restores the objects from the string!
-- The string is damn near an XML document (all it it lacks is the tag at the beginning.)
-- Why would you want this? Well, if you want to store data anywhere, say, using setPrefs or on a server using postNetText,
-- you can only send the data as a string. What if you want to store a sprite reference? Or a vertexList? or a float with all of
-- its precision? You could use string() to convert your object and value() to restore it, but that has problems. Try these in the
-- message window and see if you get back what you tried to convert:
-- x = VOID
-- arg = [1,2,x]
-- put value(string(arg))
--
-- the floatPrecision = 4
-- arg = 1.123456789
-- result = value(string(arg))
-- the floatPrecision = 9
-- put result
-- arg = ["I said," & QUOTE & "Oops!" & QUOTE]
-- put value(string(arg))
-- There are probably more, but those were enough reason for me to write the scripts below. Also, it is well formed XML so if you have
-- some other application that you want to send data to, you can use it for that too!
-- The two handlers to use are toXML() and fromXML()
-- The objects you can convert are listed in the case statement in the toXML() handler.
-- Lists and pLists can only contain convertible objects.
-- If you come with with other data that is storable this way, let me know and I'll share it with the world.
-- To see the scripts in action run these in the message window
--
-- x = toXML( [#p:1 , "test":[1,2,VOID] , #sym:rect(1,2,3,4) , #mem:member("decoder"), #sp:sprite(1) ] ,1)
-- put x
-- put fromXML(x)
-- x = VOID
-- arg = [1,2,x]
-- put fromXML(toXML(arg))
--
-- the floatPrecision = 4
-- arg = 1.123456789
-- result = fromXML(toXML(arg))
-- the floatPrecision = 9
-- put result
--
-- arg = ["I said," & QUOTE & "Oops!" & QUOTE]
-- put fromXML(toXML(arg))
on toXML arg, aMode
-- if aMode = 1 then make the XML human readable with returns and spaces.
-- If aMode = 0 or VOID then save a few bytes and omit the dressing.
vSpace = EMPTY
if aMode > 0 then
put RETURN after vSpace
repeat with i = 1 to aMode-1
put " " after vSpace
end repeat
else
aMode = -1
end if
txt = EMPTY
case arg.ilk of
(#void):
put vSpace & "" after txt
(#integer):
put vSpace & "" & arg & "" after txt
(#float):
f = the floatPrecision
the floatPrecision = 15
put vSpace & "" & arg & "" after txt
the floatPrecision = f
(#string):
if arg = EMPTY then
put vSpace & "" & QUOTE & QUOTE & "" after txt
else
put vSpace & "" & enCode(arg) & "" after txt
end if
(#symbol):
put vSpace & "" & enCode(string(arg)) & "" after txt
(#rect):
put vSpace & "" after txt
repeat with i = 1 to 4
put toXML(arg[i], aMode+1) after txt
end repeat
put vSpace & "" after txt
(#point):
put vSpace & "" after txt
repeat with i = 1 to 2
put toXML(arg[i]) after txt
end repeat
put vSpace & " " after txt
(#list):
put vSpace & "" after txt
lim = arg.count
repeat with i = 1 to lim
put toXML(arg[i], aMode+1) after txt
end repeat
put vSpace & "" after txt
(#propList):
put vSpace & "" after txt
lim = arg.count
repeat with i = 1 to lim
put toXML( arg.getPropAt(i) ,aMode+1 ) after txt
put toXML( arg[i] ,aMode+1 ) after txt
end repeat
put vSpace & "" after txt
(#color):
put vSpace & "" after txt
case arg.colorType of
(#rgb):
put toXML( arg.red ,aMode+1 ) after txt
put toXML( arg.green ,aMode+1 ) after txt
put toXML( arg.blue ,aMode+1 ) after txt
(#paletteIndex):
put arg.paletteIndex after txt
end case
put vSpace & "" after txt
(#date):
put vSpace & "" after txt
put toXML( arg.year ,aMode+1 ) after txt
put toXML( arg.month ,aMode+1 ) after txt
put toXML( arg.day ,aMode+1 ) after txt
put vSpace & "" after txt
(#member):
put vSpace & "" after txt
put toXML( arg.name ,aMode+1 ) after txt
--put toXML( arg.number ,aMode+1 ) after txt
-- put toXML( arg.castLibNum ,aMode+1 ) after txt
put vSpace & "" after txt
(#castLib):
put vSpace & "" & arg.number & "" after txt
(#sprite):
put vSpace & "" & arg.spriteNum & "" after txt
(#xtra):
put vSpace & "" & enCode( arg.name ) & "" after txt
otherwise
if voidP(arg.ill) then
alert("XML parser error: Could not find a data type for" && arg)
else
alert("XML parser error: Data type" && arg.ilk && "not supported for XML conversion")
end if
end case
return txt
end toXML
on fromXML aXML
-- aXML is a string of XML created by toXML above.
-- It returns the object(s) described in the XML
vX = new(xtra "xmlparser")
errCode = vX.parseString(aXML)
errorString = vX.getError()
if voidP(errorString) then
vResult = convertXML( vX.makePropList() )
else
alert "Error parsing XML string:" && errorString
exit
end if
return vResult
end fromXML
on convertXML aList
--put aList
-- XML to object converter. Expects the makePropList() from an XML object created by toXML
case aList.name of
("v"): return VOID
("i"): return integer( aList.charData )
("f"): return float( aList.charData )
("s"): return decode( aList.charData )
("sy"): return symbol( decode(aList.charData) )
("r"): return rect( convertXML(aList.child[1]), convertXML(aList.child[2]), convertXML(aList.child[3]), convertXML(aList.child[4]) )
("p"): return point ( convertXML( aList.child[1]) , convertXML(aList.child[2]) )
("ll"):
vList = []
lim = aList.child.count
repeat with i = 1 to lim
vList.add( convertXML( aList.child[i] ) )
end repeat
return vList
("pl"):
vList = [:]
lim = aList.child.count/2
repeat with i = 1 to lim
vList.addProp( convertXML( aList.child[i*2-1] ) , convertXML( aList.child[i*2] ) )
end repeat
return vList
("c"):
if aList.child.count = 0 then
return paletteIndex( integer(aList.charData) )
else
return rgb( integer(aList.child[1].charData), integer(aList.child[2].charData), integer(aList.child[3].charData) )
end if
("d"): return date ( integer(aList.child[1].charData) , integer(aList.child[2].charData), integer(aList.child[3].charData) )
("m"): return member(aList.child[1].charData)
--return member integer(aList.child[1].charData) of castLib integer(aList.child[2].charData)
("cl"): return castLib integer(aList.charData)
("sp"): return sprite integer(aList.charData)
("x"): return xtra( decode ( aList.charData ) )
otherwise
alert("Can't convert XML" && aList.name && "to data type.")
return VOID
end case
end convertXML
-- The next two handlers convert special characters for XML. e.g. & <=> &
-- It requires a text member named "decoder" in a cast somewhere.
on deCode aTxt
-- replace returns with
newTxt = EMPTY
the itemDelimiter = RETURN
lim = aTxt.items.count
repeat with i = 1 to lim
put aTxt.item[i] after newTxt
if i < lim then put " " after newTxt
end repeat
-- use the internal HTML handler to decode.
member("decoder").html = "" & newTxt & ""
aTxt = member("decoder").text
return (aTxt)
end deCode
on enCode aTxt
if aTxt = "" then return EMPTY
vCharList = [ ["&","&"] , ["<","<"] , [">",">"] , [QUOTE,"""] , ["'","'"] ] -- "&" must be first in this list!
lim = vCharList.count
repeat with i = 1 to lim
the itemDelimiter = vCharList[i][1]
lim2 = aTxt.item.count
if lim2 > 1 then
tempTxt = EMPTY
repeat with j = 1 to lim2
put aTxt.item[j] after tempTxt
if j < lim2 then put vCharList[i][2] after tempTxt
end repeat
aTxt = tempTxt
end if
end repeat
return aTxt
end enCode
|