1// Copyright (c) 2012 - Cloud Instruments Co., Ltd.
2//
3// All rights reserved.
4//
5// Redistribution and use in source and binary forms, with or without
6// modification, are permitted provided that the following conditions are met:
7//
8// 1. Redistributions of source code must retain the above copyright notice, this
9//    list of conditions and the following disclaimer.
10// 2. Redistributions in binary form must reproduce the above copyright notice,
11//    this list of conditions and the following disclaimer in the documentation
12//    and/or other materials provided with the distribution.
13//
14// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
15// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
18// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
19// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
20// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
21// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
23// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24
25package seelog
26
27import (
28	"encoding/xml"
29	"errors"
30	"fmt"
31	"io"
32	"strings"
33)
34
35type xmlNode struct {
36	name       string
37	attributes map[string]string
38	children   []*xmlNode
39	value      string
40}
41
42func newNode() *xmlNode {
43	node := new(xmlNode)
44	node.children = make([]*xmlNode, 0)
45	node.attributes = make(map[string]string)
46	return node
47}
48
49func (node *xmlNode) String() string {
50	str := fmt.Sprintf("<%s", node.name)
51
52	for attrName, attrVal := range node.attributes {
53		str += fmt.Sprintf(" %s=\"%s\"", attrName, attrVal)
54	}
55
56	str += ">"
57	str += node.value
58
59	if len(node.children) != 0 {
60		for _, child := range node.children {
61			str += fmt.Sprintf("%s", child)
62		}
63	}
64
65	str += fmt.Sprintf("</%s>", node.name)
66
67	return str
68}
69
70func (node *xmlNode) unmarshal(startEl xml.StartElement) error {
71	node.name = startEl.Name.Local
72
73	for _, v := range startEl.Attr {
74		_, alreadyExists := node.attributes[v.Name.Local]
75		if alreadyExists {
76			return errors.New("tag '" + node.name + "' has duplicated attribute: '" + v.Name.Local + "'")
77		}
78		node.attributes[v.Name.Local] = v.Value
79	}
80
81	return nil
82}
83
84func (node *xmlNode) add(child *xmlNode) {
85	if node.children == nil {
86		node.children = make([]*xmlNode, 0)
87	}
88
89	node.children = append(node.children, child)
90}
91
92func (node *xmlNode) hasChildren() bool {
93	return node.children != nil && len(node.children) > 0
94}
95
96//=============================================
97
98func unmarshalConfig(reader io.Reader) (*xmlNode, error) {
99	xmlParser := xml.NewDecoder(reader)
100
101	config, err := unmarshalNode(xmlParser, nil)
102	if err != nil {
103		return nil, err
104	}
105	if config == nil {
106		return nil, errors.New("xml has no content")
107	}
108
109	nextConfigEntry, err := unmarshalNode(xmlParser, nil)
110	if nextConfigEntry != nil {
111		return nil, errors.New("xml contains more than one root element")
112	}
113
114	return config, nil
115}
116
117func unmarshalNode(xmlParser *xml.Decoder, curToken xml.Token) (node *xmlNode, err error) {
118	firstLoop := true
119	for {
120		var tok xml.Token
121		if firstLoop && curToken != nil {
122			tok = curToken
123			firstLoop = false
124		} else {
125			tok, err = getNextToken(xmlParser)
126			if err != nil || tok == nil {
127				return
128			}
129		}
130
131		switch tt := tok.(type) {
132		case xml.SyntaxError:
133			err = errors.New(tt.Error())
134			return
135		case xml.CharData:
136			value := strings.TrimSpace(string([]byte(tt)))
137			if node != nil {
138				node.value += value
139			}
140		case xml.StartElement:
141			if node == nil {
142				node = newNode()
143				err := node.unmarshal(tt)
144				if err != nil {
145					return nil, err
146				}
147			} else {
148				childNode, childErr := unmarshalNode(xmlParser, tok)
149				if childErr != nil {
150					return nil, childErr
151				}
152
153				if childNode != nil {
154					node.add(childNode)
155				} else {
156					return
157				}
158			}
159		case xml.EndElement:
160			return
161		}
162	}
163}
164
165func getNextToken(xmlParser *xml.Decoder) (tok xml.Token, err error) {
166	if tok, err = xmlParser.Token(); err != nil {
167		if err == io.EOF {
168			err = nil
169			return
170		}
171		return
172	}
173
174	return
175}
176