xref: /aosp_15_r20/external/deqp/framework/qphelper/qpXmlWriter.c (revision 35238bce31c2a825756842865a792f8cf7f89930)
1*35238bceSAndroid Build Coastguard Worker /*-------------------------------------------------------------------------
2*35238bceSAndroid Build Coastguard Worker  * drawElements Quality Program Helper Library
3*35238bceSAndroid Build Coastguard Worker  * -------------------------------------------
4*35238bceSAndroid Build Coastguard Worker  *
5*35238bceSAndroid Build Coastguard Worker  * Copyright 2014 The Android Open Source Project
6*35238bceSAndroid Build Coastguard Worker  *
7*35238bceSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
8*35238bceSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
9*35238bceSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
10*35238bceSAndroid Build Coastguard Worker  *
11*35238bceSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
12*35238bceSAndroid Build Coastguard Worker  *
13*35238bceSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
14*35238bceSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
15*35238bceSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16*35238bceSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
17*35238bceSAndroid Build Coastguard Worker  * limitations under the License.
18*35238bceSAndroid Build Coastguard Worker  *
19*35238bceSAndroid Build Coastguard Worker  *//*!
20*35238bceSAndroid Build Coastguard Worker  * \file
21*35238bceSAndroid Build Coastguard Worker  * \brief XML Writer.
22*35238bceSAndroid Build Coastguard Worker  *//*--------------------------------------------------------------------*/
23*35238bceSAndroid Build Coastguard Worker 
24*35238bceSAndroid Build Coastguard Worker #include "qpXmlWriter.h"
25*35238bceSAndroid Build Coastguard Worker 
26*35238bceSAndroid Build Coastguard Worker #include "deMemory.h"
27*35238bceSAndroid Build Coastguard Worker #include "deInt32.h"
28*35238bceSAndroid Build Coastguard Worker 
29*35238bceSAndroid Build Coastguard Worker /*------------------------------------------------------------------------
30*35238bceSAndroid Build Coastguard Worker  * qpXmlWriter stand-alone implementation.
31*35238bceSAndroid Build Coastguard Worker  *----------------------------------------------------------------------*/
32*35238bceSAndroid Build Coastguard Worker 
33*35238bceSAndroid Build Coastguard Worker #include "deMemPool.h"
34*35238bceSAndroid Build Coastguard Worker #include "dePoolArray.h"
35*35238bceSAndroid Build Coastguard Worker 
36*35238bceSAndroid Build Coastguard Worker struct qpXmlWriter_s
37*35238bceSAndroid Build Coastguard Worker {
38*35238bceSAndroid Build Coastguard Worker     FILE *outputFile;
39*35238bceSAndroid Build Coastguard Worker     bool flushAfterWrite;
40*35238bceSAndroid Build Coastguard Worker 
41*35238bceSAndroid Build Coastguard Worker     bool xmlPrevIsStartElement;
42*35238bceSAndroid Build Coastguard Worker     bool xmlIsWriting;
43*35238bceSAndroid Build Coastguard Worker     int xmlElementDepth;
44*35238bceSAndroid Build Coastguard Worker };
45*35238bceSAndroid Build Coastguard Worker 
writeEscaped(qpXmlWriter * writer,const char * str)46*35238bceSAndroid Build Coastguard Worker static bool writeEscaped(qpXmlWriter *writer, const char *str)
47*35238bceSAndroid Build Coastguard Worker {
48*35238bceSAndroid Build Coastguard Worker     char buf[256 + 10];
49*35238bceSAndroid Build Coastguard Worker     char *d       = &buf[0];
50*35238bceSAndroid Build Coastguard Worker     const char *s = str;
51*35238bceSAndroid Build Coastguard Worker     bool isEOS    = false;
52*35238bceSAndroid Build Coastguard Worker 
53*35238bceSAndroid Build Coastguard Worker     do
54*35238bceSAndroid Build Coastguard Worker     {
55*35238bceSAndroid Build Coastguard Worker         /* Check for characters that need to be escaped. */
56*35238bceSAndroid Build Coastguard Worker         const char *repl = DE_NULL;
57*35238bceSAndroid Build Coastguard Worker         switch (*s)
58*35238bceSAndroid Build Coastguard Worker         {
59*35238bceSAndroid Build Coastguard Worker         case 0:
60*35238bceSAndroid Build Coastguard Worker             isEOS = true;
61*35238bceSAndroid Build Coastguard Worker             break;
62*35238bceSAndroid Build Coastguard Worker         case '<':
63*35238bceSAndroid Build Coastguard Worker             repl = "&lt;";
64*35238bceSAndroid Build Coastguard Worker             break;
65*35238bceSAndroid Build Coastguard Worker         case '>':
66*35238bceSAndroid Build Coastguard Worker             repl = "&gt;";
67*35238bceSAndroid Build Coastguard Worker             break;
68*35238bceSAndroid Build Coastguard Worker         case '&':
69*35238bceSAndroid Build Coastguard Worker             repl = "&amp;";
70*35238bceSAndroid Build Coastguard Worker             break;
71*35238bceSAndroid Build Coastguard Worker         case '\'':
72*35238bceSAndroid Build Coastguard Worker             repl = "&apos;";
73*35238bceSAndroid Build Coastguard Worker             break;
74*35238bceSAndroid Build Coastguard Worker         case '"':
75*35238bceSAndroid Build Coastguard Worker             repl = "&quot;";
76*35238bceSAndroid Build Coastguard Worker             break;
77*35238bceSAndroid Build Coastguard Worker 
78*35238bceSAndroid Build Coastguard Worker         /* Non-printable characters. */
79*35238bceSAndroid Build Coastguard Worker         case 1:
80*35238bceSAndroid Build Coastguard Worker             repl = "&lt;SOH&gt;";
81*35238bceSAndroid Build Coastguard Worker             break;
82*35238bceSAndroid Build Coastguard Worker         case 2:
83*35238bceSAndroid Build Coastguard Worker             repl = "&lt;STX&gt;";
84*35238bceSAndroid Build Coastguard Worker             break;
85*35238bceSAndroid Build Coastguard Worker         case 3:
86*35238bceSAndroid Build Coastguard Worker             repl = "&lt;ETX&gt;";
87*35238bceSAndroid Build Coastguard Worker             break;
88*35238bceSAndroid Build Coastguard Worker         case 4:
89*35238bceSAndroid Build Coastguard Worker             repl = "&lt;EOT&gt;";
90*35238bceSAndroid Build Coastguard Worker             break;
91*35238bceSAndroid Build Coastguard Worker         case 5:
92*35238bceSAndroid Build Coastguard Worker             repl = "&lt;ENQ&gt;";
93*35238bceSAndroid Build Coastguard Worker             break;
94*35238bceSAndroid Build Coastguard Worker         case 6:
95*35238bceSAndroid Build Coastguard Worker             repl = "&lt;ACK&gt;";
96*35238bceSAndroid Build Coastguard Worker             break;
97*35238bceSAndroid Build Coastguard Worker         case 7:
98*35238bceSAndroid Build Coastguard Worker             repl = "&lt;BEL&gt;";
99*35238bceSAndroid Build Coastguard Worker             break;
100*35238bceSAndroid Build Coastguard Worker         case 8:
101*35238bceSAndroid Build Coastguard Worker             repl = "&lt;BS&gt;";
102*35238bceSAndroid Build Coastguard Worker             break;
103*35238bceSAndroid Build Coastguard Worker         case 11:
104*35238bceSAndroid Build Coastguard Worker             repl = "&lt;VT&gt;";
105*35238bceSAndroid Build Coastguard Worker             break;
106*35238bceSAndroid Build Coastguard Worker         case 12:
107*35238bceSAndroid Build Coastguard Worker             repl = "&lt;FF&gt;";
108*35238bceSAndroid Build Coastguard Worker             break;
109*35238bceSAndroid Build Coastguard Worker         case 14:
110*35238bceSAndroid Build Coastguard Worker             repl = "&lt;SO&gt;";
111*35238bceSAndroid Build Coastguard Worker             break;
112*35238bceSAndroid Build Coastguard Worker         case 15:
113*35238bceSAndroid Build Coastguard Worker             repl = "&lt;SI&gt;";
114*35238bceSAndroid Build Coastguard Worker             break;
115*35238bceSAndroid Build Coastguard Worker         case 16:
116*35238bceSAndroid Build Coastguard Worker             repl = "&lt;DLE&gt;";
117*35238bceSAndroid Build Coastguard Worker             break;
118*35238bceSAndroid Build Coastguard Worker         case 17:
119*35238bceSAndroid Build Coastguard Worker             repl = "&lt;DC1&gt;";
120*35238bceSAndroid Build Coastguard Worker             break;
121*35238bceSAndroid Build Coastguard Worker         case 18:
122*35238bceSAndroid Build Coastguard Worker             repl = "&lt;DC2&gt;";
123*35238bceSAndroid Build Coastguard Worker             break;
124*35238bceSAndroid Build Coastguard Worker         case 19:
125*35238bceSAndroid Build Coastguard Worker             repl = "&lt;DC3&gt;";
126*35238bceSAndroid Build Coastguard Worker             break;
127*35238bceSAndroid Build Coastguard Worker         case 20:
128*35238bceSAndroid Build Coastguard Worker             repl = "&lt;DC4&gt;";
129*35238bceSAndroid Build Coastguard Worker             break;
130*35238bceSAndroid Build Coastguard Worker         case 21:
131*35238bceSAndroid Build Coastguard Worker             repl = "&lt;NAK&gt;";
132*35238bceSAndroid Build Coastguard Worker             break;
133*35238bceSAndroid Build Coastguard Worker         case 22:
134*35238bceSAndroid Build Coastguard Worker             repl = "&lt;SYN&gt;";
135*35238bceSAndroid Build Coastguard Worker             break;
136*35238bceSAndroid Build Coastguard Worker         case 23:
137*35238bceSAndroid Build Coastguard Worker             repl = "&lt;ETB&gt;";
138*35238bceSAndroid Build Coastguard Worker             break;
139*35238bceSAndroid Build Coastguard Worker         case 24:
140*35238bceSAndroid Build Coastguard Worker             repl = "&lt;CAN&gt;";
141*35238bceSAndroid Build Coastguard Worker             break;
142*35238bceSAndroid Build Coastguard Worker         case 25:
143*35238bceSAndroid Build Coastguard Worker             repl = "&lt;EM&gt;";
144*35238bceSAndroid Build Coastguard Worker             break;
145*35238bceSAndroid Build Coastguard Worker         case 26:
146*35238bceSAndroid Build Coastguard Worker             repl = "&lt;SUB&gt;";
147*35238bceSAndroid Build Coastguard Worker             break;
148*35238bceSAndroid Build Coastguard Worker         case 27:
149*35238bceSAndroid Build Coastguard Worker             repl = "&lt;ESC&gt;";
150*35238bceSAndroid Build Coastguard Worker             break;
151*35238bceSAndroid Build Coastguard Worker         case 28:
152*35238bceSAndroid Build Coastguard Worker             repl = "&lt;FS&gt;";
153*35238bceSAndroid Build Coastguard Worker             break;
154*35238bceSAndroid Build Coastguard Worker         case 29:
155*35238bceSAndroid Build Coastguard Worker             repl = "&lt;GS&gt;";
156*35238bceSAndroid Build Coastguard Worker             break;
157*35238bceSAndroid Build Coastguard Worker         case 30:
158*35238bceSAndroid Build Coastguard Worker             repl = "&lt;RS&gt;";
159*35238bceSAndroid Build Coastguard Worker             break;
160*35238bceSAndroid Build Coastguard Worker         case 31:
161*35238bceSAndroid Build Coastguard Worker             repl = "&lt;US&gt;";
162*35238bceSAndroid Build Coastguard Worker             break;
163*35238bceSAndroid Build Coastguard Worker 
164*35238bceSAndroid Build Coastguard Worker         default: /* nada */
165*35238bceSAndroid Build Coastguard Worker             break;
166*35238bceSAndroid Build Coastguard Worker         }
167*35238bceSAndroid Build Coastguard Worker 
168*35238bceSAndroid Build Coastguard Worker         /* Write out char or escape sequence. */
169*35238bceSAndroid Build Coastguard Worker         if (repl)
170*35238bceSAndroid Build Coastguard Worker         {
171*35238bceSAndroid Build Coastguard Worker             s++;
172*35238bceSAndroid Build Coastguard Worker             strcpy(d, repl);
173*35238bceSAndroid Build Coastguard Worker             d += strlen(repl);
174*35238bceSAndroid Build Coastguard Worker         }
175*35238bceSAndroid Build Coastguard Worker         else
176*35238bceSAndroid Build Coastguard Worker             *d++ = *s++;
177*35238bceSAndroid Build Coastguard Worker 
178*35238bceSAndroid Build Coastguard Worker         /* Write buffer if EOS or buffer full. */
179*35238bceSAndroid Build Coastguard Worker         if (isEOS || ((d - &buf[0]) >= 4))
180*35238bceSAndroid Build Coastguard Worker         {
181*35238bceSAndroid Build Coastguard Worker             *d = 0;
182*35238bceSAndroid Build Coastguard Worker             fputs(buf, writer->outputFile);
183*35238bceSAndroid Build Coastguard Worker             d = &buf[0];
184*35238bceSAndroid Build Coastguard Worker         }
185*35238bceSAndroid Build Coastguard Worker     } while (!isEOS);
186*35238bceSAndroid Build Coastguard Worker 
187*35238bceSAndroid Build Coastguard Worker     if (writer->flushAfterWrite)
188*35238bceSAndroid Build Coastguard Worker         fflush(writer->outputFile);
189*35238bceSAndroid Build Coastguard Worker     DE_ASSERT(d == &buf[0]); /* buffer must be empty */
190*35238bceSAndroid Build Coastguard Worker     return true;
191*35238bceSAndroid Build Coastguard Worker }
192*35238bceSAndroid Build Coastguard Worker 
qpXmlWriter_createFileWriter(FILE * outputFile,bool useCompression,bool flushAfterWrite)193*35238bceSAndroid Build Coastguard Worker qpXmlWriter *qpXmlWriter_createFileWriter(FILE *outputFile, bool useCompression, bool flushAfterWrite)
194*35238bceSAndroid Build Coastguard Worker {
195*35238bceSAndroid Build Coastguard Worker     qpXmlWriter *writer = (qpXmlWriter *)deCalloc(sizeof(qpXmlWriter));
196*35238bceSAndroid Build Coastguard Worker     if (!writer)
197*35238bceSAndroid Build Coastguard Worker         return DE_NULL;
198*35238bceSAndroid Build Coastguard Worker 
199*35238bceSAndroid Build Coastguard Worker     DE_UNREF(useCompression); /* no compression supported. */
200*35238bceSAndroid Build Coastguard Worker 
201*35238bceSAndroid Build Coastguard Worker     writer->outputFile      = outputFile;
202*35238bceSAndroid Build Coastguard Worker     writer->flushAfterWrite = flushAfterWrite;
203*35238bceSAndroid Build Coastguard Worker 
204*35238bceSAndroid Build Coastguard Worker     return writer;
205*35238bceSAndroid Build Coastguard Worker }
206*35238bceSAndroid Build Coastguard Worker 
qpXmlWriter_destroy(qpXmlWriter * writer)207*35238bceSAndroid Build Coastguard Worker void qpXmlWriter_destroy(qpXmlWriter *writer)
208*35238bceSAndroid Build Coastguard Worker {
209*35238bceSAndroid Build Coastguard Worker     DE_ASSERT(writer);
210*35238bceSAndroid Build Coastguard Worker 
211*35238bceSAndroid Build Coastguard Worker     deFree(writer);
212*35238bceSAndroid Build Coastguard Worker }
213*35238bceSAndroid Build Coastguard Worker 
closePending(qpXmlWriter * writer)214*35238bceSAndroid Build Coastguard Worker static bool closePending(qpXmlWriter *writer)
215*35238bceSAndroid Build Coastguard Worker {
216*35238bceSAndroid Build Coastguard Worker     if (writer->xmlPrevIsStartElement)
217*35238bceSAndroid Build Coastguard Worker     {
218*35238bceSAndroid Build Coastguard Worker         fprintf(writer->outputFile, ">\n");
219*35238bceSAndroid Build Coastguard Worker         writer->xmlPrevIsStartElement = false;
220*35238bceSAndroid Build Coastguard Worker     }
221*35238bceSAndroid Build Coastguard Worker 
222*35238bceSAndroid Build Coastguard Worker     return true;
223*35238bceSAndroid Build Coastguard Worker }
224*35238bceSAndroid Build Coastguard Worker 
qpXmlWriter_flush(qpXmlWriter * writer)225*35238bceSAndroid Build Coastguard Worker void qpXmlWriter_flush(qpXmlWriter *writer)
226*35238bceSAndroid Build Coastguard Worker {
227*35238bceSAndroid Build Coastguard Worker     closePending(writer);
228*35238bceSAndroid Build Coastguard Worker }
229*35238bceSAndroid Build Coastguard Worker 
qpXmlWriter_startDocument(qpXmlWriter * writer,bool writeXmlHeader)230*35238bceSAndroid Build Coastguard Worker bool qpXmlWriter_startDocument(qpXmlWriter *writer, bool writeXmlHeader)
231*35238bceSAndroid Build Coastguard Worker {
232*35238bceSAndroid Build Coastguard Worker     DE_ASSERT(writer && !writer->xmlIsWriting);
233*35238bceSAndroid Build Coastguard Worker     writer->xmlIsWriting          = true;
234*35238bceSAndroid Build Coastguard Worker     writer->xmlElementDepth       = 0;
235*35238bceSAndroid Build Coastguard Worker     writer->xmlPrevIsStartElement = false;
236*35238bceSAndroid Build Coastguard Worker     if (writeXmlHeader)
237*35238bceSAndroid Build Coastguard Worker     {
238*35238bceSAndroid Build Coastguard Worker         fprintf(writer->outputFile, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
239*35238bceSAndroid Build Coastguard Worker     }
240*35238bceSAndroid Build Coastguard Worker     return true;
241*35238bceSAndroid Build Coastguard Worker }
242*35238bceSAndroid Build Coastguard Worker 
getIndentStr(int indentLevel)243*35238bceSAndroid Build Coastguard Worker static const char *getIndentStr(int indentLevel)
244*35238bceSAndroid Build Coastguard Worker {
245*35238bceSAndroid Build Coastguard Worker     static const char s_indentStr[33] = "                                ";
246*35238bceSAndroid Build Coastguard Worker     static const int s_indentStrLen   = 32;
247*35238bceSAndroid Build Coastguard Worker     return &s_indentStr[s_indentStrLen - deMin32(s_indentStrLen, indentLevel)];
248*35238bceSAndroid Build Coastguard Worker }
249*35238bceSAndroid Build Coastguard Worker 
qpXmlWriter_endDocument(qpXmlWriter * writer)250*35238bceSAndroid Build Coastguard Worker bool qpXmlWriter_endDocument(qpXmlWriter *writer)
251*35238bceSAndroid Build Coastguard Worker {
252*35238bceSAndroid Build Coastguard Worker     DE_ASSERT(writer);
253*35238bceSAndroid Build Coastguard Worker     DE_ASSERT(writer->xmlIsWriting);
254*35238bceSAndroid Build Coastguard Worker     DE_ASSERT(writer->xmlElementDepth == 0);
255*35238bceSAndroid Build Coastguard Worker     closePending(writer);
256*35238bceSAndroid Build Coastguard Worker     writer->xmlIsWriting = false;
257*35238bceSAndroid Build Coastguard Worker     return true;
258*35238bceSAndroid Build Coastguard Worker }
259*35238bceSAndroid Build Coastguard Worker 
qpXmlWriter_writeString(qpXmlWriter * writer,const char * str)260*35238bceSAndroid Build Coastguard Worker bool qpXmlWriter_writeString(qpXmlWriter *writer, const char *str)
261*35238bceSAndroid Build Coastguard Worker {
262*35238bceSAndroid Build Coastguard Worker     if (writer->xmlPrevIsStartElement)
263*35238bceSAndroid Build Coastguard Worker     {
264*35238bceSAndroid Build Coastguard Worker         fprintf(writer->outputFile, ">");
265*35238bceSAndroid Build Coastguard Worker         writer->xmlPrevIsStartElement = false;
266*35238bceSAndroid Build Coastguard Worker     }
267*35238bceSAndroid Build Coastguard Worker 
268*35238bceSAndroid Build Coastguard Worker     return writeEscaped(writer, str);
269*35238bceSAndroid Build Coastguard Worker }
270*35238bceSAndroid Build Coastguard Worker 
qpXmlWriter_startElement(qpXmlWriter * writer,const char * elementName,int numAttribs,const qpXmlAttribute * attribs)271*35238bceSAndroid Build Coastguard Worker bool qpXmlWriter_startElement(qpXmlWriter *writer, const char *elementName, int numAttribs,
272*35238bceSAndroid Build Coastguard Worker                               const qpXmlAttribute *attribs)
273*35238bceSAndroid Build Coastguard Worker {
274*35238bceSAndroid Build Coastguard Worker     int ndx;
275*35238bceSAndroid Build Coastguard Worker 
276*35238bceSAndroid Build Coastguard Worker     closePending(writer);
277*35238bceSAndroid Build Coastguard Worker 
278*35238bceSAndroid Build Coastguard Worker     fprintf(writer->outputFile, "%s<%s", getIndentStr(writer->xmlElementDepth), elementName);
279*35238bceSAndroid Build Coastguard Worker 
280*35238bceSAndroid Build Coastguard Worker     for (ndx = 0; ndx < numAttribs; ndx++)
281*35238bceSAndroid Build Coastguard Worker     {
282*35238bceSAndroid Build Coastguard Worker         const qpXmlAttribute *attrib = &attribs[ndx];
283*35238bceSAndroid Build Coastguard Worker         fprintf(writer->outputFile, " %s=\"", attrib->name);
284*35238bceSAndroid Build Coastguard Worker         switch (attrib->type)
285*35238bceSAndroid Build Coastguard Worker         {
286*35238bceSAndroid Build Coastguard Worker         case QP_XML_ATTRIBUTE_STRING:
287*35238bceSAndroid Build Coastguard Worker             writeEscaped(writer, attrib->stringValue);
288*35238bceSAndroid Build Coastguard Worker             break;
289*35238bceSAndroid Build Coastguard Worker 
290*35238bceSAndroid Build Coastguard Worker         case QP_XML_ATTRIBUTE_INT:
291*35238bceSAndroid Build Coastguard Worker         {
292*35238bceSAndroid Build Coastguard Worker             char buf[64];
293*35238bceSAndroid Build Coastguard Worker             sprintf(buf, "%d", attrib->intValue);
294*35238bceSAndroid Build Coastguard Worker             writeEscaped(writer, buf);
295*35238bceSAndroid Build Coastguard Worker             break;
296*35238bceSAndroid Build Coastguard Worker         }
297*35238bceSAndroid Build Coastguard Worker 
298*35238bceSAndroid Build Coastguard Worker         case QP_XML_ATTRIBUTE_BOOL:
299*35238bceSAndroid Build Coastguard Worker             writeEscaped(writer, attrib->boolValue ? "True" : "False");
300*35238bceSAndroid Build Coastguard Worker             break;
301*35238bceSAndroid Build Coastguard Worker 
302*35238bceSAndroid Build Coastguard Worker         default:
303*35238bceSAndroid Build Coastguard Worker             DE_ASSERT(false);
304*35238bceSAndroid Build Coastguard Worker         }
305*35238bceSAndroid Build Coastguard Worker         fprintf(writer->outputFile, "\"");
306*35238bceSAndroid Build Coastguard Worker     }
307*35238bceSAndroid Build Coastguard Worker 
308*35238bceSAndroid Build Coastguard Worker     writer->xmlElementDepth++;
309*35238bceSAndroid Build Coastguard Worker     writer->xmlPrevIsStartElement = true;
310*35238bceSAndroid Build Coastguard Worker     return true;
311*35238bceSAndroid Build Coastguard Worker }
312*35238bceSAndroid Build Coastguard Worker 
qpXmlWriter_endElement(qpXmlWriter * writer,const char * elementName)313*35238bceSAndroid Build Coastguard Worker bool qpXmlWriter_endElement(qpXmlWriter *writer, const char *elementName)
314*35238bceSAndroid Build Coastguard Worker {
315*35238bceSAndroid Build Coastguard Worker     DE_ASSERT(writer && writer->xmlElementDepth > 0);
316*35238bceSAndroid Build Coastguard Worker     writer->xmlElementDepth--;
317*35238bceSAndroid Build Coastguard Worker 
318*35238bceSAndroid Build Coastguard Worker     if (writer->xmlPrevIsStartElement) /* leave flag as-is */
319*35238bceSAndroid Build Coastguard Worker     {
320*35238bceSAndroid Build Coastguard Worker         fprintf(writer->outputFile, " />\n");
321*35238bceSAndroid Build Coastguard Worker         writer->xmlPrevIsStartElement = false;
322*35238bceSAndroid Build Coastguard Worker     }
323*35238bceSAndroid Build Coastguard Worker     else
324*35238bceSAndroid Build Coastguard Worker         fprintf(writer->outputFile, "</%s>\n", /*getIndentStr(writer->xmlElementDepth),*/ elementName);
325*35238bceSAndroid Build Coastguard Worker 
326*35238bceSAndroid Build Coastguard Worker     return true;
327*35238bceSAndroid Build Coastguard Worker }
328*35238bceSAndroid Build Coastguard Worker 
qpXmlWriter_writeBase64(qpXmlWriter * writer,const uint8_t * data,size_t numBytes)329*35238bceSAndroid Build Coastguard Worker bool qpXmlWriter_writeBase64(qpXmlWriter *writer, const uint8_t *data, size_t numBytes)
330*35238bceSAndroid Build Coastguard Worker {
331*35238bceSAndroid Build Coastguard Worker     static const char s_base64Table[64] = {
332*35238bceSAndroid Build Coastguard Worker         'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
333*35238bceSAndroid Build Coastguard Worker         'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r',
334*35238bceSAndroid Build Coastguard Worker         's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'};
335*35238bceSAndroid Build Coastguard Worker 
336*35238bceSAndroid Build Coastguard Worker     int numWritten        = 0;
337*35238bceSAndroid Build Coastguard Worker     size_t srcNdx         = 0;
338*35238bceSAndroid Build Coastguard Worker     bool writeIndent      = true;
339*35238bceSAndroid Build Coastguard Worker     const char *indentStr = getIndentStr(writer->xmlElementDepth);
340*35238bceSAndroid Build Coastguard Worker 
341*35238bceSAndroid Build Coastguard Worker     DE_ASSERT(writer && data && (numBytes > 0));
342*35238bceSAndroid Build Coastguard Worker 
343*35238bceSAndroid Build Coastguard Worker     /* Close and pending writes. */
344*35238bceSAndroid Build Coastguard Worker     closePending(writer);
345*35238bceSAndroid Build Coastguard Worker 
346*35238bceSAndroid Build Coastguard Worker     /* Loop all input chars. */
347*35238bceSAndroid Build Coastguard Worker     while (srcNdx < numBytes)
348*35238bceSAndroid Build Coastguard Worker     {
349*35238bceSAndroid Build Coastguard Worker         size_t numRead = (size_t)deMin32(3, (int)(numBytes - srcNdx));
350*35238bceSAndroid Build Coastguard Worker         uint8_t s0     = data[srcNdx];
351*35238bceSAndroid Build Coastguard Worker         uint8_t s1     = (numRead >= 2) ? data[srcNdx + 1] : 0;
352*35238bceSAndroid Build Coastguard Worker         uint8_t s2     = (numRead >= 3) ? data[srcNdx + 2] : 0;
353*35238bceSAndroid Build Coastguard Worker         char d[5];
354*35238bceSAndroid Build Coastguard Worker 
355*35238bceSAndroid Build Coastguard Worker         srcNdx += numRead;
356*35238bceSAndroid Build Coastguard Worker 
357*35238bceSAndroid Build Coastguard Worker         d[0] = s_base64Table[s0 >> 2];
358*35238bceSAndroid Build Coastguard Worker         d[1] = s_base64Table[((s0 & 0x3) << 4) | (s1 >> 4)];
359*35238bceSAndroid Build Coastguard Worker         d[2] = s_base64Table[((s1 & 0xF) << 2) | (s2 >> 6)];
360*35238bceSAndroid Build Coastguard Worker         d[3] = s_base64Table[s2 & 0x3F];
361*35238bceSAndroid Build Coastguard Worker         d[4] = 0;
362*35238bceSAndroid Build Coastguard Worker 
363*35238bceSAndroid Build Coastguard Worker         if (numRead < 3)
364*35238bceSAndroid Build Coastguard Worker             d[3] = '=';
365*35238bceSAndroid Build Coastguard Worker         if (numRead < 2)
366*35238bceSAndroid Build Coastguard Worker             d[2] = '=';
367*35238bceSAndroid Build Coastguard Worker 
368*35238bceSAndroid Build Coastguard Worker         /* Write indent (if needed). */
369*35238bceSAndroid Build Coastguard Worker         if (writeIndent)
370*35238bceSAndroid Build Coastguard Worker         {
371*35238bceSAndroid Build Coastguard Worker             fprintf(writer->outputFile, "%s", indentStr);
372*35238bceSAndroid Build Coastguard Worker             writeIndent = false;
373*35238bceSAndroid Build Coastguard Worker         }
374*35238bceSAndroid Build Coastguard Worker 
375*35238bceSAndroid Build Coastguard Worker         /* Write data. */
376*35238bceSAndroid Build Coastguard Worker         fprintf(writer->outputFile, "%s", &d[0]);
377*35238bceSAndroid Build Coastguard Worker 
378*35238bceSAndroid Build Coastguard Worker         /* EOL every now and then. */
379*35238bceSAndroid Build Coastguard Worker         numWritten += 4;
380*35238bceSAndroid Build Coastguard Worker         if (numWritten >= 64)
381*35238bceSAndroid Build Coastguard Worker         {
382*35238bceSAndroid Build Coastguard Worker             fprintf(writer->outputFile, "\n");
383*35238bceSAndroid Build Coastguard Worker             numWritten  = 0;
384*35238bceSAndroid Build Coastguard Worker             writeIndent = true;
385*35238bceSAndroid Build Coastguard Worker         }
386*35238bceSAndroid Build Coastguard Worker     }
387*35238bceSAndroid Build Coastguard Worker 
388*35238bceSAndroid Build Coastguard Worker     /* Last EOL. */
389*35238bceSAndroid Build Coastguard Worker     if (numWritten > 0)
390*35238bceSAndroid Build Coastguard Worker         fprintf(writer->outputFile, "\n");
391*35238bceSAndroid Build Coastguard Worker 
392*35238bceSAndroid Build Coastguard Worker     DE_ASSERT(srcNdx == numBytes);
393*35238bceSAndroid Build Coastguard Worker     return true;
394*35238bceSAndroid Build Coastguard Worker }
395*35238bceSAndroid Build Coastguard Worker 
396*35238bceSAndroid Build Coastguard Worker /* Common helper functions. */
397*35238bceSAndroid Build Coastguard Worker 
qpXmlWriter_writeStringElement(qpXmlWriter * writer,const char * elementName,const char * elementContent)398*35238bceSAndroid Build Coastguard Worker bool qpXmlWriter_writeStringElement(qpXmlWriter *writer, const char *elementName, const char *elementContent)
399*35238bceSAndroid Build Coastguard Worker {
400*35238bceSAndroid Build Coastguard Worker     if (!qpXmlWriter_startElement(writer, elementName, 0, DE_NULL) ||
401*35238bceSAndroid Build Coastguard Worker         (elementContent && !qpXmlWriter_writeString(writer, elementContent)) ||
402*35238bceSAndroid Build Coastguard Worker         !qpXmlWriter_endElement(writer, elementName))
403*35238bceSAndroid Build Coastguard Worker         return false;
404*35238bceSAndroid Build Coastguard Worker 
405*35238bceSAndroid Build Coastguard Worker     return true;
406*35238bceSAndroid Build Coastguard Worker }
407