b311480e |
1 | // Created on: 2004-09-27 |
2 | // Created by: Pavel TELKOV |
973c2be1 |
3 | // Copyright (c) 2004-2014 OPEN CASCADE SAS |
b311480e |
4 | // |
973c2be1 |
5 | // This file is part of Open CASCADE Technology software library. |
b311480e |
6 | // |
d5f74e42 |
7 | // This library is free software; you can redistribute it and/or modify it under |
8 | // the terms of the GNU Lesser General Public License version 2.1 as published |
973c2be1 |
9 | // by the Free Software Foundation, with special exception defined in the file |
10 | // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT |
11 | // distribution for complete text of the license and disclaimer of any warranty. |
b311480e |
12 | // |
973c2be1 |
13 | // Alternatively, this file may be used under the terms of Open CASCADE |
14 | // commercial license or contractual agreement. |
7fd59977 |
15 | |
7fd59977 |
16 | |
42cf5bc1 |
17 | #include <CDM_MessageDriver.hxx> |
7fd59977 |
18 | #include <LDOM_MemManager.hxx> |
42cf5bc1 |
19 | #include <Standard_Type.hxx> |
20 | #include <TDataStd_ExtStringArray.hxx> |
21 | #include <TDF_Attribute.hxx> |
22 | #include <XmlMDataStd.hxx> |
23 | #include <XmlMDataStd_ExtStringArrayDriver.hxx> |
7fd59977 |
24 | #include <XmlObjMgt.hxx> |
25 | #include <XmlObjMgt_Document.hxx> |
42cf5bc1 |
26 | #include <XmlObjMgt_Persistent.hxx> |
c2f5b821 |
27 | #include <XmlLDrivers.hxx> |
7fd59977 |
28 | |
92efcf78 |
29 | IMPLEMENT_STANDARD_RTTIEXT(XmlMDataStd_ExtStringArrayDriver,XmlMDF_ADriver) |
7fd59977 |
30 | IMPLEMENT_DOMSTRING (FirstIndexString, "first") |
31 | IMPLEMENT_DOMSTRING (LastIndexString, "last") |
32 | IMPLEMENT_DOMSTRING (ExtString, "string") |
33 | IMPLEMENT_DOMSTRING (IsDeltaOn, "delta") |
e9947e12 |
34 | IMPLEMENT_DOMSTRING (Separator, "separator") |
35 | |
36 | // Searches for a symbol within an array of strings. |
37 | // Returns TRUE if the symbol is found. |
38 | static Standard_Boolean Contains(const Handle(TDataStd_ExtStringArray)& arr, |
39 | const TCollection_ExtendedString& c) |
40 | { |
41 | for (Standard_Integer i = arr->Lower(); i <= arr->Upper(); i++) |
42 | { |
43 | const TCollection_ExtendedString& value = arr->Value(i); |
44 | if (value.Search(c) != -1) |
45 | { |
46 | return Standard_True; |
47 | } |
48 | } |
49 | return Standard_False; |
50 | } |
51 | |
7fd59977 |
52 | //======================================================================= |
53 | //function : XmlMDataStd_ExtStringArrayDriver |
54 | //purpose : Constructor |
55 | //======================================================================= |
56 | |
57 | XmlMDataStd_ExtStringArrayDriver::XmlMDataStd_ExtStringArrayDriver |
58 | ( const Handle(CDM_MessageDriver)& theMsgDriver ) |
59 | : XmlMDF_ADriver( theMsgDriver, NULL ) |
60 | {} |
61 | |
62 | //======================================================================= |
63 | //function : NewEmpty |
64 | //purpose : |
65 | //======================================================================= |
66 | Handle(TDF_Attribute) XmlMDataStd_ExtStringArrayDriver::NewEmpty() const |
67 | { |
68 | return ( new TDataStd_ExtStringArray() ); |
69 | } |
70 | |
71 | //======================================================================= |
72 | //function : Paste |
73 | //purpose : persistent -> transient (retrieve) |
74 | //======================================================================= |
75 | Standard_Boolean XmlMDataStd_ExtStringArrayDriver::Paste |
76 | ( const XmlObjMgt_Persistent& theSource, |
77 | const Handle(TDF_Attribute)& theTarget, |
78 | XmlObjMgt_RRelocationTable& ) const |
79 | { |
80 | Standard_Integer aFirstInd, aLastInd, ind; |
81 | TCollection_ExtendedString aValue; |
82 | const XmlObjMgt_Element& anElement = theSource; |
83 | |
84 | // Read the FirstIndex; if the attribute is absent initialize to 1 |
85 | XmlObjMgt_DOMString aFirstIndex= anElement.getAttribute(::FirstIndexString()); |
86 | if (aFirstIndex == NULL) |
87 | aFirstInd = 1; |
88 | else if (!aFirstIndex.GetInteger(aFirstInd)) { |
89 | TCollection_ExtendedString aMessageString = |
90 | TCollection_ExtendedString("Cannot retrieve the first index" |
91 | " for ExtStringArray attribute as \"") |
92 | + aFirstIndex + "\""; |
93 | WriteMessage (aMessageString); |
94 | return Standard_False; |
95 | } |
96 | |
97 | // Read LastIndex; the attribute should be present |
98 | if (!anElement.getAttribute(::LastIndexString()).GetInteger(aLastInd)) { |
99 | TCollection_ExtendedString aMessageString = |
100 | TCollection_ExtendedString("Cannot retrieve the last index" |
101 | " for ExtStringArray attribute as \"") |
102 | + aFirstIndex + "\""; |
103 | WriteMessage (aMessageString); |
104 | return Standard_False; |
105 | } |
106 | |
e9947e12 |
107 | // Read separator. |
108 | TCollection_ExtendedString separator; |
109 | XmlObjMgt_DOMString aSeparator = anElement.getAttribute(::Separator()); |
110 | if (aSeparator.Type() != XmlObjMgt_DOMString::LDOM_NULL) |
111 | separator = aSeparator.GetString(); |
112 | |
7fd59977 |
113 | Handle(TDataStd_ExtStringArray) aExtStringArray = |
114 | Handle(TDataStd_ExtStringArray)::DownCast(theTarget); |
115 | aExtStringArray->Init(aFirstInd, aLastInd); |
116 | |
e9947e12 |
117 | // Read string values. |
118 | if ( !separator.Length() && anElement.hasChildNodes() ) |
7fd59977 |
119 | { |
e9947e12 |
120 | // Read values written by <string>VALUE<\string> notion - as children of the attribute. |
121 | LDOM_Node aCurNode = anElement.getFirstChild(); |
122 | LDOM_Element* aCurElement = (LDOM_Element*)&aCurNode; |
123 | TCollection_ExtendedString aValueStr; |
124 | for (ind = aFirstInd; ind <= aLastInd && *aCurElement != anElement.getLastChild(); ind++) |
125 | { |
126 | XmlObjMgt::GetExtendedString( *aCurElement, aValueStr ); |
127 | aExtStringArray->SetValue(ind, aValueStr); |
128 | aCurNode = aCurElement->getNextSibling(); |
129 | aCurElement = (LDOM_Element*)&aCurNode; |
130 | } |
7fd59977 |
131 | XmlObjMgt::GetExtendedString( *aCurElement, aValueStr ); |
e9947e12 |
132 | aExtStringArray->SetValue( aLastInd, aValueStr ); |
7fd59977 |
133 | } |
e9947e12 |
134 | else |
135 | { |
136 | TCollection_ExtendedString xstr; |
137 | XmlObjMgt::GetExtendedString(anElement, xstr); |
138 | #ifdef _DEBUG |
139 | TCollection_AsciiString cstr(xstr, '?'); |
140 | #endif |
141 | |
142 | // Split strings by the separator. |
143 | Standard_Integer isym(1); // index of symbol in xstr |
144 | Standard_ExtCharacter xsep = separator.Value(1); |
145 | for (ind = aFirstInd; ind <= aLastInd; ind++) |
146 | { |
147 | // Calculate length of the string-value. |
148 | Standard_Integer iend = isym; |
149 | while (iend < xstr.Length()) |
150 | { |
151 | if (xstr.Value(iend) == xsep) |
152 | { |
153 | break; |
154 | } |
155 | iend++; |
156 | } |
157 | if (iend <= xstr.Length() && |
158 | xstr.Value(iend) != xsep) |
159 | { |
160 | iend++; |
161 | } |
162 | |
163 | // Allocate the string-value. |
164 | TCollection_ExtendedString xvalue(iend - isym, '\0'); |
165 | |
166 | // Set string-value. |
167 | for (Standard_Integer i = isym; i < iend; ++i) |
168 | { |
169 | const Standard_ExtCharacter x = xstr.Value(i); |
170 | xvalue.SetValue(i - isym + 1, x); |
171 | } |
172 | #ifdef _DEBUG |
173 | TCollection_AsciiString cvalue(xvalue, '?'); |
174 | #endif |
7fd59977 |
175 | |
e9947e12 |
176 | // Set value for the array. |
177 | aExtStringArray->SetValue(ind, xvalue); |
7fd59977 |
178 | |
e9947e12 |
179 | // Next string-value. |
180 | isym = iend + 1; |
181 | } |
182 | } |
183 | |
184 | // Read delta-flag. |
7fd59977 |
185 | Standard_Boolean aDelta(Standard_False); |
186 | |
187 | if(XmlMDataStd::DocumentVersion() > 2) { |
188 | Standard_Integer aDeltaValue; |
189 | if (!anElement.getAttribute(::IsDeltaOn()).GetInteger(aDeltaValue)) |
190 | { |
191 | TCollection_ExtendedString aMessageString = |
192 | TCollection_ExtendedString("Cannot retrieve the isDelta value" |
193 | " for IntegerArray attribute as \"") |
194 | + aDeltaValue + "\""; |
195 | WriteMessage (aMessageString); |
196 | return Standard_False; |
197 | } |
198 | else |
dde68833 |
199 | aDelta = aDeltaValue != 0; |
7fd59977 |
200 | } |
0797d9d3 |
201 | #ifdef OCCT_DEBUG |
7fd59977 |
202 | else if(XmlMDataStd::DocumentVersion() == -1) |
203 | cout << "Current DocVersion field is not initialized. " <<endl; |
204 | #endif |
205 | aExtStringArray->SetDelta(aDelta); |
206 | |
207 | return Standard_True; |
208 | } |
209 | |
210 | //======================================================================= |
211 | //function : Paste |
212 | //purpose : transient -> persistent (store) |
213 | //======================================================================= |
214 | void XmlMDataStd_ExtStringArrayDriver::Paste (const Handle(TDF_Attribute)& theSource, |
215 | XmlObjMgt_Persistent& theTarget, |
216 | XmlObjMgt_SRelocationTable& ) const |
217 | { |
218 | Handle(TDataStd_ExtStringArray) aExtStringArray = |
219 | Handle(TDataStd_ExtStringArray)::DownCast(theSource); |
220 | |
e9947e12 |
221 | Standard_Integer aL = aExtStringArray->Lower(), anU = aExtStringArray->Upper(), i; |
7fd59977 |
222 | |
223 | XmlObjMgt_Element& anElement = theTarget; |
224 | |
225 | if (aL != 1) anElement.setAttribute(::FirstIndexString(), aL); |
226 | anElement.setAttribute(::LastIndexString(), anU); |
dde68833 |
227 | anElement.setAttribute(::IsDeltaOn(), aExtStringArray->GetDelta() ? 1 : 0); |
7fd59977 |
228 | |
e9947e12 |
229 | // Find a separator. |
230 | Standard_Boolean found(Standard_True); |
c2f5b821 |
231 | // Optimization of storage of string array elements. |
232 | // It is applied since the storage version 8 and newer. |
e9947e12 |
233 | Standard_Character c = '-'; |
c2f5b821 |
234 | if (XmlLDrivers::StorageVersion() > 7) |
e9947e12 |
235 | { |
c2f5b821 |
236 | // Preferrable symbols for the separator: - _ . : ^ ~ |
237 | // Don't use a space as a separator: XML low-level parser sometimes "eats" it. |
238 | static Standard_Character aPreferable[] = "-_.:^~"; |
239 | for (i = 0; found && aPreferable[i]; i++) |
240 | { |
241 | c = aPreferable[i]; |
242 | found = Contains(aExtStringArray, TCollection_ExtendedString(c)); |
243 | } |
244 | // If all prefferable symbols exist in the array, |
245 | // try to use any other simple symbols. |
246 | if (found) |
e9947e12 |
247 | { |
c2f5b821 |
248 | c = '!'; |
249 | while (found && c < '~') |
250 | { |
251 | found = Standard_False; |
e9947e12 |
252 | #ifdef _DEBUG |
c2f5b821 |
253 | TCollection_AsciiString cseparator(c); // deb |
e9947e12 |
254 | #endif |
c2f5b821 |
255 | TCollection_ExtendedString separator(c); |
256 | found = Contains(aExtStringArray, separator); |
257 | if (found) |
e9947e12 |
258 | { |
259 | c++; |
c2f5b821 |
260 | // Skip forbidden symbols for XML. |
261 | while (c < '~' && (c == '&' || c == '<')) |
262 | { |
263 | c++; |
264 | } |
e9947e12 |
265 | } |
266 | } |
267 | } |
c2f5b821 |
268 | }// check doc version |
7fd59977 |
269 | |
e9947e12 |
270 | if (found) |
7fd59977 |
271 | { |
e9947e12 |
272 | // There is no unique separator. Use child elements for storage of strings of the array. |
273 | |
274 | // store a set of elements with string in each of them |
275 | XmlObjMgt_Document aDoc (anElement.getOwnerDocument()); |
276 | for ( i = aL; i <= anU; i++ ) |
277 | { |
278 | const TCollection_ExtendedString& aValueStr = aExtStringArray->Value( i ); |
279 | XmlObjMgt_Element aCurTarget = aDoc.createElement( ::ExtString() ); |
280 | XmlObjMgt::SetExtendedString( aCurTarget, aValueStr ); |
281 | anElement.appendChild( aCurTarget ); |
282 | } |
283 | } |
284 | else |
285 | { |
286 | // Set the separator. |
287 | TCollection_AsciiString csep(c); |
288 | anElement.setAttribute(::Separator(), csep.ToCString()); |
289 | |
290 | // Calculate length of the common string. |
291 | Standard_Integer len(0); |
292 | for (i = aL; i <= anU; i++) |
293 | { |
294 | const TCollection_ExtendedString& aValueStr = aExtStringArray->Value(i); |
295 | len += aValueStr.Length(); |
296 | len++; // for separator or ending \0 symbol |
297 | } |
298 | if (!len) |
299 | len++; // for end of line \0 symbol |
300 | |
301 | // Merge all strings of the array into one extended string separated by the "separator". |
302 | Standard_Integer isym(1); |
303 | TCollection_ExtendedString xstr(len, c); |
304 | for (i = aL; i <= anU; i++) |
305 | { |
306 | const TCollection_ExtendedString& aValueStr = aExtStringArray->Value(i); |
307 | for (Standard_Integer k = 1; k <= aValueStr.Length(); k++) |
308 | { |
309 | xstr.SetValue(isym++, aValueStr.Value(k)); |
310 | } |
311 | xstr.SetValue(isym++, c); |
312 | } |
313 | if (xstr.SearchFromEnd(c) == isym - 1) |
314 | isym--; // replace the last separator by '\0' |
315 | xstr.SetValue(isym, '\0'); |
316 | #ifdef _DEBUG |
317 | TCollection_AsciiString cstr(xstr, '?'); // deb |
318 | #endif |
319 | |
320 | // Set UNICODE value. |
321 | XmlObjMgt::SetExtendedString(theTarget, xstr); |
7fd59977 |
322 | } |
323 | } |