1 /*-------------------------------------------------------------------------
2 * drawElements Quality Program Helper Library
3 * -------------------------------------------
5 * Copyright 2014 The Android Open Source Project
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
22 *//*--------------------------------------------------------------------*/
24 #include "qpXmlWriter.h"
29 /*------------------------------------------------------------------------
30 * qpXmlWriter stand-alone implementation.
31 *----------------------------------------------------------------------*/
33 #include "deMemPool.h"
34 #include "dePoolArray.h"
39 deBool flushAfterWrite;
41 deBool xmlPrevIsStartElement;
46 static deBool writeEscaped (qpXmlWriter* writer, const char* str)
51 deBool isEOS = DE_FALSE;
55 /* Check for characters that need to be escaped. */
56 const char* repl = DE_NULL;
59 case 0: isEOS = DE_TRUE; break;
60 case '<': repl = "<"; break;
61 case '>': repl = ">"; break;
62 case '&': repl = "&"; break;
63 case '\'': repl = "'"; break;
64 case '"': repl = """; break;
66 /* Non-printable characters. */
67 case 1: repl = "<SOH>"; break;
68 case 2: repl = "<STX>"; break;
69 case 3: repl = "<ETX>"; break;
70 case 4: repl = "<EOT>"; break;
71 case 5: repl = "<ENQ>"; break;
72 case 6: repl = "<ACK>"; break;
73 case 7: repl = "<BEL>"; break;
74 case 8: repl = "<BS>"; break;
75 case 11: repl = "<VT>"; break;
76 case 12: repl = "<FF>"; break;
77 case 14: repl = "<SO>"; break;
78 case 15: repl = "<SI>"; break;
79 case 16: repl = "<DLE>"; break;
80 case 17: repl = "<DC1>"; break;
81 case 18: repl = "<DC2>"; break;
82 case 19: repl = "<DC3>"; break;
83 case 20: repl = "<DC4>"; break;
84 case 21: repl = "<NAK>"; break;
85 case 22: repl = "<SYN>"; break;
86 case 23: repl = "<ETB>"; break;
87 case 24: repl = "<CAN>"; break;
88 case 25: repl = "<EM>"; break;
89 case 26: repl = "<SUB>"; break;
90 case 27: repl = "<ESC>"; break;
91 case 28: repl = "<FS>"; break;
92 case 29: repl = "<GS>"; break;
93 case 30: repl = "<RS>"; break;
94 case 31: repl = "<US>"; break;
96 default: /* nada */ break;
99 /* Write out char or escape sequence. */
109 /* Write buffer if EOS or buffer full. */
110 if (isEOS || ((d - &buf[0]) >= 4))
113 fprintf(writer->outputFile, "%s", buf);
118 if (writer->flushAfterWrite)
119 fflush(writer->outputFile);
120 DE_ASSERT(d == &buf[0]); /* buffer must be empty */
124 qpXmlWriter* qpXmlWriter_createFileWriter (FILE* outputFile, deBool useCompression, deBool flushAfterWrite)
126 qpXmlWriter* writer = (qpXmlWriter*)deCalloc(sizeof(qpXmlWriter));
130 DE_UNREF(useCompression); /* no compression supported. */
132 writer->outputFile = outputFile;
133 writer->flushAfterWrite = flushAfterWrite;
138 void qpXmlWriter_destroy (qpXmlWriter* writer)
145 static deBool closePending (qpXmlWriter* writer)
147 if (writer->xmlPrevIsStartElement)
149 fprintf(writer->outputFile, ">\n");
150 writer->xmlPrevIsStartElement = DE_FALSE;
156 void qpXmlWriter_flush (qpXmlWriter* writer)
158 closePending(writer);
161 deBool qpXmlWriter_startDocument (qpXmlWriter* writer)
163 DE_ASSERT(writer && !writer->xmlIsWriting);
164 writer->xmlIsWriting = DE_TRUE;
165 writer->xmlElementDepth = 0;
166 writer->xmlPrevIsStartElement = DE_FALSE;
167 fprintf(writer->outputFile, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
171 static const char* getIndentStr (int indentLevel)
173 static const char s_indentStr[33] = " ";
174 static const int s_indentStrLen = 32;
175 return &s_indentStr[s_indentStrLen - deMin32(s_indentStrLen, indentLevel)];
178 deBool qpXmlWriter_endDocument (qpXmlWriter* writer)
181 DE_ASSERT(writer->xmlIsWriting);
182 DE_ASSERT(writer->xmlElementDepth == 0);
183 closePending(writer);
184 writer->xmlIsWriting = DE_FALSE;
188 deBool qpXmlWriter_writeString (qpXmlWriter* writer, const char* str)
190 if (writer->xmlPrevIsStartElement)
192 fprintf(writer->outputFile, ">");
193 writer->xmlPrevIsStartElement = DE_FALSE;
196 return writeEscaped(writer, str);
199 deBool qpXmlWriter_startElement(qpXmlWriter* writer, const char* elementName, int numAttribs, const qpXmlAttribute* attribs)
203 closePending(writer);
205 fprintf(writer->outputFile, "%s<%s", getIndentStr(writer->xmlElementDepth), elementName);
207 for (ndx = 0; ndx < numAttribs; ndx++)
209 const qpXmlAttribute* attrib = &attribs[ndx];
210 fprintf(writer->outputFile, " %s=\"", attrib->name);
211 switch (attrib->type)
213 case QP_XML_ATTRIBUTE_STRING:
214 writeEscaped(writer, attrib->stringValue);
217 case QP_XML_ATTRIBUTE_INT:
220 sprintf(buf, "%d", attrib->intValue);
221 writeEscaped(writer, buf);
225 case QP_XML_ATTRIBUTE_BOOL:
226 writeEscaped(writer, attrib->boolValue ? "True" : "False");
232 fprintf(writer->outputFile, "\"");
235 writer->xmlElementDepth++;
236 writer->xmlPrevIsStartElement = DE_TRUE;
240 deBool qpXmlWriter_endElement (qpXmlWriter* writer, const char* elementName)
242 DE_ASSERT(writer && writer->xmlElementDepth > 0);
243 writer->xmlElementDepth--;
245 if (writer->xmlPrevIsStartElement) /* leave flag as-is */
247 fprintf(writer->outputFile, " />\n");
248 writer->xmlPrevIsStartElement = DE_FALSE;
251 fprintf(writer->outputFile, "</%s>\n", /*getIndentStr(writer->xmlElementDepth),*/ elementName);
256 deBool qpXmlWriter_writeBase64 (qpXmlWriter* writer, const deUint8* data, size_t numBytes)
258 static const char s_base64Table[64] =
260 'A','B','C','D','E','F','G','H','I','J','K','L','M',
261 'N','O','P','Q','R','S','T','U','V','W','X','Y','Z',
262 'a','b','c','d','e','f','g','h','i','j','k','l','m',
263 'n','o','p','q','r','s','t','u','v','w','x','y','z',
264 '0','1','2','3','4','5','6','7','8','9','+','/'
269 deBool writeIndent = DE_TRUE;
270 const char* indentStr = getIndentStr(writer->xmlElementDepth);
272 DE_ASSERT(writer && data && (numBytes > 0));
274 /* Close and pending writes. */
275 closePending(writer);
277 /* Loop all input chars. */
278 while (srcNdx < numBytes)
280 size_t numRead = (size_t)deMin32(3, (int)(numBytes - srcNdx));
281 deUint8 s0 = data[srcNdx];
282 deUint8 s1 = (numRead >= 2) ? data[srcNdx+1] : 0;
283 deUint8 s2 = (numRead >= 3) ? data[srcNdx+2] : 0;
288 d[0] = s_base64Table[s0 >> 2];
289 d[1] = s_base64Table[((s0&0x3)<<4) | (s1>>4)];
290 d[2] = s_base64Table[((s1&0xF)<<2) | (s2>>6)];
291 d[3] = s_base64Table[s2&0x3F];
294 if (numRead < 3) d[3] = '=';
295 if (numRead < 2) d[2] = '=';
297 /* Write indent (if needed). */
300 fprintf(writer->outputFile, "%s", indentStr);
301 writeIndent = DE_FALSE;
305 fprintf(writer->outputFile, "%s", &d[0]);
307 /* EOL every now and then. */
309 if (numWritten >= 64)
311 fprintf(writer->outputFile, "\n");
313 writeIndent = DE_TRUE;
319 fprintf(writer->outputFile, "\n");
321 DE_ASSERT(srcNdx == numBytes);
325 /* Common helper functions. */
327 deBool qpXmlWriter_writeStringElement (qpXmlWriter* writer, const char* elementName, const char* elementContent)
329 if (!qpXmlWriter_startElement(writer, elementName, 0, DE_NULL) ||
330 (elementContent && !qpXmlWriter_writeString(writer, elementContent)) ||
331 !qpXmlWriter_endElement(writer, elementName))