|
1 /****************************************************************************** |
|
2 * |
|
3 * Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). |
|
4 * |
|
5 * Permission to use, copy, modify, and distribute this software and its |
|
6 * documentation under the terms of the GNU General Public License is hereby |
|
7 * granted. No representations are made about the suitability of this software |
|
8 * for any purpose. It is provided "as is" without express or implied warranty. |
|
9 * See the GNU General Public License for more details. |
|
10 * |
|
11 */ |
|
12 |
|
13 |
|
14 |
1 #include "xmlwriter.h" |
15 #include "xmlwriter.h" |
2 #include "message.h" |
16 #include "message.h" |
|
17 #include "xmldita.h" |
3 |
18 |
4 char ILLEGAL_UNICODE_REPLACEMENT = ' '; |
19 char ILLEGAL_UNICODE_REPLACEMENT = ' '; |
5 /******************** XmlStream ********************/ |
20 /******************** XmlStream ********************/ |
6 XmlStream::XmlStream(const QString &fileName, const QString &aEncoding, const QString &aStandalone, const QString &doctypeStr) : mFile(fileName), \ |
21 XmlStream::XmlStream(const QString &fileName, const QString &aEncoding, const QString &aStandalone, const QString &doctypeStr) : mFile(fileName), \ |
7 mStreamP(0), \ |
22 mStreamP(0), \ |
8 mElemStack(), \ |
23 mElemStack(), \ |
9 mInElement(false), \ |
24 mInElement(false) |
10 mCanIndent(true) |
25 { |
11 { |
26 mCanIndentList.setAutoDelete(true); |
12 mIsOpen = mFile.open(IO_WriteOnly); |
27 mIsOpen = mFile.open(IO_WriteOnly); |
13 if (mIsOpen) { |
28 if (mIsOpen) { |
14 mStreamP = new QTextStream(&mFile); |
29 mStreamP = new QTextStream(&mFile); |
15 if (aEncoding == "UTF-8") { |
30 if (aEncoding == "UTF-8") { |
16 mStreamP->setEncoding(QTextStream::UnicodeUTF8); |
31 mStreamP->setEncoding(QTextStream::UnicodeUTF8); |
119 // Write element name |
134 // Write element name |
120 *mStreamP << "<" << aElemName; |
135 *mStreamP << "<" << aElemName; |
121 // Attributes in sorted order |
136 // Attributes in sorted order |
122 AttributeMapIter it = aAttrs.begin(); |
137 AttributeMapIter it = aAttrs.begin(); |
123 while (it != aAttrs.end()){ |
138 while (it != aAttrs.end()){ |
124 *mStreamP << " " << it.key() << "=\"" << encodeText(it.data()) << "\""; |
139 QString attrVal = encodeText(it.data()); |
|
140 #ifdef DITA_OT_BUG_ATTRIBUTE_VALUE_HACK |
|
141 // DITA Open Toolkit error, it fails to re-encode files properly |
|
142 // Replace "<" with "&lt;" |
|
143 // Replace ">" with "&gt;" |
|
144 int fIdx = 0; |
|
145 QString toFind; |
|
146 QString toReplace; |
|
147 toFind = "<"; |
|
148 toReplace = "&lt;"; |
|
149 fIdx = attrVal.find(toFind, 0); |
|
150 while (fIdx != -1) { |
|
151 attrVal.replace(fIdx, toFind.length(), toReplace); |
|
152 fIdx = attrVal.find(toFind, 0); |
|
153 } |
|
154 toFind = ">"; |
|
155 toReplace = "&gt;"; |
|
156 fIdx = attrVal.find(toFind, 0); |
|
157 while (fIdx != -1) { |
|
158 attrVal.replace(fIdx, toFind.length(), toReplace); |
|
159 fIdx = attrVal.find(toFind, 0); |
|
160 } |
|
161 #endif |
|
162 *mStreamP << " " << it.key() << "=\"" << attrVal << "\""; |
125 ++it; |
163 ++it; |
126 } |
164 } |
127 // Update internals |
165 // Update internals |
128 mInElement = true; |
166 mInElement = true; |
129 mCanIndent = true; |
167 //mCanIndent = true; |
130 mElemStack.push(&aElemName); |
168 mElemStack.push(&aElemName); |
|
169 mCanIndentList.append(new bool(true)); |
131 } |
170 } |
132 } |
171 } |
133 |
172 |
134 void XmlStream::characters(const QString& aText) |
173 void XmlStream::characters(const QString& aText) |
135 { |
174 { |
139 if (mStreamP && mIsOpen && mCanWrite) { |
178 if (mStreamP && mIsOpen && mCanWrite) { |
140 closeElementDeclIfOpen(); |
179 closeElementDeclIfOpen(); |
141 *mStreamP << encodeText(aText); |
180 *mStreamP << encodeText(aText); |
142 } |
181 } |
143 // Don't indent mixed content |
182 // Don't indent mixed content |
144 mCanIndent = false; |
183 //mCanIndent = false; |
145 } |
184 setLastIndent(false); |
|
185 } |
|
186 #ifdef DITA_TRACE |
|
187 #ifdef DITA_TRACE_TO_XML |
|
188 // Useful for assertion crashes where otherwise the buffer would be lost |
|
189 flush(*mStreamP); |
|
190 #endif |
|
191 #endif |
146 } |
192 } |
147 |
193 |
148 void XmlStream::characters(char c) |
194 void XmlStream::characters(char c) |
149 { |
195 { |
150 if (mStreamP && mIsOpen && mCanWrite) { |
196 if (mStreamP && mIsOpen && mCanWrite) { |
158 } else { |
204 } else { |
159 *mStreamP << ILLEGAL_UNICODE_REPLACEMENT; |
205 *mStreamP << ILLEGAL_UNICODE_REPLACEMENT; |
160 } |
206 } |
161 } |
207 } |
162 // Don't indent mixed content |
208 // Don't indent mixed content |
163 mCanIndent = false; |
209 //mCanIndent = false; |
|
210 setLastIndent(false); |
|
211 #ifdef DITA_TRACE |
|
212 #ifdef DITA_TRACE_TO_XML |
|
213 // Useful for assertion crashes where otherwise the buffer would be lost |
|
214 flush(*mStreamP); |
|
215 #endif |
|
216 #endif |
164 } |
217 } |
165 |
218 |
166 XmlStream& XmlStream::operator<<(const QCString& s) |
219 XmlStream& XmlStream::operator<<(const QCString& s) |
167 { |
220 { |
168 characters(s); |
221 characters(s); |
196 cmtTxt += "\""; |
249 cmtTxt += "\""; |
197 comment(cmtTxt); |
250 comment(cmtTxt); |
198 } |
251 } |
199 } |
252 } |
200 // Don't indent mixed content |
253 // Don't indent mixed content |
201 mCanIndent = false; |
254 //mCanIndent = false; |
|
255 setLastIndent(false); |
202 return *this; |
256 return *this; |
203 } |
257 } |
204 |
258 |
205 void XmlStream::processingInstruction(const QString& aText) |
259 void XmlStream::processingInstruction(const QString& aText) |
206 { |
260 { |
207 if (mStreamP && mIsOpen && mCanWrite) { |
261 if (mStreamP && mIsOpen && mCanWrite) { |
208 closeElementDeclIfOpen(); |
262 closeElementDeclIfOpen(); |
209 *mStreamP << "<?" << aText << "?>"; |
263 *mStreamP << "<?" << aText << "?>"; |
210 } |
264 } |
211 mCanIndent = true; |
265 //mCanIndent = true; |
212 } |
266 } |
213 |
267 |
214 void XmlStream::comment(const QString& aText) |
268 void XmlStream::comment(const QString& aText) |
215 { |
269 { |
216 if (mStreamP && mIsOpen && mCanWrite) { |
270 if (mStreamP && mIsOpen && mCanWrite) { |
217 closeElementDeclIfOpen(); |
271 closeElementDeclIfOpen(); |
218 *mStreamP << "<!-- " << aText << " -->"; |
272 *mStreamP << "<!-- " << aText << " -->"; |
219 } |
273 } |
220 mCanIndent = true; |
274 //mCanIndent = true; |
221 } |
275 } |
222 |
276 |
223 void XmlStream::endElement(const QString& aElemName) |
277 void XmlStream::endElement(const QString& aElemName) |
224 { |
278 { |
225 if (mStreamP && mIsOpen && mCanWrite) { |
279 if (mStreamP && mIsOpen && mCanWrite) { |
246 } |
300 } |
247 } |
301 } |
248 |
302 |
249 void XmlStream::indent(unsigned int aInitVal) |
303 void XmlStream::indent(unsigned int aInitVal) |
250 { |
304 { |
251 if (mStreamP && mIsOpen && mCanIndent && mCanWrite) { |
305 if (mStreamP && mIsOpen && canIndent() && mCanWrite) { |
252 *mStreamP << XML_OUTPUT_ENDL; |
306 *mStreamP << XML_OUTPUT_ENDL; |
253 for (unsigned int i = aInitVal; i < mElemStack.count(); i++) { |
307 for (unsigned int i = aInitVal; i < mElemStack.count(); i++) { |
254 *mStreamP << XML_INDENT; |
308 *mStreamP << XML_INDENT; |
255 } |
309 } |
256 } |
310 } |
274 // that appear in the source code from getting into the XML. |
328 // that appear in the source code from getting into the XML. |
275 bool result = (u == 0x09 || u == 0x0A || u == 0x0D || \ |
329 bool result = (u == 0x09 || u == 0x0A || u == 0x0D || \ |
276 ((u >= 0x20) && (u <= 0x7F)) \ |
330 ((u >= 0x20) && (u <= 0x7F)) \ |
277 ); |
331 ); |
278 if (!result) { |
332 if (!result) { |
279 printf("XmlStream::isLegalXmlChar() rejecting 0x%X\n", u); |
333 msg("XmlStream::isLegalXmlChar() rejecting 0x%X\n", u); |
280 } |
334 } |
281 return result; |
335 return result; |
282 } |
336 } |
283 |
337 |
284 QString XmlStream::encodeText(const QString& aStr) const |
338 QString XmlStream::encodeText(const QString& aStr) const |