1/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "SyncML_DM_WBXMLWriter.H"
18#include "SyncML_DM_WBXMLArchive.H"
19
20#ifdef LOB_SUPPORT
21#include "dm_tree_default_ESN_class.H" //header file for class defn
22#endif
23
24#include "dm_uri_utils.h"
25const int SyncML_DM_WBXMLWriter::MAX_OPAQUE_STRING_LENGTH = 255;
26
27/*==================================================================================================
28
29Function:    SyncML_DM_WBXMLWriter::writeByte
30
31Description: Write a byte of data to the file handle
32
33==================================================================================================*/
34SYNCML_DM_RET_STATUS_T
35SyncML_DM_WBXMLWriter::writeByte(UINT8 byte) {
36    return this->fileHandle->write(&byte, 1);
37}
38
39/*==================================================================================================
40
41Function:    SyncML_DM_WBXMLWriter::writeString
42
43Description: Writes a string of data as opaque data. The null terminator will
44             not be written, as opaque data has a length stored with it. If the
45             string is NULL, that will be written as an opaque data with length 0.
46
47==================================================================================================*/
48SYNCML_DM_RET_STATUS_T
49SyncML_DM_WBXMLWriter::writeString(CPCHAR string) {
50    UINT32 len = 0;
51
52    if (string != NULL)
53        len = DmStrlen(string);
54    return writeOpaque((UINT8*)string, len);
55}
56
57/*==================================================================================================
58
59Function:    SyncML_DM_WBXMLWriter::writeData
60
61Description: Writes a given amount of raw data (without WBXML formatting or special encodings)
62
63==================================================================================================*/
64SYNCML_DM_RET_STATUS_T
65SyncML_DM_WBXMLWriter::writeData(const UINT8* data, UINT8 len) {
66    return this->fileHandle->write(data, len);
67}
68
69/*==================================================================================================
70
71Function:    SyncML_DM_WBXMLWriter::writeOpaque
72
73Description:
74            Write opaque data of a given length.
75            The data better be less than 128 bytes in length,
76            as this service does not handle encoding the mb_u_int32 format.
77
78            The service returns the success/fail code from the lower level I/O, or
79            may also return SYNCML_DM_IO_FAILURE if the data was too long.
80
81            A length of 0 and/or a NULL data buffer is handled.
82
83==================================================================================================*/
84SYNCML_DM_RET_STATUS_T
85SyncML_DM_WBXMLWriter::writeOpaque(const UINT8* data, UINT32 len) {
86    SYNCML_DM_RET_STATUS_T ret_stat;
87
88    ret_stat = writeByte(SyncML_DM_WBXMLArchive::OPAQUE_CODE);
89
90    if (ret_stat != SYNCML_DM_SUCCESS)
91        return ret_stat;
92
93    if((data != NULL) && (len != 0)) {
94
95        UINT8 result, bits;
96        int continuation=0;
97        for(int shift = 28; shift > 0; shift -= 7) {
98            bits = (len >> shift) & 0x7F;
99            if ((bits!=0) ||(continuation != 0)) {
100                result = 0x80 | bits;
101                ret_stat = writeByte((UINT8)result);
102                if (ret_stat != SYNCML_DM_SUCCESS)
103                    return SYNCML_DM_IO_FAILURE;
104            }
105            if (bits != 0)
106                continuation = 1;
107        }
108        result = len & 0x7F;
109        ret_stat = writeByte((UINT8)result);
110        if (ret_stat != SYNCML_DM_SUCCESS)
111            return SYNCML_DM_IO_FAILURE;
112
113        ret_stat = this->fileHandle->write(data, (UINT16)len);
114
115    } else {
116        /* Since the pointer to the byte is NULL, then there is no opaque data
117         * for this node to be written, so the length field is zero. Zero encoded
118         * in the mb_u_int32 format takes one byte, 0.
119         */
120        ret_stat = writeByte((UINT8)0);
121    }
122
123    return ret_stat;
124}
125
126
127/*==================================================================================================
128
129Function:    SyncML_DM_WBXMLWriter::writeNode
130
131Description: Write a SYNCML_DM_NODE_PROPERTIES_T type node of data to the WBXML file
132    Note! This service does not write the END_TAG for the whole node; the next byte that can occur
133    is a NODE_START_TAG (indicating the start of a new sub-node) or an END_TAG, (indicating the end
134    of the current node, and parhaps the end of the current branch of the tree). The caller must
135    decide what to write next.
136
137==================================================================================================*/
138SYNCML_DM_RET_STATUS_T
139SyncML_DM_WBXMLWriter::writeNode(const DMNode* node) {
140    /* Write the start tag */
141    if(writeByte(SyncML_DM_WBXMLArchive::NODE_START_TAG | SyncML_DM_WBXMLArchive::TAG_CONTENT_MASK) != SYNCML_DM_SUCCESS)
142        return SYNCML_DM_IO_FAILURE;
143
144    /* Write node properties */
145    CPCHAR tmpStr;
146    tmpStr = node->getName();
147
148    if ( DmStrcmp(tmpStr,"") != 0 )  /* If there a NodeName to write... */
149    {
150        if(writeByte(SyncML_DM_WBXMLArchive::NAME_START_TAG | SyncML_DM_WBXMLArchive::TAG_CONTENT_MASK) != SYNCML_DM_SUCCESS ||
151                writeString(tmpStr) != SYNCML_DM_SUCCESS ||
152                writeByte(SyncML_DM_WBXMLArchive::END_TAG) != SYNCML_DM_SUCCESS)
153            return SYNCML_DM_IO_FAILURE;
154    }
155    UINT8 nodeFormat = (const UINT8) node->getFormat();
156
157    if ( node->IsOverlayPIData() && nodeFormat == SYNCML_DM_FORMAT_NODE )
158      nodeFormat = SYNCML_DM_FORMAT_NODE_PDATA;
159
160    if ( nodeFormat != SYNCML_DM_FORMAT_NODE ) {
161      if(writeByte(SyncML_DM_WBXMLArchive::FORMAT_NEW_START_TAG | SyncML_DM_WBXMLArchive::TAG_CONTENT_MASK) != SYNCML_DM_SUCCESS ||
162              writeOpaque((const UINT8*)&nodeFormat, sizeof(nodeFormat)) != SYNCML_DM_SUCCESS ||
163              writeByte(SyncML_DM_WBXMLArchive::END_TAG) != SYNCML_DM_SUCCESS)
164          return SYNCML_DM_IO_FAILURE;
165    }
166#ifdef LOB_SUPPORT
167    if(node->IsESN())
168    {
169	 DMString tempESNName;
170
171  	 // Get ESN pointer
172	 const DMDefaultESN *tempESN = reinterpret_cast<const DMDefaultESN *>(node);
173	// Get original storage file name
174	 tmpStr = tempESN->GetOriginalInternalFileName();
175
176	// Storage file changed ?
177	if(tempESN->IsDirty())
178	{
179		if(tempESN->IsSetComplete())
180		{
181			// Newly created node
182			if(tmpStr == NULL)
183			{	tempESNName.RemoveSufix(tempESN->GetInternalStorageFileName(), SYNCML_DM_DOT);
184				tmpStr = tempESNName.c_str();
185			}
186		}
187		else
188			 return SYNCML_DM_INCOMPLETE_COMMAND;
189	}
190	if(DmStrlen(tmpStr) != 0)   /* If there a file name  to write... */
191	 {
192	        if(writeByte(SyncML_DM_WBXMLArchive::ESN_File_NAME_START_TAG | SyncML_DM_WBXMLArchive::TAG_CONTENT_MASK) != SYNCML_DM_SUCCESS ||
193	                writeString(tmpStr) != SYNCML_DM_SUCCESS ||
194	                writeByte(SyncML_DM_WBXMLArchive::END_TAG) != SYNCML_DM_SUCCESS)
195	            return SYNCML_DM_IO_FAILURE;
196	  }
197    }
198#endif
199    if ( node->IsOverlayPIData() && node->getOverlayPIData() && node->getOverlayPIData()->size() > 0 )
200    {
201      if(writeByte(SyncML_DM_WBXMLArchive::OPI_DATA_START_TAG | SyncML_DM_WBXMLArchive::TAG_CONTENT_MASK) != SYNCML_DM_SUCCESS ||
202              writeOpaque(node->getOverlayPIData()->get_data(), node->getOverlayPIData()->size()) != SYNCML_DM_SUCCESS ||
203              writeByte(SyncML_DM_WBXMLArchive::END_TAG) != SYNCML_DM_SUCCESS)
204          return SYNCML_DM_IO_FAILURE;
205    }
206    UINT16 flag = node->getFlags(); flag &= ~DMNode::enum_NodeNotPersisted;
207        /* Guarantee Big Endian storage of a UINT16 */
208    UINT8 flagNo[2] = { static_cast<UINT8>(flag >> 8),
209                        static_cast<UINT8>(flag & 0xFF) };
210    if ( flag ){
211      if(writeByte(SyncML_DM_WBXMLArchive::FLAGS_START_TAG | SyncML_DM_WBXMLArchive::TAG_CONTENT_MASK) != SYNCML_DM_SUCCESS ||
212              writeOpaque(flagNo, sizeof(flagNo)) != SYNCML_DM_SUCCESS ||
213              writeByte(SyncML_DM_WBXMLArchive::END_TAG) != SYNCML_DM_SUCCESS)
214          return SYNCML_DM_IO_FAILURE;
215    }
216
217    tmpStr = node->getType();
218    if (DmStrcmp(tmpStr,"") != 0)  /* If there are any mimetype to write... */
219    {
220        if(writeByte(SyncML_DM_WBXMLArchive::TYPE_START_TAG | SyncML_DM_WBXMLArchive::TAG_CONTENT_MASK) != SYNCML_DM_SUCCESS ||
221                writeString(tmpStr) != SYNCML_DM_SUCCESS ||
222                writeByte(SyncML_DM_WBXMLArchive::END_TAG) != SYNCML_DM_SUCCESS)
223            return SYNCML_DM_IO_FAILURE;
224    }
225
226    const DMBuffer * psData = node->getData();
227
228    if ( psData && psData->getSize() )  /* If there are any ACLs to write... */
229    {
230        if(writeByte(SyncML_DM_WBXMLArchive::DATA_START_TAG | SyncML_DM_WBXMLArchive::TAG_CONTENT_MASK) != SYNCML_DM_SUCCESS ||
231                writeOpaque(psData->getBuffer(), psData->getSize()) != SYNCML_DM_SUCCESS ||
232                writeByte(SyncML_DM_WBXMLArchive::END_TAG) != SYNCML_DM_SUCCESS)
233            return SYNCML_DM_IO_FAILURE;
234    }
235
236    tmpStr = node->getTitle();
237    if (DmStrcmp(tmpStr,"") != 0) {
238        if(writeByte(SyncML_DM_WBXMLArchive::TITLE_START_TAG | SyncML_DM_WBXMLArchive::TAG_CONTENT_MASK) != SYNCML_DM_SUCCESS ||
239                writeString(tmpStr) != SYNCML_DM_SUCCESS ||
240                writeByte(SyncML_DM_WBXMLArchive::END_TAG) != SYNCML_DM_SUCCESS)
241            return SYNCML_DM_IO_FAILURE;
242    }
243
244#ifndef DM_IGNORE_TSTAMP_AND_VERSION
245    {
246        DMNode * pNode = (DMNode*)node;
247
248        UINT8 timeStamp[ sizeof(XPL_CLK_CLOCK_T) ];
249
250        XPL_CLK_CLOCK_T tStamp = pNode->GetTStamp(NULL);
251
252        for ( UINT32 i = 0; i < sizeof(XPL_CLK_CLOCK_T); i++ )
253          timeStamp[i] = (UINT8)(tStamp >> (i*8));
254
255        if(writeByte(SyncML_DM_WBXMLArchive::TSTAMP_INT_START_TAG | SyncML_DM_WBXMLArchive::TAG_CONTENT_MASK) != SYNCML_DM_SUCCESS ||
256                writeOpaque(timeStamp, sizeof(timeStamp) ) != SYNCML_DM_SUCCESS ||
257                writeByte(SyncML_DM_WBXMLArchive::END_TAG) != SYNCML_DM_SUCCESS)
258            return SYNCML_DM_IO_FAILURE;
259
260        if(writeByte(SyncML_DM_WBXMLArchive::VERSION_START_TAG | SyncML_DM_WBXMLArchive::TAG_CONTENT_MASK) != SYNCML_DM_SUCCESS)
261           return SYNCML_DM_IO_FAILURE;
262        /* Guarantee Big Endian storage of a UINT16 */
263        UINT16 wVerNo = pNode->GetVerNo(NULL);
264        UINT8 verNo[2] = { static_cast<UINT8>(wVerNo >> 8),
265                           static_cast<UINT8>(wVerNo & 0xFF) };
266        if(writeOpaque(verNo, sizeof(verNo)) != SYNCML_DM_SUCCESS ||
267           writeByte(SyncML_DM_WBXMLArchive::END_TAG) != SYNCML_DM_SUCCESS)
268           return SYNCML_DM_IO_FAILURE;
269   }
270
271#endif
272
273    return SYNCML_DM_SUCCESS;
274}
275/*==================================================================================================
276
277Function:    SyncML_DM_WBXMLWriter::operator new
278
279Description: Allocate memory for this object
280
281Memory policy: The caller is responsible to delete (free) the new object (alloc'd memory)
282
283==================================================================================================*/
284void *
285SyncML_DM_WBXMLWriter::operator new(size_t sz) {
286    return (DmAllocMem(sz));
287}
288
289/*==================================================================================================
290
291Function:    SyncML_DM_WBXMLWriter::operator delete
292
293Description: De-allocate memory for this object
294
295==================================================================================================*/
296void
297SyncML_DM_WBXMLWriter::operator delete (void *buf) {
298    DmFreeMem(buf);
299}
300