-- 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