1 /******************************************************************************
2 *
3 * Copyright (C) 2006, The Gentee Group. All rights reserved.
4 * This file is part of the Gentee open source project - http://www.gentee.com.
5 *
6 * THIS FILE IS PROVIDED UNDER THE TERMS OF THE GENTEE LICENSE ("AGREEMENT").
7 * ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS FILE CONSTITUTES RECIPIENTS
8 * ACCEPTANCE OF THE AGREEMENT.
9 *
10 * ID: gtsave 29.09.06 0.0.A.
11 *
12 * Author: Alexey Krivonogov ( gentee )
13 *
14 ******************************************************************************/
15
16 define
17 {
18 GTS_ENDNAME = 0x01 // </name> or /name>
19 GTS_INLINE = 0x02 // <name> data </>
20 GTS_NOATTRIB = 0x04 // do not save attributes
21 }
22
23 type gtsave
24 {
25 uint off // The offset of the first level
26 uint offstep // The offset of the next level
27 uint inside // If body len < inside then <name = body
28 uint flags //
29 }
30
31 method str str.gtsaveval( str value )
32 {
33 uint inside
34 uint i
35
36 while ( inside = value.findchfrom( '<', i )) < *value
37 {
38 this.append( value.ptr() + i, inside - i )
39 if !inside || value[ inside + 1 ] == '/'
40 {
41 this.out4( "&x%02x;", '<' )
42 }
43 else : this.appendch( '<' )
44 i = inside + 1
45 }
46 this.append( value.ptr() + i, inside - i )
47
48 return this
49 }
50
51 method str str.gtsaveval( ustr uvalue )
52 {
53 str value
54
55 uvalue.toutf8( value )
56 return this.gtsaveval( value )
57 }
58
59 // Save gtitem to a string
60 method str gtitem.save( str ret, gtsave gts )
61 {
62 subfunc attr2text( str in )
63 {
64 uint space slash q dq i
65
66 slash = in.findch( '/' )
67 if in.findch( ' ' ) < *in ||
68 slash < *in || in.findch( '>' ) < *in
69 {
70 dq = in.findch( '"' )
71 if dq < *in
72 {
73 if ( q = in.findch( 0x27 /*'''*/ )) < *in
74 {
75 fornum i, *in
76 {
77 switch in[ i ]
78 {
79 case '"',0x27 /*'''*/,'/'
80 {
81 ret.out4( "&x%02x;", in[i] )
82 }
83 default : ret.appendch( in[i] )
84 }
85 }
86 }
87 else : ret += "'\(in)'"
88 }
89 else : ret += "\"\(in)\""
90 }
91 else : ret += in
92 }
93
94 // gtitems gtis
95 str soff name
96 uint i inside
97
98 soff = " ".repeat( gts.off )
99
100 if this.comment
101 {
102 return ret += "\( soff )<-\( this.value )->\l"
103 }
104 if this.isroot()
105 {
106 foreach curroot, this : curroot->gtitem.save( ret, gts )
107 return ret
108 }
109 name = this.name
110 if name[1] == ' ' : name = "_"
111 ret += "\( soff )<\(name)"
112 if gts.flags & $GTS_NOATTRIB : goto skipattrib
113 if *this.value < gts.inside
114 {
115 if *this.value
116 {
117 ret += " = "
118 attr2text( this.value )
119 }
120 inside = 1
121 }
122 fornum i = 0, *this.attrib
123 {
124 ret += " \(this.attrib[i].name)"
125 if *this.attrib[i].value
126 {
127 ret += " = "
128 attr2text( this.attrib[i].value )
129 }
130 }
131 label skipattrib
132
133 if inside && !this.haschild()
134 {
135 if name != "_" && gts.flags & $GTS_ENDNAME : ret += " /\(name)>\l"
136 else : ret += " />\l"
137 return ret
138 }
139 elif gts.flags & $GTS_INLINE && !this.haschild() : ret += " >"
140 else : ret += " >\l"
141
142 gts.off += gts.offstep
143 foreach cur, this
144 {
145 cur->gtitem.save( ret, gts )
146 }
147 gts.off -= gts.offstep
148
149 if !inside
150 {
151 ret.gtsaveval( this.value )
152 /* i = 0
153 while ( inside = this.value.findchfrom( '<', i )) < *this.value
154 {
155 ret.append( this.value.ptr() + i, inside - i )
156 if !inside || this.value[ inside + 1 ] == '/'
157 {
158 ret.out4( "&x%02x;", '<' )
159 }
160 else : ret.appendch( '<' )
161 i = inside + 1
162 }
163 ret.append( this.value.ptr() + i, inside - i )*/
164 // print("Ret=\("".substr(ret, 0, 50 ))\n")
165 if *this.value && !( gts.flags & $GTS_INLINE ) : ret += "\l"
166 }
167 if gts.flags & $GTS_INLINE && !this.haschild() : soff.clear()
168 if name != "_" && gts.flags & $GTS_ENDNAME : ret += "\(soff)</\(name)>\l"
169 else : ret += "\(soff)</>\l"
170 return ret
171 }
172
173 method str gtitem.savechildren( str ret, gtsave gts )
174 {
175 foreach curg, this
176 {
177 curg.save( ret, gts )
178 }
179 return ret
180 }
181
182 method uint gt.write( str filename, gtsave gts )
183 {
184 str stemp
185
186 if this.utf8 : stemp = "п»ї"
187 this.root().save( stemp, gts )
188 return stemp.write( filename )
189 }
190
191 method uint gt.write( str filename )
192 {
193 gtsave gts
194
195 gts.offstep = 3
196 gts.flags = $GTS_INLINE
197 return .write( filename, gts )
198 }