source: sources/src/dataFormatJsonProcessor.cc @ 1464:3f6711617be1

Revision 1464:3f6711617be1, 14.9 KB checked in by niam, 22 months ago (diff)

{issue #58[resolved]} support for non-c++ exceptions

Line 
1/***************************************************************************
2 *            dataFormatJsonProcessor.cc
3 *
4 *  Mon Oct 20 2007
5 *  Copyright  2007  Dmytro Milinevskyy
6 *  milinevskyy@gmail.com
7 ****************************************************************************/
8
9/*
10 *  This program is free software; you can redistribute it and/or modify
11 *  it under the terms of the GNU Lesser General Public License version 2.1 as published by
12 *  the Free Software Foundation;
13 *
14 *  This program is distributed in the hope that it will be useful,
15 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 *  GNU Library General Public License for more details.
18 *
19 *  You should have received a copy of the GNU Lesser General Public License
20 *  along with this program; if not, write to the Free Software
21 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22 */
23
24/**
25 * vim indentation settings
26 * set tabstop=4
27 * set shiftwidth=4
28 */
29
30#include <libdodo/directives.h>
31
32#include <libdodo/dataFormatJsonProcessor.h>
33#include <libdodo/types.h>
34#include <libdodo/toolsString.h>
35#include <libdodo/toolsFilesystem.h>
36#include <libdodo/dataFormatJsonProcessorEx.h>
37#include <libdodo/dataFormatJsonNode.h>
38#include <libdodo/ioChannel.h>
39
40using namespace dodo::data::format::json;
41
42processor::processor()
43{
44}
45
46//-------------------------------------------------------------------
47
48processor::~processor()
49{
50}
51
52//-------------------------------------------------------------------
53
54void
55processor::make(const node        &root,
56                const io::channel &io)
57{
58    switch (root.valueDataType) {
59        case node::DATA_STRING:
60        {
61            io.writeString("\"");
62            dodo::string stringValue = *root.stringValue;
63            tools::string::replace("\"", "\\\"", stringValue);
64            io.writeString(stringValue);
65            io.writeString("\"");
66
67            break;
68        }
69
70        case node::DATA_OBJECT:
71        {
72            io.writeString("{");
73
74            dodoMap<dodo::string, node, dodoMapStringCompare>::const_iterator
75            i = root.objectValue->begin(),
76            j = root.objectValue->end();
77            if (i != j) {
78                for (--j; i != j; ++i) {
79                    io.writeString("\"");
80                    io.writeString(i->first);
81                    io.writeString("\":");
82
83                    make(i->second, io);
84                    io.writeString(",");
85                }
86                io.writeString("\"");
87                io.writeString(i->first);
88                io.writeString("\":");
89
90                make(i->second, io);
91            }
92
93            io.writeString("}");
94
95            break;
96        }
97
98        case node::DATA_ARRAY:
99        {
100            io.writeString("[");
101
102            dodoArray<node>::const_iterator
103            i = root.arrayValue->begin(),
104            j = root.arrayValue->end();
105            if (i != j) {
106                --j;
107                for (; i != j; ++i) {
108                    make(*i, io);
109                    io.writeString(",");
110                }
111                make(*i, io);
112            }
113
114            io.writeString("]");
115
116            break;
117        }
118
119        case node::DATA_NUMERIC:
120            io.writeString(tools::string::lToString(root.numericValue));
121
122            break;
123
124        case node::DATA_BOOLEAN:
125            io.writeString(root.booleanValue ? "true" : "false");
126
127            break;
128
129        case node::DATA_NULL:
130        default:
131            io.writeString("null");
132    }
133}
134
135//-------------------------------------------------------------------
136
137unsigned long
138processor::processArray(dodoArray<node>  &jnode,
139                        const dodo::string &root,
140                        unsigned long    pos)
141{
142    bool initial = true;
143
144    node subNode;
145
146    unsigned long i(pos), j(root.size());
147    for (; i < j; ++i) {
148        switch (root[i]) {
149            case ' ':
150            case '\r':
151            case '\n':
152            case '\t':
153                break;
154
155            case '[':
156                if (initial)
157                    initial = false;
158                else {
159                    i = processValue(subNode, root, i);
160
161                    jnode.push_back(subNode);
162
163                    subNode.~node();
164                    subNode.valueDataType = node::DATA_NULL;
165                }
166
167                break;
168
169            case ']':
170                return i;
171
172            case ',':
173                break;
174
175            default:
176                i = processValue(subNode, root, i);
177
178                jnode.push_back(subNode);
179
180                subNode.~node();
181                subNode.valueDataType = node::DATA_NULL;
182        }
183    }
184
185    return i;
186}
187
188//-------------------------------------------------------------------
189
190unsigned long
191processor::processValue(node             &node,
192                        const dodo::string &root,
193                        unsigned long    pos)
194{
195    unsigned long i(pos), j(root.size());
196    for (; i < j; ++i) {
197        switch (root[i]) {
198            case ' ':
199            case '\r':
200            case '\n':
201            case '\t':
202                break;
203
204            case '"':
205                node.valueDataType = node::DATA_STRING;
206                node.stringValue = new dodo::string;
207
208                return processString(*node.stringValue, root, i);
209
210            case '{':
211                node.valueDataType = node::DATA_OBJECT;
212                node.objectValue = new dodoMap<dodo::string, json::node, dodoMapStringCompare>;
213
214                return processObject(*node.objectValue, root, i);
215
216            case '[':
217                node.valueDataType = node::DATA_ARRAY;
218                node.arrayValue = new dodoArray<json::node>;
219
220                return processArray(*node.arrayValue, root, i);
221
222            case 't':
223            case 'f':
224                node.valueDataType = node::DATA_BOOLEAN;
225
226                return processBoolean(node.booleanValue, root, i);
227
228            case 'n':
229                node.valueDataType = node::DATA_NULL;
230
231                return processNull(root, i);
232
233            default:
234                node.valueDataType = node::DATA_NUMERIC;
235
236                return processNumeric(node.numericValue, root, i);
237        }
238    }
239
240    return (unsigned long)-1;
241}
242
243//-------------------------------------------------------------------
244
245unsigned long
246processor::processBoolean(bool             &node,
247                          const dodo::string &root,
248                          unsigned long    pos)
249{
250    if ((root.size() - pos) < 4)
251        dodo_throw exception::basic(exception::MODULE_DATAFORMATJSONPROCESSOR, PROCESSOREX_PROCESSBOOLEAN, exception::ERRNO_LIBDODO, PROCESSOREX_MALFORMEDJSONBOOLEAN, DATAFORMATJSONPROCESSOREX_MALFORMEDJSONBOOLEAN_STR, __LINE__, __FILE__);
252
253    if (root[pos] == 't' && root[pos + 1] == 'r' && root[pos + 2] == 'u' && root[pos + 3] == 'e') {
254        node = true;
255
256        return pos + 3;
257    } else {
258        if (root[pos] == 'f' && root[pos + 1] == 'a' && root[pos + 2] == 'l' && root[pos + 3] == 's' && root[pos + 4] == 'e') {
259            node = false;
260
261            return pos + 4;
262        } else
263            dodo_throw exception::basic(exception::MODULE_DATAFORMATJSONPROCESSOR, PROCESSOREX_PROCESSBOOLEAN, exception::ERRNO_LIBDODO, PROCESSOREX_MALFORMEDJSONBOOLEAN, DATAFORMATJSONPROCESSOREX_MALFORMEDJSONBOOLEAN_STR, __LINE__, __FILE__);
264    }
265
266    return pos;
267}
268
269//-------------------------------------------------------------------
270
271unsigned long
272processor::processNull(const dodo::string &root,
273                       unsigned long    pos)
274{
275    if ((root.size() - pos) < 4)
276        dodo_throw exception::basic(exception::MODULE_DATAFORMATJSONPROCESSOR, PROCESSOREX_PROCESSNULL, exception::ERRNO_LIBDODO, PROCESSOREX_MALFORMEDJSONNULL, DATAFORMATJSONPROCESSOREX_MALFORMEDJSONNULL_STR, __LINE__, __FILE__);
277
278    if (root[pos] == 'n' && root[pos + 1] == 'u' && root[pos + 2] == 'l' && root[pos + 3] == 'l')
279        return pos + 3;
280    else
281        dodo_throw exception::basic(exception::MODULE_DATAFORMATJSONPROCESSOR, PROCESSOREX_PROCESSNULL, exception::ERRNO_LIBDODO, PROCESSOREX_MALFORMEDJSONNULL, DATAFORMATJSONPROCESSOREX_MALFORMEDJSONNULL_STR, __LINE__, __FILE__);
282
283    return pos;
284}
285
286//-------------------------------------------------------------------
287
288unsigned long
289processor::processNumeric(long             &node,
290                          const dodo::string &root,
291                          unsigned long    pos)
292{
293    dodo::string numeric;
294
295    unsigned long i(pos), j(root.size());
296    for (; i < j; ++i) {
297        switch (root[i]) {
298            case ' ':
299            case '\r':
300            case '\n':
301            case '\t':
302                break;
303
304            case '1':
305            case '2':
306            case '3':
307            case '4':
308            case '5':
309            case '6':
310            case '7':
311            case '8':
312            case '9':
313            case '0':
314            case '+':
315            case '-':
316            case 'e':
317            case 'E':
318                numeric += root[i];
319
320                break;
321
322            case ',':
323            case ']':
324            case '}':
325                node = tools::string::stringToL(numeric);
326
327                return i - 1;
328
329            default:
330                dodo_throw exception::basic(exception::MODULE_DATAFORMATJSONPROCESSOR, PROCESSOREX_PROCESSNUMERIC, exception::ERRNO_LIBDODO, PROCESSOREX_MALFORMEDJSONNUMERIC, DATAFORMATJSONPROCESSOREX_MALFORMEDJSONNUMERIC_STR, __LINE__, __FILE__);
331        }
332    }
333
334    return i;
335}
336
337//-------------------------------------------------------------------
338
339unsigned long
340processor::processObject(dodoMap<dodo::string, node, dodoMapStringCompare> &jnode,
341                         const dodo::string &root,
342                         unsigned long pos)
343{
344    short state = STATE_OBJECT_INITIAL;
345
346    node subNodeValue;
347    dodo::string subNodeName;
348
349    unsigned long i(pos), j(root.size());
350    for (; i < j; ++i) {
351        switch (root[i]) {
352            case ' ':
353            case '\r':
354            case '\n':
355            case '\t':
356            case ':':
357            case ',':
358                break;
359
360            case '{':
361                if (state == STATE_OBJECT_INITIAL)
362                    state = STATE_OBJECT_OBJECTNAME;
363                else {
364                    if (state == STATE_OBJECT_OBJECTVALUE) {
365                        subNodeValue.valueDataType = node::DATA_OBJECT;
366                        subNodeValue.objectValue = new dodoMap<dodo::string, node, dodoMapStringCompare>;
367
368                        i = processObject(*subNodeValue.objectValue, root, i);
369                        jnode.insert(std::make_pair(subNodeName, subNodeValue));
370
371                        delete subNodeValue.objectValue;
372                        subNodeValue.valueDataType = node::DATA_NULL;
373
374                        state = STATE_OBJECT_OBJECTNAME;
375                    }
376                }
377
378                break;
379
380            case '}':
381                return i;
382
383            case '"':
384                if (state == STATE_OBJECT_OBJECTNAME) {
385                    subNodeName.clear();
386                    i = processString(subNodeName, root, i);
387
388                    state = STATE_OBJECT_OBJECTVALUE;
389                } else {
390                    if (state == STATE_OBJECT_OBJECTVALUE) {
391                        subNodeValue.valueDataType = node::DATA_STRING;
392                        subNodeValue.stringValue = new dodo::string;
393
394                        i = processString(*subNodeValue.stringValue, root, i);
395                        jnode.insert(std::make_pair(subNodeName, subNodeValue));
396
397                        delete subNodeValue.stringValue;
398                        subNodeValue.valueDataType = node::DATA_NULL;
399
400                        state = STATE_OBJECT_OBJECTNAME;
401                    }
402                }
403
404                break;
405
406            default:
407                if (state == STATE_OBJECT_OBJECTVALUE) {
408                    i = processValue(subNodeValue, root, i);
409                    jnode.insert(std::make_pair(subNodeName, subNodeValue));
410
411                    subNodeValue.~node();
412                    subNodeValue.valueDataType = node::DATA_NULL;
413
414                    state = STATE_OBJECT_OBJECTNAME;
415                }
416        }
417    }
418
419    return i;
420}
421
422//-------------------------------------------------------------------
423
424node
425processor::process(const io::channel &io)
426{
427    node node;
428
429    node.valueDataType = node::DATA_OBJECT;
430    node.objectValue = new dodoMap<dodo::string, json::node, dodoMapStringCompare>;
431
432    dodo::string json, jsonPart;
433
434    while (true) {
435        jsonPart = io.readString();
436        if (jsonPart.size() == 0)
437            break;
438
439        json += jsonPart;
440    }
441    jsonPart.clear();
442
443    processObject(*node.objectValue, json, 0);
444
445    return node;
446}
447
448//-------------------------------------------------------------------
449
450void
451processor::fromMap(const dodoStringMap &root,
452                   const io::channel   &io)
453{
454    node nodeDef;
455    node subNodeDef;
456
457    nodeDef.valueDataType = node::DATA_OBJECT;
458    nodeDef.objectValue = new dodoMap<dodo::string, json::node, dodoMapStringCompare>;
459
460    subNodeDef.valueDataType = node::DATA_STRING;
461
462    dodoStringMap::const_iterator i = root.begin(), j = root.end();
463    for (; i != j; ++i) {
464        subNodeDef.stringValue = new dodo::string(i->second);
465
466        nodeDef.objectValue->insert(std::make_pair(i->first, subNodeDef));
467        delete subNodeDef.stringValue;
468    }
469    subNodeDef.valueDataType = node::DATA_NULL;
470
471    make(nodeDef, io);
472}
473
474//-------------------------------------------------------------------
475
476dodo::dodoStringMap
477processor::toMap(const io::channel &io)
478{
479    node JSON = process(io);
480
481    dodoStringMap map;
482
483    dodoMap<dodo::string, node, dodoMapStringCompare>::iterator
484    i = JSON.objectValue->begin(),
485    j = JSON.objectValue->end();
486    for (; i != j; ++i)
487        if (i->second.valueDataType == node::DATA_STRING)
488            map.insert(std::make_pair(i->first, *i->second.stringValue));
489
490    return map;
491}
492
493//-------------------------------------------------------------------
494
495unsigned long
496processor::processString(dodo::string       &jnode,
497                         const dodo::string &root,
498                         unsigned long    pos)
499{
500    bool escape = false;
501    bool initial = true;
502
503    unsigned long i(pos), j(root.size());
504    for (; i < j; ++i) {
505        switch (root[i]) {
506            case '\\':
507                if (!escape) {
508                    escape = true;
509
510                    break;
511                }
512
513            case '"':
514                if (!escape) {
515                    if (initial) {
516                        initial = false;
517
518                        break;
519                    } else {
520                        return i;
521                    }
522                }
523
524            default:
525                if (escape) {
526                    escape = false;
527
528                    jnode += '\\';
529                    jnode += root[i];
530                } else {
531                    jnode += root[i];
532                }
533        }
534    }
535
536    return i;
537}
538
539//-------------------------------------------------------------------
540
Note: See TracBrowser for help on using the repository browser.