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 = "<";
64*35238bceSAndroid Build Coastguard Worker break;
65*35238bceSAndroid Build Coastguard Worker case '>':
66*35238bceSAndroid Build Coastguard Worker repl = ">";
67*35238bceSAndroid Build Coastguard Worker break;
68*35238bceSAndroid Build Coastguard Worker case '&':
69*35238bceSAndroid Build Coastguard Worker repl = "&";
70*35238bceSAndroid Build Coastguard Worker break;
71*35238bceSAndroid Build Coastguard Worker case '\'':
72*35238bceSAndroid Build Coastguard Worker repl = "'";
73*35238bceSAndroid Build Coastguard Worker break;
74*35238bceSAndroid Build Coastguard Worker case '"':
75*35238bceSAndroid Build Coastguard Worker repl = """;
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 = "<SOH>";
81*35238bceSAndroid Build Coastguard Worker break;
82*35238bceSAndroid Build Coastguard Worker case 2:
83*35238bceSAndroid Build Coastguard Worker repl = "<STX>";
84*35238bceSAndroid Build Coastguard Worker break;
85*35238bceSAndroid Build Coastguard Worker case 3:
86*35238bceSAndroid Build Coastguard Worker repl = "<ETX>";
87*35238bceSAndroid Build Coastguard Worker break;
88*35238bceSAndroid Build Coastguard Worker case 4:
89*35238bceSAndroid Build Coastguard Worker repl = "<EOT>";
90*35238bceSAndroid Build Coastguard Worker break;
91*35238bceSAndroid Build Coastguard Worker case 5:
92*35238bceSAndroid Build Coastguard Worker repl = "<ENQ>";
93*35238bceSAndroid Build Coastguard Worker break;
94*35238bceSAndroid Build Coastguard Worker case 6:
95*35238bceSAndroid Build Coastguard Worker repl = "<ACK>";
96*35238bceSAndroid Build Coastguard Worker break;
97*35238bceSAndroid Build Coastguard Worker case 7:
98*35238bceSAndroid Build Coastguard Worker repl = "<BEL>";
99*35238bceSAndroid Build Coastguard Worker break;
100*35238bceSAndroid Build Coastguard Worker case 8:
101*35238bceSAndroid Build Coastguard Worker repl = "<BS>";
102*35238bceSAndroid Build Coastguard Worker break;
103*35238bceSAndroid Build Coastguard Worker case 11:
104*35238bceSAndroid Build Coastguard Worker repl = "<VT>";
105*35238bceSAndroid Build Coastguard Worker break;
106*35238bceSAndroid Build Coastguard Worker case 12:
107*35238bceSAndroid Build Coastguard Worker repl = "<FF>";
108*35238bceSAndroid Build Coastguard Worker break;
109*35238bceSAndroid Build Coastguard Worker case 14:
110*35238bceSAndroid Build Coastguard Worker repl = "<SO>";
111*35238bceSAndroid Build Coastguard Worker break;
112*35238bceSAndroid Build Coastguard Worker case 15:
113*35238bceSAndroid Build Coastguard Worker repl = "<SI>";
114*35238bceSAndroid Build Coastguard Worker break;
115*35238bceSAndroid Build Coastguard Worker case 16:
116*35238bceSAndroid Build Coastguard Worker repl = "<DLE>";
117*35238bceSAndroid Build Coastguard Worker break;
118*35238bceSAndroid Build Coastguard Worker case 17:
119*35238bceSAndroid Build Coastguard Worker repl = "<DC1>";
120*35238bceSAndroid Build Coastguard Worker break;
121*35238bceSAndroid Build Coastguard Worker case 18:
122*35238bceSAndroid Build Coastguard Worker repl = "<DC2>";
123*35238bceSAndroid Build Coastguard Worker break;
124*35238bceSAndroid Build Coastguard Worker case 19:
125*35238bceSAndroid Build Coastguard Worker repl = "<DC3>";
126*35238bceSAndroid Build Coastguard Worker break;
127*35238bceSAndroid Build Coastguard Worker case 20:
128*35238bceSAndroid Build Coastguard Worker repl = "<DC4>";
129*35238bceSAndroid Build Coastguard Worker break;
130*35238bceSAndroid Build Coastguard Worker case 21:
131*35238bceSAndroid Build Coastguard Worker repl = "<NAK>";
132*35238bceSAndroid Build Coastguard Worker break;
133*35238bceSAndroid Build Coastguard Worker case 22:
134*35238bceSAndroid Build Coastguard Worker repl = "<SYN>";
135*35238bceSAndroid Build Coastguard Worker break;
136*35238bceSAndroid Build Coastguard Worker case 23:
137*35238bceSAndroid Build Coastguard Worker repl = "<ETB>";
138*35238bceSAndroid Build Coastguard Worker break;
139*35238bceSAndroid Build Coastguard Worker case 24:
140*35238bceSAndroid Build Coastguard Worker repl = "<CAN>";
141*35238bceSAndroid Build Coastguard Worker break;
142*35238bceSAndroid Build Coastguard Worker case 25:
143*35238bceSAndroid Build Coastguard Worker repl = "<EM>";
144*35238bceSAndroid Build Coastguard Worker break;
145*35238bceSAndroid Build Coastguard Worker case 26:
146*35238bceSAndroid Build Coastguard Worker repl = "<SUB>";
147*35238bceSAndroid Build Coastguard Worker break;
148*35238bceSAndroid Build Coastguard Worker case 27:
149*35238bceSAndroid Build Coastguard Worker repl = "<ESC>";
150*35238bceSAndroid Build Coastguard Worker break;
151*35238bceSAndroid Build Coastguard Worker case 28:
152*35238bceSAndroid Build Coastguard Worker repl = "<FS>";
153*35238bceSAndroid Build Coastguard Worker break;
154*35238bceSAndroid Build Coastguard Worker case 29:
155*35238bceSAndroid Build Coastguard Worker repl = "<GS>";
156*35238bceSAndroid Build Coastguard Worker break;
157*35238bceSAndroid Build Coastguard Worker case 30:
158*35238bceSAndroid Build Coastguard Worker repl = "<RS>";
159*35238bceSAndroid Build Coastguard Worker break;
160*35238bceSAndroid Build Coastguard Worker case 31:
161*35238bceSAndroid Build Coastguard Worker repl = "<US>";
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