Exemplo n.º 1
0
func WriteRBXM(input string) (out []byte, err error) {
	doc := xmlx.New()
	doc.SaveDocType = false

	root := newnode(xmlx.NT_ELEMENT, "roblox", "")
	root.AddChild(leading(0))
	doc.Root = root

	root.SetAttr("xmlns:xmime", "http://www.w3.org/2005/05/xmlmime")
	root.SetAttr("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance")
	root.SetAttr("xsi:noNamespaceSchemaLocation", "http://www.roblox.com/roblox.xsd")
	root.SetAttr("version", "4")

	ext := newnode(xmlx.NT_ELEMENT, "External", "")
	ext.AddChild(newnode(xmlx.NT_TEXT, "", "null"))
	root.AddChildAt(leading(1), -2)
	root.AddChildAt(ext, -2)

	ext = newnode(xmlx.NT_ELEMENT, "External", "")
	ext.AddChild(newnode(xmlx.NT_TEXT, "", "nil"))
	root.AddChildAt(leading(1), -2)
	root.AddChildAt(ext, -2)

	err = Walk(input, root)
	if err != nil {
		return out, err
	}

	// Reorder referents of items in the tree
	ref := 0
	refmap := make(map[string]string)
	items := doc.SelectNodesRecursive("", "Item")
	for _, item := range items {
		if item.HasAttr("", "referent") {
			newref := "RBX" + strconv.Itoa(ref)
			refmap[item.As("", "referent")] = newref
			item.SetAttr("referent", newref)
			ref++
		}
	}
	refs := doc.SelectNodesRecursive("", "Ref")
	for _, refnode := range refs {
		value := refnode.GetValue()
		if newref, ok := refmap[value]; ok {
			if len(refnode.Children) > 0 {
				refnode.Children[0].Value = newref
			}
		}
	}

	return doc.SaveBytes(), nil
}
Exemplo n.º 2
0
func walk(path string, info os.FileInfo, parent *xmlx.Node, uncles *nodeMap, ref *int, indent int) error {
	var child *xmlx.Node
	if info.IsDir() {
		// If possible, reuse a node created by a file that shares the same
		// base name. The sorting function ensures that the uncles map will be
		// populated with nodes, since files are traversed before directories.
		base := info.Name()
		node, ok := (*uncles)[base]
		if !ok {
			// Convert directories into Backpack objects
			item := Item{
				Class: "Backpack",
				Properties: []Property{
					{"string", "Name", info.Name()},
				},
			}

			node = item.Node(indent)

			node.SetAttr("referent", "RBX"+strconv.Itoa(*ref))
			*(ref)++

			parent.AddChildAt(leading(indent), -2)
			parent.AddChildAt(node, -2)
		}
		child = node
	} else {
		base, ext := splitName(info.Name())
		content, err := ioutil.ReadFile(path)
		if err != nil {
			return nil
		}

		var node *xmlx.Node
		if ext == ".lua" {
			// convert lua files into script objects
			subbase, subext := splitName(base)
			var item Item
			if subext == ".module" {
				// If the base name of the file ends with ".module"
				// (script.module.lua), then convert the file to a
				// ModuleScript object.
				item = Item{
					Class: "ModuleScript",
					Properties: []Property{
						{"string", "Name", subbase},
						{"ProtectedString", "Source", string(content)},
					},
				}
			} else {
				// Otherwise, convert it to a Script object.
				item = Item{
					Class: "Script",
					Properties: []Property{
						{"bool", "Disabled", "false"},
						{"Content", "LinkedSource", "null"},
						{"string", "Name", base},
						{"ProtectedString", "Source", string(content)},
					},
				}
			}

			node = item.Node(indent)

			node.SetAttr("referent", "RBX"+strconv.Itoa(*ref))
			*(ref)++

			parent.AddChildAt(leading(indent), -2)
			parent.AddChildAt(node, -2)
		} else if ext == ".rbxm" {
			// Insert contents of a roblox model file directly into the tree.
			doc := xmlx.New()
			if err := doc.LoadFile(path, nil); err != nil {
				return nil
			}

			nodes := doc.SelectNodes("", "Item")
			if len(nodes) == 0 {
				// Somehow, the model doesn't contain any objects.
				return nil
			}

			// Remap referents of items in this file
			refmap := make(map[string]string)
			items := doc.SelectNodesRecursive("", "Item")
			for _, item := range items {
				if item.HasAttr("", "referent") {
					newref := "RBX" + strconv.Itoa(*ref)
					refmap[item.As("", "referent")] = newref
					item.SetAttr("referent", newref)
					*(ref)++
				}
			}
			refs := doc.SelectNodesRecursive("", "Ref")
			for _, refnode := range refs {
				value := refnode.GetValue()
				if newref, ok := refmap[value]; ok {
					if len(refnode.Children) > 0 {
						refnode.Children[0].Value = newref
					}
				}
			}

			// Fix identation.
			fixIndentation(items, indent)
			fixIndentation(doc.SelectNodesRecursive("", "Properties"), indent)

			// Move each child node to new document
			for _, node := range nodes {
				parent.AddChildAt(leading(indent), -2)
				parent.AddChildAt(node, -2)
			}

			// Since a model may have multiple nodes, only the first node will
			// be paired with the model file.
			node = nodes[0]
		} else {
			// convert anything else into StringValue objects
			item := Item{
				Class: "StringValue",
				Properties: []Property{
					{"string", "Name", base},
					{"string", "Value", string(content)},
				},
			}

			node = item.Node(indent)
			node.SetAttr("referent", "RBX"+strconv.Itoa(*ref))
			*(ref)++

			parent.AddChildAt(leading(indent), -2)
			parent.AddChildAt(node, -2)
		}

		// Pair the node with the file's base name, which may be used later in
		// place of a directory that shares the same name.
		if _, ok := (*uncles)[base]; !ok {
			(*uncles)[base] = node
		}
		child = node
	}

	if !info.IsDir() {
		return nil
	}

	list, err := readDir(path)
	if err != nil {
		return nil
	}

	siblings := make(nodeMap)
	for _, fileInfo := range list {
		err = walk(filepath.Join(path, fileInfo.Name()), fileInfo, child, &siblings, ref, indent+1)
		if err != nil {
			return err
		}
	}
	return nil
}