package jdr
|
|
|
|
import (
|
|
//"html/template"
|
|
"encoding/xml"
|
|
|
|
"errors"
|
|
"os"
|
|
)
|
|
|
|
type Page struct {
|
|
Items []SheetItem
|
|
}
|
|
|
|
type SheetItem interface{
|
|
}
|
|
|
|
type Block struct {
|
|
Items []SheetItem
|
|
}
|
|
|
|
type Variable struct {
|
|
Type VariableType
|
|
Name string
|
|
}
|
|
|
|
type CharacterSheet struct {
|
|
types map[string]VariableType
|
|
Pages []*Page
|
|
}
|
|
|
|
func (self *CharacterSheet) AddType(t VariableType) {
|
|
if self.types == nil {
|
|
self.types = make(map[string]VariableType)
|
|
}
|
|
|
|
name := t.Name()
|
|
self.types[name] = t
|
|
}
|
|
|
|
func (self *CharacterSheet) AddDefaultTypes() {
|
|
self.AddType(&VariableType_bool{})
|
|
self.AddType(&VariableType_int{})
|
|
self.AddType(&VariableType_float{})
|
|
self.AddType(&VariableType_string{})
|
|
self.AddType(&VariableType_d{})
|
|
}
|
|
|
|
func (self *CharacterSheet) getType(typename string) (VariableType, error) {
|
|
t, ok := self.types[typename]
|
|
if !ok {
|
|
return &VariableType_badType{}, errors.New("unknown type \"" + typename + "\"")
|
|
}
|
|
|
|
return t, nil
|
|
}
|
|
|
|
type xmlNode struct {
|
|
XMLName xml.Name
|
|
Attrs []xml.Attr `xml:"-"`
|
|
Content []byte `xml:",innerxml"`
|
|
Nodes []xmlNode `xml:",any"`
|
|
}
|
|
|
|
func (n *xmlNode) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
|
|
n.Attrs = start.Attr
|
|
type node xmlNode
|
|
|
|
return d.DecodeElement((*node)(n), &start)
|
|
}
|
|
|
|
func parseVariable(root xmlNode, sheet *CharacterSheet) (*Variable, error) {
|
|
ret := &Variable{}
|
|
|
|
typeOk := false
|
|
nameOk := false
|
|
for i := 0; i < len(root.Attrs); i++ {
|
|
attrName := root.Attrs[i].Name.Local
|
|
attrVal := root.Attrs[i].Value
|
|
|
|
switch attrName {
|
|
case "type":
|
|
t, err := sheet.getType(attrVal)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
ret.Type = t
|
|
typeOk = true
|
|
case "name":
|
|
ret.Name = attrVal
|
|
nameOk = true
|
|
}
|
|
}
|
|
|
|
if !nameOk {
|
|
return nil, errors.New("Unnamed variable")
|
|
}
|
|
if !typeOk {
|
|
return nil, errors.New("No type provided for variable \"" + ret.Name + "\"")
|
|
}
|
|
|
|
return ret, nil
|
|
}
|
|
|
|
func parseBlock(root xmlNode, sheet *CharacterSheet) (*Block, error) {
|
|
ret := &Block{}
|
|
|
|
for i := 0; i < len(root.Nodes); i++ {
|
|
item, err := parseItem(root.Nodes[i], sheet)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
ret.Items = append(ret.Items, item)
|
|
}
|
|
|
|
return ret, nil
|
|
}
|
|
|
|
func parseItem(root xmlNode, sheet *CharacterSheet) (SheetItem, error) {
|
|
switch root.XMLName.Local {
|
|
case "block":
|
|
return parseBlock(root, sheet)
|
|
case "variable":
|
|
return parseVariable(root, sheet)
|
|
default:
|
|
return nil, errors.New("Unknown item: " + root.XMLName.Local)
|
|
}
|
|
}
|
|
|
|
func parsePage(root xmlNode, sheet *CharacterSheet) (*Page, error) {
|
|
ret := &Page{}
|
|
|
|
for i := 0; i < len(root.Nodes); i++ {
|
|
item, err := parseItem(root.Nodes[i], sheet)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
ret.Items = append(ret.Items, item)
|
|
}
|
|
|
|
return ret, nil
|
|
}
|
|
|
|
func parseSheet(root xmlNode) (*CharacterSheet, error) {
|
|
if root.XMLName.Local != "jdr-desc" {
|
|
return nil, errors.New("Wrong root node")
|
|
}
|
|
|
|
sheet := &CharacterSheet{}
|
|
sheet.AddDefaultTypes()
|
|
for i := 0; i < len(root.Nodes); i++ {
|
|
node := root.Nodes[i]
|
|
|
|
switch node.XMLName.Local {
|
|
case "custom-types":
|
|
types, err := parseCustomTypes(node)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
for j := 0; j < len(types); j++ {
|
|
sheet.AddType(types[j])
|
|
}
|
|
|
|
case "page":
|
|
page, err := parsePage(node, sheet)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
sheet.Pages = append(sheet.Pages, page)
|
|
|
|
default:
|
|
return nil, errors.New("Wrong format")
|
|
}
|
|
}
|
|
|
|
return sheet, nil
|
|
}
|
|
|
|
func ReadCharacterSheet(filename string) (*CharacterSheet, error) {
|
|
file, err := os.Open(filename)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer file.Close()
|
|
|
|
decoder := xml.NewDecoder(file)
|
|
var n xmlNode
|
|
err = decoder.Decode(&n)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
sheet, err := parseSheet(n)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return sheet, nil
|
|
}
|