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 <android_runtime/AndroidRuntime.h>
18#include "utils/Log.h"
19#include "DMServiceMain.h"
20#include "dmt.hpp"
21#include <stdarg.h>
22#include <dmMemory.h>
23
24extern "C" {
25#include "xltdec.h"
26}
27
28static const int RESULT_BUF_SIZE = 8192; /*2048*/
29
30// FIXME: get rid of these static variables!
31static PDmtTree ptrTree = NULL;
32static DMString s_strRootPath;
33static DmtPrincipal principal("localhost");
34static bool bShowTimestamp = false;
35
36static PDmtTree GetTree();
37static SYNCML_DM_RET_STATUS_T PrintNode(PDmtNode ptrNode);
38static void DumpSubTree(PDmtNode ptrNode);
39
40static char resultBuf[RESULT_BUF_SIZE];
41static void strcatEx(const char * format, ...)
42{
43    if (!format) {
44        return;
45    }
46
47    int len = strlen(resultBuf);
48    if (len < RESULT_BUF_SIZE - 1) {
49        va_list args;
50        va_start(args, format);
51        int ret = vsnprintf(&resultBuf[len], RESULT_BUF_SIZE - len - 1, format, args);
52        if (ret == -1) {
53            resultBuf[RESULT_BUF_SIZE - 1] = 0x0;
54        }
55        va_end(args);
56    }
57}
58
59static PDmtNode GetNode(const DMString& strNodeName)
60{
61    PDmtNode ptrNode;
62    GetTree();
63
64    if (ptrTree) {
65        if (ptrTree->GetNode(strNodeName, ptrNode) != SYNCML_DM_SUCCESS) {
66            strcatEx("can't get node %s", strNodeName.c_str());
67        }
68    }
69
70    return ptrNode;
71}
72
73JNIEXPORT jstring JNICALL setStringNode(JNIEnv* jenv, jclass, jstring nodePath, jstring value)
74{
75    resultBuf[0] = 0x0;
76
77    const char* szNodePath = jenv->GetStringUTFChars(nodePath, NULL);
78    const char* szValue = jenv->GetStringUTFChars(value, NULL);
79
80    DMString strNodePath(szNodePath);
81    DMString strValue(szValue);
82
83    jenv->ReleaseStringUTFChars(nodePath, szNodePath);
84    jenv->ReleaseStringUTFChars(value, szValue);
85
86    PDmtNode ptrNode = GetNode(strNodePath);
87    if (!ptrNode) {
88        goto end;
89    }
90
91    if (ptrNode->SetStringValue(strValue) == SYNCML_DM_SUCCESS) {
92        strcatEx("set value of node %s to %s successfully\n", strNodePath.c_str(), strValue.c_str());
93        PrintNode(ptrNode);
94    } else {
95        strcatEx("can't set value of node %s to %s", strNodePath.c_str(), strValue.c_str());
96    }
97
98end:
99    jstring ret = jenv->NewStringUTF(resultBuf);
100    return ret;
101}
102
103JNIEXPORT jstring JNICALL getNodeInfo(JNIEnv* jenv, jclass, jstring jszNode)
104{
105    resultBuf[0] = 0x0;
106
107    const char* szNode = jenv->GetStringUTFChars(jszNode, NULL);
108    DMString strNode(szNode);
109    jenv->ReleaseStringUTFChars(jszNode, szNode);
110
111    PDmtNode ptrNode = GetNode(strNode);
112    if (ptrNode) {
113        PrintNode(ptrNode);
114    }
115
116    jstring ret = jenv->NewStringUTF(resultBuf);
117    return ret;
118}
119
120JNIEXPORT jint JNICALL getNodeType(JNIEnv* jenv, jclass, jstring jszNode)
121{
122    const char* szNode = jenv->GetStringUTFChars(jszNode, NULL);
123    DMString strNode(szNode);
124    jenv->ReleaseStringUTFChars(jszNode, szNode);
125
126    PDmtNode ptrNode = GetNode(strNode);
127    if (ptrNode && !ptrNode->IsExternalStorageNode())
128    {
129        DmtData oData;
130        LOGD("Enter get value...\n");
131        SYNCML_DM_RET_STATUS_T ret = ptrNode->GetValue(oData);
132        if (ret != SYNCML_DM_SUCCESS) {
133            LOGD("Value is null");
134            return 0;   // return NULL type on error
135        }
136        return oData.GetType();
137    }
138
139    return 0;   // return NULL type on error
140}
141
142JNIEXPORT jstring JNICALL getNodeValue(JNIEnv* jenv, jclass, jstring jszNode)
143{
144    const char* szNode = jenv->GetStringUTFChars(jszNode, NULL);
145    DMString strNode(szNode);
146    jenv->ReleaseStringUTFChars(jszNode, szNode);
147
148    PDmtNode ptrNode = GetNode(strNode);
149    if (ptrNode && !ptrNode->IsExternalStorageNode())
150    {
151        LOGD("Enter get value...\n");
152        DmtData oData;
153        DMString value;
154
155        if (!ptrNode->IsLeaf()) {
156            SYNCML_DM_RET_STATUS_T ret = ptrNode->GetValue(oData);
157            if (ret != SYNCML_DM_SUCCESS) {
158                LOGE("can't get child nodes");
159                return NULL;    // return NULL reference on error
160            }
161            DMStringVector aChildren;
162            ret = oData.GetNodeValue(aChildren);
163            if (ret != SYNCML_DM_SUCCESS) {
164                LOGE("oData.getNodeValue() failed");
165                return NULL;    // return NULL reference on error
166            }
167            UINT32 childLength = aChildren.size();
168            for (UINT32 i = 0; i < childLength; ++i) {
169                if (i != 0) {
170                    value += '|';
171                }
172                value += aChildren[i];
173            }
174        }
175        else
176        {
177            SYNCML_DM_RET_STATUS_T ret = ptrNode->GetValue(oData);
178            if (ret != SYNCML_DM_SUCCESS) {
179                LOGE("Value is null");
180                return NULL;   // return NULL reference on error
181            }
182            if (oData.GetString(value) != SYNCML_DM_SUCCESS) {
183                LOGE("oData.GetString() failed");
184                return NULL;   // return NULL reference on error
185            }
186        }
187
188        return jenv->NewStringUTF(value.c_str());
189    }
190
191    return NULL;    // return NULL reference on error
192}
193
194JNIEXPORT jstring JNICALL executePlugin(JNIEnv* jenv, jclass, jstring jszNode, jstring jszData)
195{
196    resultBuf[0] = 0x0;
197
198    const char* szNode = jenv->GetStringUTFChars(jszNode, NULL);
199    DMString strNode(szNode);
200    jenv->ReleaseStringUTFChars(jszNode, szNode);
201
202    const char* szData = jenv->GetStringUTFChars(jszData, NULL);
203    DMString strData(szData);
204    jenv->ReleaseStringUTFChars(jszData, szData);
205
206    PDmtNode ptrNode = GetNode(strNode);
207    if (ptrNode) {
208        DMString strResult;
209        if (ptrNode->Execute(strData, strResult) == SYNCML_DM_SUCCESS) {
210            strcatEx("execute node %s successfully, result=%s\n", strNode.c_str(), strResult.c_str());
211        } else {
212            strcatEx("can't execute node %s", strNode.c_str());
213        }
214    }
215
216    jstring ret = jenv->NewStringUTF(resultBuf);
217    return ret;
218}
219
220JNIEXPORT jstring JNICALL dumpTree(JNIEnv *jenv, jclass, jstring jszNode)
221{
222    resultBuf[0] = 0x0;
223
224    const char* szNode = jenv->GetStringUTFChars(jszNode, NULL);
225    DMString strNode(szNode);
226    jenv->ReleaseStringUTFChars(jszNode, szNode);
227
228    PDmtNode ptrNode = GetNode(strNode);
229    if (ptrNode) {
230        DumpSubTree(ptrNode);
231    }
232
233    jstring ret = jenv->NewStringUTF(resultBuf);
234    return ret;
235}
236
237JNIEXPORT jint JNICALL createInterior(JNIEnv *jenv, jclass, jstring jszNode)
238{
239    GetTree();
240    if (!ptrTree) {
241        return static_cast<jint>(SYNCML_DM_FAIL);
242    }
243
244    const char* szNode = jenv->GetStringUTFChars(jszNode, NULL);
245    DMString strNode(szNode);
246    jenv->ReleaseStringUTFChars(jszNode, szNode);
247
248    PDmtNode ptrNode;
249    SYNCML_DM_RET_STATUS_T ret = ptrTree->CreateInteriorNode(strNode, ptrNode);
250    if (ret == SYNCML_DM_SUCCESS) {
251        LOGI("node %s created successfully\n", strNode.c_str());
252    } else {
253        LOGE("can't create node %s", strNode.c_str());
254    }
255    return static_cast<jint>(ret);
256}
257
258JNIEXPORT jint JNICALL createLeaf(JNIEnv *jenv, jclass, jstring jszNode, jstring jszData)
259{
260    if (jszNode == NULL) {
261        return static_cast<jint>(SYNCML_DM_FAIL);
262    }
263
264    GetTree();
265    if (!ptrTree) {
266        return static_cast<jint>(SYNCML_DM_FAIL);
267    }
268
269    const char* szNode = jenv->GetStringUTFChars(jszNode, NULL);
270    const char* szData = NULL;
271
272    if (jszData != NULL) {
273        szData = jenv->GetStringUTFChars(jszData, NULL);
274    }
275
276    PDmtNode ptrNode;
277    SYNCML_DM_RET_STATUS_T ret = ptrTree->CreateLeafNode(szNode, ptrNode, DmtData(szData));
278    if (ret == SYNCML_DM_SUCCESS) {
279        LOGI("node %s (%s) created successfully\n", szNode, szData);
280    } else {
281        LOGE("can't create node %s", szNode);
282    }
283
284    jenv->ReleaseStringUTFChars(jszNode, szNode);
285    jenv->ReleaseStringUTFChars(jszData, szData);
286
287    return static_cast<jint>(ret);
288}
289
290
291JNIEXPORT jint JNICALL createLeafByte(JNIEnv *jenv, jclass clz, jstring jszNode,
292        jbyteArray bDataArray)
293{
294    const char* szNode = jenv->GetStringUTFChars(jszNode, NULL);
295    jbyte* jData = (jbyte*)jenv->GetByteArrayElements(bDataArray, NULL);
296    jsize arraySize = jenv->GetArrayLength(bDataArray);
297
298    char* pData = (char*)DmAllocMem(arraySize+1);
299    memcpy(pData, jData, arraySize);
300    pData[arraySize] = '\0';
301
302    PDmtNode ptrNode;
303    GetTree();
304
305    jenv->ReleaseByteArrayElements(bDataArray, jData, 0);
306
307    if ( ptrTree == NULL ) {
308        DmFreeMem(pData);
309        return SYNCML_DM_FAIL;
310    }
311
312    LOGI("NodePath=%s,Byte Data=0x%X,0x%X,0x%X,0x%X,0x%X,0x%X,0x%X\n", szNode, pData[0], pData[1],
313            pData[2], pData[3], pData[4], pData[5], pData[6]);
314
315    DMString strNode(szNode);
316
317    //PDmtNode ptrNode;
318    SYNCML_DM_RET_STATUS_T ret = ptrTree->CreateLeafNode(szNode, ptrNode, DmtData( pData ));
319    if (ret == SYNCML_DM_SUCCESS) {
320        LOGI("node %s created successfully\n", strNode.c_str());
321    } else {
322        LOGE("can't create node %s", strNode.c_str());
323    }
324    return static_cast<jint>(ret);
325}
326
327JNIEXPORT jint JNICALL deleteNode(JNIEnv *jenv, jclass, jstring jszNode)
328{
329    GetTree();
330    if (!ptrTree) {
331        return static_cast<jint>(SYNCML_DM_FAIL);
332    }
333
334    const char* szNode = jenv->GetStringUTFChars(jszNode, NULL);
335    DMString strNode(szNode);
336    jenv->ReleaseStringUTFChars(jszNode, szNode);
337
338    SYNCML_DM_RET_STATUS_T ret = ptrTree->DeleteNode(strNode);
339    if (ret == SYNCML_DM_SUCCESS) {
340        LOGI("node %s deleted successfully\n", strNode.c_str());
341    } else {
342        LOGE("can't delete node %s", strNode.c_str());
343    }
344    return static_cast<jint>(ret);
345}
346
347static PDmtTree GetTree()
348{
349    if (ptrTree) return ptrTree;
350
351    if (DmtTreeFactory::GetSubtree(principal, s_strRootPath, ptrTree) != SYNCML_DM_SUCCESS) {
352        strcatEx("Can't get tree '%s'.", s_strRootPath.c_str());
353    }
354
355    return ptrTree;
356}
357
358static void DumpSubTree(PDmtNode ptrNode)
359{
360    SYNCML_DM_RET_STATUS_T ret = PrintNode(ptrNode);
361    strcatEx("\n");
362    if (ret != SYNCML_DM_SUCCESS) return;
363
364    if (!ptrNode->IsLeaf()) {
365        DMVector<PDmtNode> aChildren;
366        ret = ptrNode->GetChildNodes(aChildren);
367        if (ret != SYNCML_DM_SUCCESS) {
368            DMString path;
369            ptrNode->GetPath(path);
370            strcatEx("can't get child nodes of %s", path.c_str());
371            return;
372        }
373        UINT32 childLength = aChildren.size();
374        for (UINT32 i = 0; i < childLength; ++i) {
375            DumpSubTree(aChildren[i]);
376        }
377    }
378}
379
380static SYNCML_DM_RET_STATUS_T PrintNode(PDmtNode ptrNode)
381{
382    LOGD("Enter PrintNode\n");
383    DmtAttributes oAttr;
384    DMString path;
385
386    SYNCML_DM_RET_STATUS_T ret = ptrNode->GetPath(path);
387    if (ret != SYNCML_DM_SUCCESS)
388    {
389        strcatEx("can't get attributes of node %d", ret);
390    }
391
392    LOGD("Get attributes\n");
393    if ((ret = ptrNode->GetAttributes(oAttr)) != ptrNode->GetPath(path)) {
394        strcatEx("can't get attributes of node %s", path.c_str());
395        return ret;
396    }
397
398    LOGD("Check storage mode...\n");
399    DmtData oData;
400    if (!ptrNode->IsExternalStorageNode())
401    {
402        LOGD("Enter get value...\n");
403        SYNCML_DM_RET_STATUS_T ret1 = ptrNode->GetValue(oData);
404        if (ret1 != SYNCML_DM_SUCCESS) {
405            LOGD("Value is null");
406            strcatEx("can't get value of node %s", path.c_str());
407            return ret1;
408        }
409    }
410
411    LOGD("Compose string begin...\n");
412    strcatEx("path=%s\n", (const char*)path.c_str());
413    strcatEx("isLeaf=%s\n", (ptrNode->IsLeaf()?"true":"false") );
414    strcatEx("name=%s\n", (const char*)oAttr.GetName().c_str() );
415    strcatEx("format=%s\n", (const char*)oAttr.GetFormat().c_str() );
416    strcatEx("type=%s\n", (const char*)oAttr.GetType().c_str() );
417    strcatEx("title=%s\n", (const char*)oAttr.GetTitle().c_str() );
418    strcatEx("acl=%s\n", (const char*)oAttr.GetAcl().toString().c_str() );
419    strcatEx("size=%d\n", oAttr.GetSize());
420    if (bShowTimestamp) {
421        time_t timestamp = (time_t)(oAttr.GetTimestamp()/1000L);
422        if (timestamp == 0) {
423            strcatEx("timestamp=(Unknown)\n");
424        } else {
425            char timestampbuf[27];
426            ctime_r(&timestamp, timestampbuf);
427            strcatEx("timestamp=%s", timestampbuf);
428        }
429    }
430
431    strcatEx("version=%d\n", oAttr.GetVersion() );
432    if ( !ptrNode->IsLeaf() ) {
433        DMStringVector aChildren;
434        oData.GetNodeValue(aChildren);
435        strcatEx("children:");
436        if ( aChildren.size() == 0 ) {
437            strcatEx("null");
438        }
439        UINT32 childLength = aChildren.size();
440        for (UINT32 i = 0; i < childLength; ++i) {
441            const DMString& child = aChildren[i];
442            strcatEx("%s/", child.c_str());
443        }
444        strcatEx("\n");
445    } else {
446        if (ptrNode->IsExternalStorageNode())
447        {
448            strcatEx("value=\n");
449            strcatEx("It is an ESN node, not supported now");
450            //displayESN(ptrNode);
451        }
452        else {
453            if (oAttr.GetFormat() == "bin") {
454                strcatEx("Binary value: [");
455                const DMVector<UINT8>& val = oData.GetBinaryValue();
456                UINT32 valLength = val.size();
457                for (UINT32 i = 0; i < valLength; ++i) {
458                    UINT8 byte = val[i];
459                    strcatEx("%02x ", byte);
460                }
461                strcatEx("]\n");
462            }
463            else
464            {
465                DMString s;
466                oData.GetString(s);
467                strcatEx("value=%s\n", s.c_str());
468            }
469        }
470    }
471    return SYNCML_DM_SUCCESS;
472}
473
474short wbxml2xml(unsigned char *bufIn, int bufInLen, unsigned char *bufOut, int * bufOutLen)
475{
476    short ret = 0;
477#ifdef __SML_WBXML__
478    ret = wbxml2xmlInternal(bufIn, bufInLen, bufOut,bufOutLen);
479#endif
480    return ret;
481}
482
483JNIEXPORT jbyteArray JNICALL ConvertWbxml2Xml(JNIEnv* env, jclass, jbyteArray bArray)
484{
485    unsigned char* xmlBuf = NULL;
486    int xmlLen = 0;
487
488    jbyte* wbxmlBuf = env->GetByteArrayElements(bArray, NULL);
489    jsize  wbxmlLen = env->GetArrayLength(bArray);
490    LOGD("ConvertWbxml2Xml: wbxml length = %d\n", wbxmlLen);
491
492    if (wbxmlBuf == NULL || wbxmlLen <= 0)
493    {
494        LOGD("ConvertWbxml2Xml: nothing to convert\n");
495        return NULL;
496    }
497
498    xmlLen = wbxmlLen * 6;
499    xmlBuf = new unsigned char[xmlLen];
500    if (xmlBuf == NULL)
501    {
502        LOGE("ConvertWbxml2Xml: failed to allocate memory\n");
503        return NULL;
504    }
505    LOGD("ConvertWbxml2Xml: allocated xml length = %d\n", xmlLen);
506
507#ifdef __SML_WBXML__
508    short ret = wbxml2xmlInternal((unsigned char*)wbxmlBuf, wbxmlLen, xmlBuf, &xmlLen);
509#else
510    short ret = -1;
511#endif
512
513    if (ret != 0) {
514        LOGE("ConvertWbxml2Xml: wbxml2xml failed: %d\n", ret);
515        delete [] xmlBuf;
516        return NULL;
517    }
518
519    jbyteArray jb = env->NewByteArray(xmlLen);
520    env->SetByteArrayRegion(jb, 0, xmlLen, (jbyte*)xmlBuf);
521    LOGD("ConvertWbxml2Xml: result xml length = %d\n", xmlLen);
522    delete [] xmlBuf;
523    return jb;
524}
525
526static JNINativeMethod gMethods[] = {
527    {"setStringNode",
528        "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;",
529        (void*)setStringNode},
530    {"getNodeInfo",
531        "(Ljava/lang/String;)Ljava/lang/String;",
532        (void*)getNodeInfo},
533    {"executePlugin",
534        "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;",
535        (void*)executePlugin},
536    {"dumpTree",
537        "(Ljava/lang/String;)Ljava/lang/String;",
538        (void*)dumpTree},
539    {"createInterior",
540        "(Ljava/lang/String;)I",
541        (void*)createInterior},
542    {"createLeaf",
543        "(Ljava/lang/String;Ljava/lang/String;)I",
544        (void*)createLeaf},
545    {"createLeaf",
546        "(Ljava/lang/String;[B)I",
547        (void*)createLeafByte},
548    {"deleteNode",
549        "(Ljava/lang/String;)I",
550        (void*)deleteNode},
551    {"nativeWbxmlToXml",
552        "([B)[B",
553        (void*)ConvertWbxml2Xml},
554    {"getNodeType",
555        "(Ljava/lang/String;)I",
556        (void*)getNodeType},
557    {"getNodeValue",
558        "(Ljava/lang/String;)Ljava/lang/String;",
559        (void*)getNodeValue},
560};
561
562int registerDMTreeNatives(JNIEnv *env)
563{
564    jclass clazz = env->FindClass(javaDMEnginePackage);
565    if (clazz == NULL)
566        return JNI_FALSE;
567
568    if (env->RegisterNatives(clazz, gMethods, sizeof(gMethods)/sizeof(gMethods[0])) < 0)
569    {
570        LOGE("registerDMTreeNatives return ERROR");
571        return JNI_FALSE;
572    }
573
574    return JNI_TRUE;
575}
576