Merge lp:~qqworini/ubuntu-rssreader-app/fix-crash-rewrite-opml into lp:ubuntu-rssreader-app

Proposed by Joey Chan
Status: Merged
Approved by: Joey Chan
Approved revision: 428
Merged at revision: 453
Proposed branch: lp:~qqworini/ubuntu-rssreader-app/fix-crash-rewrite-opml
Merge into: lp:ubuntu-rssreader-app
Diff against target: 9146 lines (+5314/-1200)
42 files modified
.bzrignore (+1/-0)
shorts/po/com.ubuntu.shorts.pot (+28/-28)
shorts/po/zh_CN.po (+0/-458)
shorts/qml/components/ArticleViewItem.qml (+6/-1)
shorts/qml/content/ContentPickerDialog.qml (+4/-0)
shorts/qml/content/ImportFeeds.qml (+10/-2)
shorts/qml/content/OpmlParser.qml (+42/-19)
shorts/qml/nongoogle/AppendNGFeedPage.qml (+14/-9)
shorts/qml/nongoogle/XmlNetwork.qml (+57/-42)
shorts/qml/shorts-app.qml (+2/-0)
shorts/qml/utils/databasemodule_v2.js (+7/-5)
shorts/utilities.cpp (+89/-15)
shorts/utilities.h (+20/-1)
shorts/xml2json/rapidjson/allocators.h (+3/-1)
shorts/xml2json/rapidjson/document.h (+607/-160)
shorts/xml2json/rapidjson/encodedstream.h (+30/-1)
shorts/xml2json/rapidjson/encodings.h (+77/-0)
shorts/xml2json/rapidjson/filereadstream.h (+1/-1)
shorts/xml2json/rapidjson/filewritestream.h (+1/-1)
shorts/xml2json/rapidjson/fwd.h (+151/-0)
shorts/xml2json/rapidjson/internal/diyfp.h (+1/-1)
shorts/xml2json/rapidjson/internal/dtoa.h (+33/-6)
shorts/xml2json/rapidjson/internal/ieee754.h (+1/-0)
shorts/xml2json/rapidjson/internal/regex.h (+705/-0)
shorts/xml2json/rapidjson/internal/stack.h (+39/-5)
shorts/xml2json/rapidjson/internal/strfunc.h (+17/-1)
shorts/xml2json/rapidjson/internal/strtod.h (+0/-1)
shorts/xml2json/rapidjson/internal/swap.h (+9/-0)
shorts/xml2json/rapidjson/istreamwrapper.h (+110/-0)
shorts/xml2json/rapidjson/memorybuffer.h (+1/-1)
shorts/xml2json/rapidjson/memorystream.h (+3/-3)
shorts/xml2json/rapidjson/ostreamwrapper.h (+76/-0)
shorts/xml2json/rapidjson/pointer.h (+55/-27)
shorts/xml2json/rapidjson/prettywriter.h (+52/-10)
shorts/xml2json/rapidjson/rapidjson.h (+76/-150)
shorts/xml2json/rapidjson/reader.h (+539/-200)
shorts/xml2json/rapidjson/schema.h (+2017/-0)
shorts/xml2json/rapidjson/stream.h (+179/-0)
shorts/xml2json/rapidjson/stringbuffer.h (+25/-1)
shorts/xml2json/rapidjson/writer.h (+222/-48)
shorts/xml2json/rapidxml/rapidxml.hpp (+1/-1)
shorts/xml2json/xml2json.hpp (+3/-1)
To merge this branch: bzr merge lp:~qqworini/ubuntu-rssreader-app/fix-crash-rewrite-opml
Reviewer Review Type Date Requested Status
Jenkins Bot continuous-integration Approve
Ubuntu Shorts Developers Pending
Review via email: mp+297077@code.launchpad.net

Commit message

fix crash bug, rewrite opml parser, update xml2json with latest upstream. fix bug 1543995.

And a new help page.

Description of the change

fix crash bug, rewrite opml parser, update xml2json with latest upstream. fix bug 1543995.

And a new help page.

To post a comment you must log in.
Revision history for this message
Jenkins Bot (ubuntu-core-apps-jenkins-bot) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Jenkins Bot (ubuntu-core-apps-jenkins-bot) wrote :

FAILED: Autolanding.
More details in the following jenkins job:
https://core-apps-jenkins.ubuntu.com/job/shorts-app-autolanding/951/
Executed test runs:
    None: https://core-apps-jenkins.ubuntu.com/job/generic-land-mp/5757/console

review: Needs Fixing (continuous-integration)
425. By Joey Chan

fix crash bug, rewrite opml parser, update xml2json with latest upstream. fix bug 1543995. fix Po file conflict. version 2

Revision history for this message
Jenkins Bot (ubuntu-core-apps-jenkins-bot) wrote :
review: Needs Fixing (continuous-integration)
426. By Joey Chan

fix crash bug, rewrite opml parser, update xml2json with latest upstream. fix bug 1543995. fix Po file conflict. version 2

427. By Joey Chan

fix crash bug, rewrite opml parser, update xml2json with latest upstream. fix bug 1543995. fix Po file conflict. version 3

Revision history for this message
Jenkins Bot (ubuntu-core-apps-jenkins-bot) wrote :
review: Approve (continuous-integration)
428. By Joey Chan

fix crash bug, rewrite opml parser, update xml2json with latest upstream. fix bug 1543995. Update zh_CN Po file conflict. version 4

Revision history for this message
Jenkins Bot (ubuntu-core-apps-jenkins-bot) wrote :
review: Approve (continuous-integration)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file '.bzrignore'
2--- .bzrignore 2015-07-17 14:42:42 +0000
3+++ .bzrignore 2016-06-15 16:13:25 +0000
4@@ -1,1 +1,2 @@
5 RE:(?i).*\.user
6+*.afc62ac
7
8=== modified file 'shorts/po/com.ubuntu.shorts.pot'
9--- shorts/po/com.ubuntu.shorts.pot 2016-03-23 01:45:49 +0000
10+++ shorts/po/com.ubuntu.shorts.pot 2016-06-15 16:13:25 +0000
11@@ -8,7 +8,7 @@
12 msgstr ""
13 "Project-Id-Version: \n"
14 "Report-Msgid-Bugs-To: \n"
15-"POT-Creation-Date: 2016-03-11 20:54+0800\n"
16+"POT-Creation-Date: 2016-06-10 14:54+0000\n"
17 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
18 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
19 "Language-Team: LANGUAGE <LL@li.org>\n"
20@@ -18,7 +18,7 @@
21 "Content-Transfer-Encoding: 8bit\n"
22 "Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n"
23
24-#: ../qml/components/ArticleViewItem.qml:120
25+#: ../qml/components/ArticleViewItem.qml:125
26 msgid "Select article"
27 msgstr ""
28
29@@ -50,51 +50,51 @@
30 msgid "Confirm"
31 msgstr ""
32
33-#: ../qml/content/ImportFeeds.qml:305
34+#: ../qml/content/ImportFeeds.qml:313
35 msgid "Please select an opml file"
36 msgstr ""
37
38-#: ../qml/content/ImportFeeds.qml:310
39+#: ../qml/content/ImportFeeds.qml:318
40 msgid "Open"
41 msgstr ""
42
43-#: ../qml/content/ImportFeeds.qml:293
44+#: ../qml/content/ImportFeeds.qml:301
45 msgid ""
46 "Attention please, before importing opml file, Shorts only support one opml "
47 "structure. <br><br>"
48 msgstr ""
49
50 #: ../qml/nongoogle/AppendNGFeedPage.qml:30 ../qml/pages/AppendFeedPage.qml:31
51-#: ../qml/shorts-app.qml:265 ../qml/shorts-app.qml:403
52-#: ../qml/shorts-app.qml:411
53+#: ../qml/shorts-app.qml:267 ../qml/shorts-app.qml:405
54+#: ../qml/shorts-app.qml:413
55 msgid "Add feeds"
56 msgstr ""
57
58-#: ../qml/nongoogle/AppendNGFeedPage.qml:94
59+#: ../qml/nongoogle/AppendNGFeedPage.qml:99
60 #: ../qml/pages/AppendFeedPage.qml:137
61 msgid "Type a keyword or URL"
62 msgstr ""
63
64-#: ../qml/nongoogle/AppendNGFeedPage.qml:149
65+#: ../qml/nongoogle/AppendNGFeedPage.qml:154
66 msgid "Feed Title:"
67 msgstr ""
68
69-#: ../qml/nongoogle/AppendNGFeedPage.qml:157
70-#: ../qml/nongoogle/AppendNGFeedPage.qml:172
71+#: ../qml/nongoogle/AppendNGFeedPage.qml:162
72+#: ../qml/nongoogle/AppendNGFeedPage.qml:177
73 msgid "No data"
74 msgstr ""
75
76-#: ../qml/nongoogle/AppendNGFeedPage.qml:164
77+#: ../qml/nongoogle/AppendNGFeedPage.qml:169
78 msgid "Feed Description:"
79 msgstr ""
80
81-#: ../qml/nongoogle/AppendNGFeedPage.qml:197
82+#: ../qml/nongoogle/AppendNGFeedPage.qml:202
83 #: ../qml/pages/AppendFeedPage.qml:243 ../qml/pages/CreateTopicPage.qml:38
84-#: ../qml/pages/TopicManagement.qml:239 ../qml/shorts-app.qml:494
85+#: ../qml/pages/TopicManagement.qml:239 ../qml/shorts-app.qml:496
86 msgid "Cancel"
87 msgstr ""
88
89-#: ../qml/nongoogle/AppendNGFeedPage.qml:230
90+#: ../qml/nongoogle/AppendNGFeedPage.qml:235
91 #: ../qml/pages/AppendFeedPage.qml:276
92 msgid "Next"
93 msgstr ""
94@@ -320,7 +320,7 @@
95 msgid "Click here to report a bug"
96 msgstr ""
97
98-#: ../qml/pages/PageSettings.qml:9 ../qml/shorts-app.qml:249
99+#: ../qml/pages/PageSettings.qml:9 ../qml/shorts-app.qml:251
100 msgid "Settings"
101 msgstr ""
102
103@@ -352,7 +352,7 @@
104 msgid "Import OPML"
105 msgstr ""
106
107-#: ../qml/pages/TopicManagement.qml:13 ../qml/shorts-app.qml:229
108+#: ../qml/pages/TopicManagement.qml:13 ../qml/shorts-app.qml:231
109 msgid "Edit topics"
110 msgstr ""
111
112@@ -360,47 +360,47 @@
113 msgid "Add Feed"
114 msgstr ""
115
116-#: ../qml/shorts-app.qml:196
117+#: ../qml/shorts-app.qml:198
118 msgid "Refresh"
119 msgstr ""
120
121-#: ../qml/shorts-app.qml:203
122+#: ../qml/shorts-app.qml:205
123 msgid "Grid View"
124 msgstr ""
125
126-#: ../qml/shorts-app.qml:203
127+#: ../qml/shorts-app.qml:205
128 msgid "List view"
129 msgstr ""
130
131-#: ../qml/shorts-app.qml:239
132+#: ../qml/shorts-app.qml:241
133 msgid "Disable night mode"
134 msgstr ""
135
136-#: ../qml/shorts-app.qml:239
137+#: ../qml/shorts-app.qml:241
138 msgid "Enable night mode"
139 msgstr ""
140
141-#: ../qml/shorts-app.qml:334
142+#: ../qml/shorts-app.qml:336
143 msgid "Saved"
144 msgstr ""
145
146-#: ../qml/shorts-app.qml:342 shorts.desktop.in.in.h:1
147+#: ../qml/shorts-app.qml:344 shorts.desktop.in.in.h:1
148 msgid "Shorts"
149 msgstr ""
150
151-#: ../qml/shorts-app.qml:486
152+#: ../qml/shorts-app.qml:488
153 msgid "Checking for new articles"
154 msgstr ""
155
156-#: ../qml/shorts-app.qml:510
157+#: ../qml/shorts-app.qml:512
158 msgid "Perhaps some of the channels have not been updated."
159 msgstr ""
160
161-#: ../qml/shorts-app.qml:511
162+#: ../qml/shorts-app.qml:513
163 msgid "Errors occurred during the update"
164 msgstr ""
165
166-#: ../qml/shorts-app.qml:525
167+#: ../qml/shorts-app.qml:527
168 msgid "Ok"
169 msgstr ""
170
171
172=== added file 'shorts/po/zh_CN.po'
173--- shorts/po/zh_CN.po 1970-01-01 00:00:00 +0000
174+++ shorts/po/zh_CN.po 2016-06-15 16:13:25 +0000
175@@ -0,0 +1,458 @@
176+# Chinese (Simplified) translation for ubuntu-rssreader-app
177+# Copyright (c) 2013 Rosetta Contributors and Canonical Ltd 2013
178+# This file is distributed under the same license as the ubuntu-rssreader-app package.
179+# FIRST AUTHOR <EMAIL@ADDRESS>, 2013.
180+#
181+msgid ""
182+msgstr ""
183+"Project-Id-Version: ubuntu-rssreader-app\n"
184+"Report-Msgid-Bugs-To: \n"
185+"POT-Creation-Date: 2016-06-10 14:54+0000\n"
186+"PO-Revision-Date: 2015-06-29 01:52+0000\n"
187+"Last-Translator: Ian Li <Unknown>\n"
188+"Language-Team: Chinese (Simplified) <zh_CN@li.org>\n"
189+"Language: \n"
190+"MIME-Version: 1.0\n"
191+"Content-Type: text/plain; charset=UTF-8\n"
192+"Content-Transfer-Encoding: 8bit\n"
193+"Plural-Forms: nplurals=1; plural=0;\n"
194+"X-Launchpad-Export-Date: 2016-03-24 06:05+0000\n"
195+"X-Generator: Launchpad (build 17958)\n"
196+
197+#: ../qml/components/ArticleViewItem.qml:125
198+msgid "Select article"
199+msgstr "选择文章"
200+
201+#: ../qml/components/ReadingOptions.qml:39
202+msgid "Dark"
203+msgstr "深色"
204+
205+#: ../qml/components/ReadingOptions.qml:46
206+msgid "Light"
207+msgstr "浅色"
208+
209+#: ../qml/components/ReadingOptions.qml:96
210+msgid "Small"
211+msgstr "小"
212+
213+#: ../qml/components/ReadingOptions.qml:98
214+msgid "Normal"
215+msgstr ""
216+
217+#: ../qml/components/ReadingOptions.qml:99
218+msgid "Large"
219+msgstr "大"
220+
221+#: ../qml/content/ImportFeeds.qml:30
222+msgid "Import Feeds"
223+msgstr ""
224+
225+#: ../qml/content/ImportFeeds.qml:42 ../qml/pages/TopicManagement.qml:258
226+msgid "Confirm"
227+msgstr "确认"
228+
229+#: ../qml/content/ImportFeeds.qml:313
230+msgid "Please select an opml file"
231+msgstr ""
232+
233+#: ../qml/content/ImportFeeds.qml:318
234+msgid "Open"
235+msgstr ""
236+
237+#: ../qml/content/ImportFeeds.qml:301
238+msgid ""
239+"Attention please, before importing opml file, Shorts only support one opml "
240+"structure. <br><br>"
241+msgstr ""
242+
243+#: ../qml/nongoogle/AppendNGFeedPage.qml:30 ../qml/pages/AppendFeedPage.qml:31
244+#: ../qml/shorts-app.qml:267 ../qml/shorts-app.qml:405
245+#: ../qml/shorts-app.qml:413
246+msgid "Add feeds"
247+msgstr "添加信息源"
248+
249+#: ../qml/nongoogle/AppendNGFeedPage.qml:99 ../qml/pages/AppendFeedPage.qml:137
250+msgid "Type a keyword or URL"
251+msgstr "请输入关键字或网址"
252+
253+#: ../qml/nongoogle/AppendNGFeedPage.qml:154
254+msgid "Feed Title:"
255+msgstr ""
256+
257+#: ../qml/nongoogle/AppendNGFeedPage.qml:162
258+#: ../qml/nongoogle/AppendNGFeedPage.qml:177
259+msgid "No data"
260+msgstr ""
261+
262+#: ../qml/nongoogle/AppendNGFeedPage.qml:169
263+msgid "Feed Description:"
264+msgstr ""
265+
266+#: ../qml/nongoogle/AppendNGFeedPage.qml:202
267+#: ../qml/pages/AppendFeedPage.qml:243 ../qml/pages/CreateTopicPage.qml:38
268+#: ../qml/pages/TopicManagement.qml:239 ../qml/shorts-app.qml:496
269+msgid "Cancel"
270+msgstr "取消"
271+
272+#: ../qml/nongoogle/AppendNGFeedPage.qml:235
273+#: ../qml/pages/AppendFeedPage.qml:276
274+msgid "Next"
275+msgstr "下一项"
276+
277+#: ../qml/pages/AppendFeedPage.qml:69
278+msgid "Failed to perform a feed search by keyword"
279+msgstr "暂时搜索不到有关该关键词的信息"
280+
281+#: ../qml/pages/AppendFeedPage.qml:70 ../qml/pages/AppendFeedPage.qml:101
282+msgid "Search failed"
283+msgstr "哎哟,好像除了点问题。。"
284+
285+#: ../qml/pages/AppendFeedPage.qml:100
286+msgid "Failed to perform a feed search by URL"
287+msgstr "暂时搜索不到有关该网址的信息"
288+
289+#: ../qml/pages/AppendFeedPage.qml:185
290+msgid "Search results"
291+msgstr "搜索结果"
292+
293+#: ../qml/pages/AppendFeedPage.qml:305 ../qml/pages/CreateTopicPage.qml:181
294+msgid "No feeds"
295+msgstr "当前没有信息源"
296+
297+#: ../qml/pages/ArticleViewPage.qml:47
298+msgid "Save"
299+msgstr "保存"
300+
301+#: ../qml/pages/ArticleViewPage.qml:47
302+msgid "Remove"
303+msgstr "移除"
304+
305+#: ../qml/pages/ArticleViewPage.qml:60
306+msgid "Options"
307+msgstr "选项"
308+
309+#: ../qml/pages/ArticleViewPage.qml:68
310+msgid "Open site"
311+msgstr "打开网站"
312+
313+#: ../qml/pages/ArticleViewPage.qml:76
314+msgid "Share..."
315+msgstr ""
316+
317+#: ../qml/pages/ChooseTopicPage.qml:13
318+msgid "Choose topic"
319+msgstr "请选择话题"
320+
321+#: ../qml/pages/ChooseTopicPage.qml:77
322+msgid "Add your new feeds to a topic"
323+msgstr "请添加您的信息源到某个话题中"
324+
325+#: ../qml/pages/ChooseTopicPage.qml:88
326+msgid " + New topic"
327+msgstr " + 添加新话题"
328+
329+#: ../qml/pages/ChooseTopicPage.qml:108 ../qml/pages/CreateTopicPage.qml:77
330+msgid "A topic with this name already exists"
331+msgstr "该话题已经存在"
332+
333+#: ../qml/pages/ChooseTopicPage.qml:109 ../qml/pages/ChooseTopicPage.qml:122
334+#: ../qml/pages/CreateTopicPage.qml:66 ../qml/pages/CreateTopicPage.qml:78
335+msgid "Warning"
336+msgstr "提示"
337+
338+#: ../qml/pages/ChooseTopicPage.qml:121 ../qml/pages/CreateTopicPage.qml:65
339+msgid "Topic name can't contain only whitespaces"
340+msgstr "请不要在话题中包含空格"
341+
342+#: ../qml/pages/CreateTopicPage.qml:12
343+msgid "Create new topic"
344+msgstr "创建一个新的话题"
345+
346+#: ../qml/pages/CreateTopicPage.qml:56 ../qml/pages/TopicManagement.qml:92
347+msgid "Add topic"
348+msgstr "添加话题"
349+
350+#: ../qml/pages/CreateTopicPage.qml:126
351+msgid "Type topic name"
352+msgstr "请输入话题名称"
353+
354+#: ../qml/pages/CreateTopicPage.qml:142
355+msgid "Select feeds (optional)"
356+msgstr "请选择信息源"
357+
358+#: ../qml/pages/EditFeedPage.qml:12
359+msgid "Edit Feed"
360+msgstr "编辑信息源"
361+
362+#: ../qml/pages/EditFeedPage.qml:19
363+msgid "Done"
364+msgstr "完成"
365+
366+#: ../qml/pages/EditFeedPage.qml:82
367+msgid "Title: "
368+msgstr "标题: "
369+
370+#: ../qml/pages/EditFeedPage.qml:103
371+msgid "URL: "
372+msgstr "地址: "
373+
374+#: ../qml/pages/EditFeedPage.qml:120
375+msgid "Topic: "
376+msgstr "话题: "
377+
378+#: ../qml/pages/PageHelp.qml:15
379+msgid "Welcome to Shorts"
380+msgstr ""
381+
382+#: ../qml/pages/PageHelp.qml:17
383+msgid "View Articles"
384+msgstr ""
385+
386+#: ../qml/pages/PageHelp.qml:19
387+msgid "Search RSS"
388+msgstr ""
389+
390+#: ../qml/pages/PageHelp.qml:21
391+msgid "Manage topics and feeds"
392+msgstr ""
393+
394+#: ../qml/pages/PageHelp.qml:23
395+msgid "Location"
396+msgstr ""
397+
398+#: ../qml/pages/PageHelp.qml:25
399+msgid "Enjoy"
400+msgstr ""
401+
402+#: ../qml/pages/PageHelp.qml:105
403+msgid "Shorts is an RSS reader app developed by Canonical & Ubuntu Comunity."
404+msgstr ""
405+
406+#: ../qml/pages/PageHelp.qml:110
407+msgid ""
408+"Shorts provides most primary features which also can be seen in other RSS "
409+"reader apps, with a beautiful Ubuntu style user interface."
410+msgstr ""
411+
412+#: ../qml/pages/PageHelp.qml:117
413+msgid "Swipe left to continue."
414+msgstr ""
415+
416+#: ../qml/pages/PageHelp.qml:136
417+msgid "Scroll left/right in grid mode or scroll up/down in list mode."
418+msgstr ""
419+
420+#: ../qml/pages/PageHelp.qml:163
421+msgid ""
422+"Swipe up will enter this search page, just type any simple words, or paste a "
423+"link."
424+msgstr ""
425+
426+#: ../qml/pages/PageHelp.qml:190
427+msgid ""
428+"Every feed must belong to one topic, swipe one item to delete feed/topic."
429+msgstr ""
430+
431+#: ../qml/pages/PageHelp.qml:223
432+msgid "Seems you are living in: "
433+msgstr ""
434+
435+#: ../qml/pages/PageHelp.qml:232
436+msgid ""
437+"Some regions/countries(e.g. China) may block Google service, if you're "
438+"living there or plan to go there, we suggest to trun off the build-in Google "
439+"RSS service in settings page, or nothing you should care."
440+msgstr ""
441+
442+#: ../qml/pages/PageHelp.qml:239
443+msgid ""
444+"We detect that you're living in some region/country(e.g. China) which blocks "
445+"Google service, so Shorts disable the build-in Google RSS service by "
446+"default. You still can turn it on here or in settings page."
447+msgstr ""
448+
449+#: ../qml/pages/PageHelp.qml:250
450+msgid "Use Google RSS engine: "
451+msgstr ""
452+
453+#: ../qml/pages/PageHelp.qml:287
454+msgid "Enjoy !"
455+msgstr ""
456+
457+#: ../qml/pages/PageHelp.qml:297
458+msgid "Do not show this help page again "
459+msgstr ""
460+
461+#: ../qml/pages/PageHelp.qml:316
462+msgid "Start using Shorts !"
463+msgstr ""
464+
465+#: ../qml/pages/PageHelp.qml:340
466+msgid "Skip"
467+msgstr ""
468+
469+#: ../qml/pages/PageInfo.qml:10
470+msgid "About Shorts"
471+msgstr ""
472+
473+#: ../qml/pages/PageInfo.qml:39
474+msgid "Author"
475+msgstr ""
476+
477+#: ../qml/pages/PageInfo.qml:53
478+msgid "Copyleft"
479+msgstr ""
480+
481+#: ../qml/pages/PageInfo.qml:57
482+msgid "License with GPLv3"
483+msgstr ""
484+
485+#: ../qml/pages/PageInfo.qml:62
486+msgid ""
487+"Ubuntu Shorts App is the official rss reader app for Ubuntu Touch. We follow "
488+"an open source model where the code is available to anyone to branch and "
489+"hack on. The ubuntu shorts app follows a test driven development (TDD) where "
490+"tests are written in parallel to feature implementation to help spot "
491+"regressions easier."
492+msgstr ""
493+
494+#: ../qml/pages/PageInfo.qml:68
495+msgid "Click here to report a bug"
496+msgstr ""
497+
498+#: ../qml/pages/PageSettings.qml:9 ../qml/shorts-app.qml:251
499+msgid "Settings"
500+msgstr ""
501+
502+#: ../qml/pages/PageSettings.qml:15
503+msgid "Help"
504+msgstr ""
505+
506+#: ../qml/pages/PageSettings.qml:20
507+msgid "Info"
508+msgstr ""
509+
510+#: ../qml/pages/PageSettings.qml:51
511+msgid ""
512+"Some special regions/countries block Google service, we suggest to turn off "
513+"the switch below if living in there."
514+msgstr ""
515+
516+#: ../qml/pages/PageSettings.qml:59
517+msgid "Use Google Search: "
518+msgstr ""
519+
520+#: ../qml/pages/PageSettings.qml:84
521+msgid ""
522+"For those users, who want to import their RSS feeds from other sources, "
523+"please press the button below."
524+msgstr ""
525+
526+#: ../qml/pages/PageSettings.qml:94
527+msgid "Import OPML"
528+msgstr ""
529+
530+#: ../qml/pages/TopicManagement.qml:13 ../qml/shorts-app.qml:231
531+msgid "Edit topics"
532+msgstr "编辑话题"
533+
534+#: ../qml/pages/TopicManagement.qml:274
535+msgid "Add Feed"
536+msgstr "添加信息源"
537+
538+#: ../qml/shorts-app.qml:198
539+msgid "Refresh"
540+msgstr "刷新"
541+
542+#: ../qml/shorts-app.qml:205
543+msgid "Grid View"
544+msgstr "网格视图"
545+
546+#: ../qml/shorts-app.qml:205
547+msgid "List view"
548+msgstr "列表视图"
549+
550+#: ../qml/shorts-app.qml:241
551+msgid "Disable night mode"
552+msgstr ""
553+
554+#: ../qml/shorts-app.qml:241
555+msgid "Enable night mode"
556+msgstr ""
557+
558+#: ../qml/shorts-app.qml:336
559+msgid "Saved"
560+msgstr "已保存"
561+
562+#: ../qml/shorts-app.qml:344 shorts.desktop.in.in.h:1
563+msgid "Shorts"
564+msgstr "摘要阅读"
565+
566+#: ../qml/shorts-app.qml:488
567+msgid "Checking for new articles"
568+msgstr "正在查询新的文章"
569+
570+#: ../qml/shorts-app.qml:512
571+msgid "Perhaps some of the channels have not been updated."
572+msgstr "部分频道内容可能未更新。"
573+
574+#: ../qml/shorts-app.qml:513
575+msgid "Errors occurred during the update"
576+msgstr "更新过程中出错"
577+
578+#: ../qml/shorts-app.qml:527
579+msgid "Ok"
580+msgstr "确认"
581+
582+#: ../qml/tabs/BaseTab.qml:153
583+msgid "There are no articles to show"
584+msgstr "当前没有文章可显示"
585+
586+#. TRANSLATORS: this is a time formatting string,
587+#. see http://qt-project.org/doc/qt-5.0/qtqml/qml-qtquick2-date.html#details for valid expressions
588+#: ../qml/utils/dateutils.js:39
589+msgid "MMMM d"
590+msgstr "M 月 d 日"
591+
592+#: ../qml/utils/dateutils.js:54
593+#, qt-format
594+msgid "Yesterday at %1"
595+msgstr "昨天 %1"
596+
597+#. TRANSLATORS: this is a time formatting string,
598+#. see http://qt-project.org/doc/qt-5.0/qtqml/qml-qtquick2-date.html#details for valid expressions
599+#: ../qml/utils/dateutils.js:57
600+msgid "h:mm AP"
601+msgstr "AP h:mm"
602+
603+#. TRANSLATORS: this is a time formatting string,
604+#. see http://qt-project.org/doc/qt-5.0/qtqml/qml-qtquick2-date.html#details for valid expressions
605+#: ../qml/utils/dateutils.js:69
606+msgid "ddd, h:mm AP"
607+msgstr "dddd,AP h:mm"
608+
609+#: ../qml/utils/dateutils.js:76
610+msgid "A few seconds ago..."
611+msgstr "刚刚"
612+
613+#: ../qml/utils/dateutils.js:79
614+#, qt-format
615+msgid "%1 minute ago"
616+msgid_plural "%1 minutes ago"
617+msgstr[0] "%1 分钟前"
618+
619+#: ../qml/utils/dateutils.js:83
620+#, qt-format
621+msgid "%1 hour ago"
622+msgid_plural "%1 hours ago"
623+msgstr[0] "%1 小时前"
624+
625+#: ../qml/utils/dateutils.js:89
626+#, qt-format
627+msgid "%1 day ago"
628+msgid_plural "%1 days ago"
629+msgstr[0] "%1 天前"
630+
631+#: shorts.desktop.in.in.h:2
632+msgid "shorts;rss;reader;"
633+msgstr "简讯;rss;聚合;阅读;"
634
635=== removed file 'shorts/po/zh_CN.po'
636--- shorts/po/zh_CN.po 2016-03-24 06:05:40 +0000
637+++ shorts/po/zh_CN.po 1970-01-01 00:00:00 +0000
638@@ -1,458 +0,0 @@
639-# Chinese (Simplified) translation for ubuntu-rssreader-app
640-# Copyright (c) 2013 Rosetta Contributors and Canonical Ltd 2013
641-# This file is distributed under the same license as the ubuntu-rssreader-app package.
642-# FIRST AUTHOR <EMAIL@ADDRESS>, 2013.
643-#
644-msgid ""
645-msgstr ""
646-"Project-Id-Version: ubuntu-rssreader-app\n"
647-"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
648-"POT-Creation-Date: 2016-03-11 20:54+0800\n"
649-"PO-Revision-Date: 2015-06-29 01:52+0000\n"
650-"Last-Translator: Ian Li <Unknown>\n"
651-"Language-Team: Chinese (Simplified) <zh_CN@li.org>\n"
652-"MIME-Version: 1.0\n"
653-"Content-Type: text/plain; charset=UTF-8\n"
654-"Content-Transfer-Encoding: 8bit\n"
655-"Plural-Forms: nplurals=1; plural=0;\n"
656-"X-Launchpad-Export-Date: 2016-03-24 06:05+0000\n"
657-"X-Generator: Launchpad (build 17958)\n"
658-
659-#: ../qml/components/ArticleViewItem.qml:120
660-msgid "Select article"
661-msgstr "选择文章"
662-
663-#: ../qml/components/ReadingOptions.qml:39
664-msgid "Dark"
665-msgstr "深色"
666-
667-#: ../qml/components/ReadingOptions.qml:46
668-msgid "Light"
669-msgstr "浅色"
670-
671-#: ../qml/components/ReadingOptions.qml:96
672-msgid "Small"
673-msgstr "小"
674-
675-#: ../qml/components/ReadingOptions.qml:98
676-msgid "Normal"
677-msgstr ""
678-
679-#: ../qml/components/ReadingOptions.qml:99
680-msgid "Large"
681-msgstr "大"
682-
683-#: ../qml/content/ImportFeeds.qml:30
684-msgid "Import Feeds"
685-msgstr ""
686-
687-#: ../qml/content/ImportFeeds.qml:42 ../qml/pages/TopicManagement.qml:258
688-msgid "Confirm"
689-msgstr "确认"
690-
691-#: ../qml/content/ImportFeeds.qml:305
692-msgid "Please select an opml file"
693-msgstr ""
694-
695-#: ../qml/content/ImportFeeds.qml:310
696-msgid "Open"
697-msgstr ""
698-
699-#: ../qml/content/ImportFeeds.qml:293
700-msgid ""
701-"Attention please, before importing opml file, Shorts only support one opml "
702-"structure. <br><br>"
703-msgstr ""
704-
705-#: ../qml/nongoogle/AppendNGFeedPage.qml:30 ../qml/pages/AppendFeedPage.qml:31
706-#: ../qml/shorts-app.qml:265 ../qml/shorts-app.qml:403
707-#: ../qml/shorts-app.qml:411
708-msgid "Add feeds"
709-msgstr "添加信息源"
710-
711-#: ../qml/nongoogle/AppendNGFeedPage.qml:94
712-#: ../qml/pages/AppendFeedPage.qml:137
713-msgid "Type a keyword or URL"
714-msgstr "请输入关键字或网址"
715-
716-#: ../qml/nongoogle/AppendNGFeedPage.qml:149
717-msgid "Feed Title:"
718-msgstr ""
719-
720-#: ../qml/nongoogle/AppendNGFeedPage.qml:157
721-#: ../qml/nongoogle/AppendNGFeedPage.qml:172
722-msgid "No data"
723-msgstr ""
724-
725-#: ../qml/nongoogle/AppendNGFeedPage.qml:164
726-msgid "Feed Description:"
727-msgstr ""
728-
729-#: ../qml/nongoogle/AppendNGFeedPage.qml:197
730-#: ../qml/pages/AppendFeedPage.qml:243 ../qml/pages/CreateTopicPage.qml:38
731-#: ../qml/pages/TopicManagement.qml:239 ../qml/shorts-app.qml:494
732-msgid "Cancel"
733-msgstr "取消"
734-
735-#: ../qml/nongoogle/AppendNGFeedPage.qml:230
736-#: ../qml/pages/AppendFeedPage.qml:276
737-msgid "Next"
738-msgstr "下一项"
739-
740-#: ../qml/pages/AppendFeedPage.qml:69
741-msgid "Failed to perform a feed search by keyword"
742-msgstr "暂时搜索不到有关该关键词的信息"
743-
744-#: ../qml/pages/AppendFeedPage.qml:70 ../qml/pages/AppendFeedPage.qml:101
745-msgid "Search failed"
746-msgstr "哎哟,好像除了点问题。。"
747-
748-#: ../qml/pages/AppendFeedPage.qml:100
749-msgid "Failed to perform a feed search by URL"
750-msgstr "暂时搜索不到有关该网址的信息"
751-
752-#: ../qml/pages/AppendFeedPage.qml:185
753-msgid "Search results"
754-msgstr "搜索结果"
755-
756-#: ../qml/pages/AppendFeedPage.qml:305 ../qml/pages/CreateTopicPage.qml:181
757-msgid "No feeds"
758-msgstr "当前没有信息源"
759-
760-#: ../qml/pages/ArticleViewPage.qml:47
761-msgid "Save"
762-msgstr "保存"
763-
764-#: ../qml/pages/ArticleViewPage.qml:47
765-msgid "Remove"
766-msgstr "移除"
767-
768-#: ../qml/pages/ArticleViewPage.qml:60
769-msgid "Options"
770-msgstr "选项"
771-
772-#: ../qml/pages/ArticleViewPage.qml:68
773-msgid "Open site"
774-msgstr "打开网站"
775-
776-#: ../qml/pages/ArticleViewPage.qml:76
777-msgid "Share..."
778-msgstr ""
779-
780-#: ../qml/pages/ChooseTopicPage.qml:13
781-msgid "Choose topic"
782-msgstr "请选择话题"
783-
784-#: ../qml/pages/ChooseTopicPage.qml:77
785-msgid "Add your new feeds to a topic"
786-msgstr "请添加您的信息源到某个话题中"
787-
788-#: ../qml/pages/ChooseTopicPage.qml:88
789-msgid " + New topic"
790-msgstr " + 添加新话题"
791-
792-#: ../qml/pages/ChooseTopicPage.qml:108 ../qml/pages/CreateTopicPage.qml:77
793-msgid "A topic with this name already exists"
794-msgstr "该话题已经存在"
795-
796-#: ../qml/pages/ChooseTopicPage.qml:109 ../qml/pages/ChooseTopicPage.qml:122
797-#: ../qml/pages/CreateTopicPage.qml:66 ../qml/pages/CreateTopicPage.qml:78
798-msgid "Warning"
799-msgstr "提示"
800-
801-#: ../qml/pages/ChooseTopicPage.qml:121 ../qml/pages/CreateTopicPage.qml:65
802-msgid "Topic name can't contain only whitespaces"
803-msgstr "请不要在话题中包含空格"
804-
805-#: ../qml/pages/CreateTopicPage.qml:12
806-msgid "Create new topic"
807-msgstr "创建一个新的话题"
808-
809-#: ../qml/pages/CreateTopicPage.qml:56 ../qml/pages/TopicManagement.qml:92
810-msgid "Add topic"
811-msgstr "添加话题"
812-
813-#: ../qml/pages/CreateTopicPage.qml:126
814-msgid "Type topic name"
815-msgstr "请输入话题名称"
816-
817-#: ../qml/pages/CreateTopicPage.qml:142
818-msgid "Select feeds (optional)"
819-msgstr "请选择信息源"
820-
821-#: ../qml/pages/EditFeedPage.qml:12
822-msgid "Edit Feed"
823-msgstr "编辑信息源"
824-
825-#: ../qml/pages/EditFeedPage.qml:19
826-msgid "Done"
827-msgstr "完成"
828-
829-#: ../qml/pages/EditFeedPage.qml:82
830-msgid "Title: "
831-msgstr "标题: "
832-
833-#: ../qml/pages/EditFeedPage.qml:103
834-msgid "URL: "
835-msgstr "地址: "
836-
837-#: ../qml/pages/EditFeedPage.qml:120
838-msgid "Topic: "
839-msgstr "话题: "
840-
841-#: ../qml/pages/PageHelp.qml:15
842-msgid "Welcome to Shorts"
843-msgstr ""
844-
845-#: ../qml/pages/PageHelp.qml:17
846-msgid "View Articles"
847-msgstr ""
848-
849-#: ../qml/pages/PageHelp.qml:19
850-msgid "Search RSS"
851-msgstr ""
852-
853-#: ../qml/pages/PageHelp.qml:21
854-msgid "Manage topics and feeds"
855-msgstr ""
856-
857-#: ../qml/pages/PageHelp.qml:23
858-msgid "Location"
859-msgstr ""
860-
861-#: ../qml/pages/PageHelp.qml:25
862-msgid "Enjoy"
863-msgstr ""
864-
865-#: ../qml/pages/PageHelp.qml:105
866-msgid "Shorts is an RSS reader app developed by Canonical & Ubuntu Comunity."
867-msgstr ""
868-
869-#: ../qml/pages/PageHelp.qml:110
870-msgid ""
871-"Shorts provides most primary features which also can be seen in other RSS "
872-"reader apps, with a beautiful Ubuntu style user interface."
873-msgstr ""
874-
875-#: ../qml/pages/PageHelp.qml:117
876-msgid "Swipe left to continue."
877-msgstr ""
878-
879-#: ../qml/pages/PageHelp.qml:136
880-msgid "Scroll left/right in grid mode or scroll up/down in list mode."
881-msgstr ""
882-
883-#: ../qml/pages/PageHelp.qml:163
884-msgid ""
885-"Swipe up will enter this search page, just type any simple words, or paste a "
886-"link."
887-msgstr ""
888-
889-#: ../qml/pages/PageHelp.qml:190
890-msgid ""
891-"Every feed must belong to one topic, swipe one item to delete feed/topic."
892-msgstr ""
893-
894-#: ../qml/pages/PageHelp.qml:223
895-msgid "Seems you are living in: "
896-msgstr ""
897-
898-#: ../qml/pages/PageHelp.qml:232
899-msgid ""
900-"Some regions/countries(e.g. China) may block Google service, if you're "
901-"living there or plan to go there, we suggest to trun off the build-in Google "
902-"RSS service in settings page, or nothing you should care."
903-msgstr ""
904-
905-#: ../qml/pages/PageHelp.qml:239
906-msgid ""
907-"We detect that you're living in some region/country(e.g. China) which blocks "
908-"Google service, so Shorts disable the build-in Google RSS service by "
909-"default. You still can turn it on here or in settings page."
910-msgstr ""
911-
912-#: ../qml/pages/PageHelp.qml:250
913-msgid "Use Google RSS engine: "
914-msgstr ""
915-
916-#: ../qml/pages/PageHelp.qml:287
917-msgid "Enjoy !"
918-msgstr ""
919-
920-#: ../qml/pages/PageHelp.qml:297
921-msgid "Do not show this help page again "
922-msgstr ""
923-
924-#: ../qml/pages/PageHelp.qml:316
925-msgid "Start using Shorts !"
926-msgstr ""
927-
928-#: ../qml/pages/PageHelp.qml:340
929-msgid "Skip"
930-msgstr ""
931-
932-#: ../qml/pages/PageInfo.qml:10
933-msgid "About Shorts"
934-msgstr ""
935-
936-#: ../qml/pages/PageInfo.qml:39
937-msgid "Author"
938-msgstr ""
939-
940-#: ../qml/pages/PageInfo.qml:53
941-msgid "Copyleft"
942-msgstr ""
943-
944-#: ../qml/pages/PageInfo.qml:57
945-msgid "License with GPLv3"
946-msgstr ""
947-
948-#: ../qml/pages/PageInfo.qml:62
949-msgid ""
950-"Ubuntu Shorts App is the official rss reader app for Ubuntu Touch. We follow "
951-"an open source model where the code is available to anyone to branch and "
952-"hack on. The ubuntu shorts app follows a test driven development (TDD) where "
953-"tests are written in parallel to feature implementation to help spot "
954-"regressions easier."
955-msgstr ""
956-
957-#: ../qml/pages/PageInfo.qml:68
958-msgid "Click here to report a bug"
959-msgstr ""
960-
961-#: ../qml/pages/PageSettings.qml:9 ../qml/shorts-app.qml:249
962-msgid "Settings"
963-msgstr ""
964-
965-#: ../qml/pages/PageSettings.qml:15
966-msgid "Help"
967-msgstr ""
968-
969-#: ../qml/pages/PageSettings.qml:20
970-msgid "Info"
971-msgstr ""
972-
973-#: ../qml/pages/PageSettings.qml:51
974-msgid ""
975-"Some special regions/countries block Google service, we suggest to turn off "
976-"the switch below if living in there."
977-msgstr ""
978-
979-#: ../qml/pages/PageSettings.qml:59
980-msgid "Use Google Search: "
981-msgstr ""
982-
983-#: ../qml/pages/PageSettings.qml:84
984-msgid ""
985-"For those users, who want to import their RSS feeds from other sources, "
986-"please press the button below."
987-msgstr ""
988-
989-#: ../qml/pages/PageSettings.qml:94
990-msgid "Import OPML"
991-msgstr ""
992-
993-#: ../qml/pages/TopicManagement.qml:13 ../qml/shorts-app.qml:229
994-msgid "Edit topics"
995-msgstr "编辑话题"
996-
997-#: ../qml/pages/TopicManagement.qml:274
998-msgid "Add Feed"
999-msgstr "添加信息源"
1000-
1001-#: ../qml/shorts-app.qml:196
1002-msgid "Refresh"
1003-msgstr "刷新"
1004-
1005-#: ../qml/shorts-app.qml:203
1006-msgid "Grid View"
1007-msgstr "网格视图"
1008-
1009-#: ../qml/shorts-app.qml:203
1010-msgid "List view"
1011-msgstr "列表视图"
1012-
1013-#: ../qml/shorts-app.qml:239
1014-msgid "Disable night mode"
1015-msgstr ""
1016-
1017-#: ../qml/shorts-app.qml:239
1018-msgid "Enable night mode"
1019-msgstr ""
1020-
1021-#: ../qml/shorts-app.qml:334
1022-msgid "Saved"
1023-msgstr "已保存"
1024-
1025-#: ../qml/shorts-app.qml:342 shorts.desktop.in.in.h:1
1026-msgid "Shorts"
1027-msgstr "摘要阅读"
1028-
1029-#: ../qml/shorts-app.qml:486
1030-msgid "Checking for new articles"
1031-msgstr "正在查询新的文章"
1032-
1033-#: ../qml/shorts-app.qml:510
1034-msgid "Perhaps some of the channels have not been updated."
1035-msgstr "部分频道内容可能未更新。"
1036-
1037-#: ../qml/shorts-app.qml:511
1038-msgid "Errors occurred during the update"
1039-msgstr "更新过程中出错"
1040-
1041-#: ../qml/shorts-app.qml:525
1042-msgid "Ok"
1043-msgstr "确认"
1044-
1045-#: ../qml/tabs/BaseTab.qml:153
1046-msgid "There are no articles to show"
1047-msgstr "当前没有文章可显示"
1048-
1049-#. TRANSLATORS: this is a time formatting string,
1050-#. see http://qt-project.org/doc/qt-5.0/qtqml/qml-qtquick2-date.html#details for valid expressions
1051-#: ../qml/utils/dateutils.js:39
1052-msgid "MMMM d"
1053-msgstr "M 月 d 日"
1054-
1055-#: ../qml/utils/dateutils.js:54
1056-#, qt-format
1057-msgid "Yesterday at %1"
1058-msgstr "昨天 %1"
1059-
1060-#. TRANSLATORS: this is a time formatting string,
1061-#. see http://qt-project.org/doc/qt-5.0/qtqml/qml-qtquick2-date.html#details for valid expressions
1062-#: ../qml/utils/dateutils.js:57
1063-msgid "h:mm AP"
1064-msgstr "AP h:mm"
1065-
1066-#. TRANSLATORS: this is a time formatting string,
1067-#. see http://qt-project.org/doc/qt-5.0/qtqml/qml-qtquick2-date.html#details for valid expressions
1068-#: ../qml/utils/dateutils.js:69
1069-msgid "ddd, h:mm AP"
1070-msgstr "dddd,AP h:mm"
1071-
1072-#: ../qml/utils/dateutils.js:76
1073-msgid "A few seconds ago..."
1074-msgstr "刚刚"
1075-
1076-#: ../qml/utils/dateutils.js:79
1077-#, qt-format
1078-msgid "%1 minute ago"
1079-msgid_plural "%1 minutes ago"
1080-msgstr[0] "%1 分钟前"
1081-
1082-#: ../qml/utils/dateutils.js:83
1083-#, qt-format
1084-msgid "%1 hour ago"
1085-msgid_plural "%1 hours ago"
1086-msgstr[0] "%1 小时前"
1087-
1088-#: ../qml/utils/dateutils.js:89
1089-#, qt-format
1090-msgid "%1 day ago"
1091-msgid_plural "%1 days ago"
1092-msgstr[0] "%1 天前"
1093-
1094-#: shorts.desktop.in.in.h:2
1095-msgid "shorts;rss;reader;"
1096-msgstr "简讯;rss;聚合;阅读;"
1097
1098=== modified file 'shorts/qml/components/ArticleViewItem.qml'
1099--- shorts/qml/components/ArticleViewItem.qml 2016-01-16 10:55:38 +0000
1100+++ shorts/qml/components/ArticleViewItem.qml 2016-06-15 16:13:25 +0000
1101@@ -59,6 +59,11 @@
1102 }
1103 }
1104
1105+ function escape2Html(str) {
1106+ var arrEntities={'lt':'<','gt':'>','nbsp':' ','amp':'&','quot':'"'};
1107+ return str.replace(/&(lt|gt|nbsp|amp|quot);/ig,function(all,t){return arrEntities[t];});
1108+ }
1109+
1110
1111 ////////////////////////////////////////////// a listview to show the RSS content
1112 ListView {
1113@@ -195,7 +200,7 @@
1114 }
1115
1116 Label {
1117- text: model.content
1118+ text: escape2Html(model.content)
1119
1120 fontSize: {
1121 switch(rssListview.contentFontSize) {
1122
1123=== modified file 'shorts/qml/content/ContentPickerDialog.qml'
1124--- shorts/qml/content/ContentPickerDialog.qml 2016-01-10 09:04:00 +0000
1125+++ shorts/qml/content/ContentPickerDialog.qml 2016-06-15 16:13:25 +0000
1126@@ -29,6 +29,10 @@
1127 id: picker
1128 visible: false
1129
1130+ header: PageHeader {
1131+ visible: false
1132+ }
1133+
1134 property var pickerParent
1135
1136 ContentPeerPicker {
1137
1138=== modified file 'shorts/qml/content/ImportFeeds.qml'
1139--- shorts/qml/content/ImportFeeds.qml 2016-01-14 15:35:31 +0000
1140+++ shorts/qml/content/ImportFeeds.qml 2016-06-15 16:13:25 +0000
1141@@ -45,7 +45,9 @@
1142 DB.importOPMLobject(repeaterFeedList.opmlList)
1143 mainView.reloadViews()
1144 pageStack.pop()
1145+ pageStack.pop()
1146 mainView.refresh()
1147+// print ("repeaterFeedList.opmlList: ", JSON.stringify(repeaterFeedList.opmlList[0]))
1148 }
1149 }
1150
1151@@ -147,6 +149,7 @@
1152
1153 ListItem.Empty {
1154 id: liStandardRoot
1155+ height: units.gu(6.5)
1156
1157 property var opmlRoot: repeaterFeedList.opmlList == undefined ?
1158 undefined : repeaterFeedList.opmlList[index]
1159@@ -172,6 +175,7 @@
1160
1161 CheckBox {
1162 id: checkboxRoot
1163+ anchors.verticalCenter: parent.verticalCenter
1164 }
1165
1166 Label{
1167@@ -217,7 +221,8 @@
1168 Repeater {
1169 id: repeaterFeedsChildren
1170 model: liStandardRoot.opmlRoot == undefined ?
1171- "" : liStandardRoot.opmlRoot.children
1172+// "" : liStandardRoot.opmlRoot.children
1173+ "" : liStandardRoot.opmlRoot.outline
1174
1175 ListItem.Standard {
1176 id: listitemFeed
1177@@ -227,7 +232,10 @@
1178 // height: visible ? units.gu(6) : 0
1179
1180 property var opmlFeed: liStandardRoot.opmlRoot == undefined ?
1181- undefined : liStandardRoot.opmlRoot.children[index]
1182+ undefined : liStandardRoot.opmlRoot.outline[index]
1183+// undefined : liStandardRoot.opmlRoot.children[index]
1184+// undefined : (liStandardRoot.opmlRoot.outline[index] == undefined ?
1185+// liStandardRoot.opmlRoot.outline : liStandardRoot.opmlRoot.outline[index])
1186
1187 Connections {
1188 target: liStandardRoot
1189
1190=== modified file 'shorts/qml/content/OpmlParser.qml'
1191--- shorts/qml/content/OpmlParser.qml 2016-01-10 09:04:00 +0000
1192+++ shorts/qml/content/OpmlParser.qml 2016-06-15 16:13:25 +0000
1193@@ -21,16 +21,39 @@
1194
1195 import QtQuick.XmlListModel 2.0
1196
1197-import "../utils/databasemodule_v2.js" as DB
1198-//import "../."
1199
1200 Item {
1201 id: opmlParser
1202
1203 property string opmlPath: ""
1204+ onOpmlPathChanged: {
1205+ utilities.loadOpml(opmlPath)
1206+ }
1207
1208 signal parseFinished(var opml)
1209
1210+ Connections {
1211+ target: utilities
1212+
1213+ onSigOpmlJsom: {
1214+// print("opml json: ", JSON.stringify(result))
1215+// print("opml json: ", /*result.opml.body.outline[0].outline[0].xmlUrl,*/ JSON.stringify(result.opml.body.outline[0].outline))
1216+
1217+ // if only one feed in a folder, there's no JS array in it, only one obj, so I add an array in a folder, make the structure compatible
1218+ for (var i=0; i<result.opml.body.outline.length; i++) {
1219+ var outLine = result.opml.body.outline[i]
1220+ if (result.opml.body.outline[i].outline[0] == undefined) {
1221+ var tmpobj = result.opml.body.outline[i].outline
1222+ var tmparr = new Array
1223+ tmparr.push(tmpobj)
1224+ result.opml.body.outline[i].outline = tmparr
1225+ }
1226+ }
1227+
1228+ parseFinished(result.opml.body.outline)
1229+ }
1230+ }
1231+
1232 XmlListModel {
1233 id: modelOpml
1234 property string subTitle
1235@@ -91,23 +114,23 @@
1236 }
1237
1238 onStatusChanged: {
1239- console.log("model status:", status)
1240- if (status == XmlListModel.Ready) {
1241- if (!subTitle) {
1242- allRootsCount = count
1243- // get all root object
1244- getAllRootObj()
1245- }
1246- else {
1247- // load children object one by one
1248-// console.log("children objs: ", JSON.stringify(opmlObj))
1249-// console.log("model count: ", count)
1250- getChildObjsFromOneRoot()
1251- }
1252- }
1253- else if (status == XmlListModel.Error) {
1254- console.log("XmlListModel.Error: ", errorString())
1255- }
1256+// console.log("model status:", status)
1257+// if (status == XmlListModel.Ready) {
1258+// if (!subTitle) {
1259+// allRootsCount = count
1260+// // get all root object
1261+// getAllRootObj()
1262+// }
1263+// else {
1264+// // load children object one by one
1265+//// console.log("children objs: ", JSON.stringify(opmlObj))
1266+//// console.log("model count: ", count)
1267+// getChildObjsFromOneRoot()
1268+// }
1269+// }
1270+// else if (status == XmlListModel.Error) {
1271+// console.log("XmlListModel.Error: ", errorString())
1272+// }
1273 }
1274
1275 query: subTitle ? "/opml/body/outline[@text='" + subTitle + "']/outline": "/opml/body/outline"
1276
1277=== modified file 'shorts/qml/nongoogle/AppendNGFeedPage.qml'
1278--- shorts/qml/nongoogle/AppendNGFeedPage.qml 2016-01-04 11:13:30 +0000
1279+++ shorts/qml/nongoogle/AppendNGFeedPage.qml 2016-06-15 16:13:25 +0000
1280@@ -1,5 +1,5 @@
1281 /*
1282- * Copyright (C) 2013, 2014
1283+ * Copyright (C) 2013, 2014, 2015, 2016
1284 *
1285 * This program is free software; you can redistribute it and/or modify
1286 * it under the terms of the GNU General Public License as published by
1287@@ -24,9 +24,9 @@
1288 import "../."
1289
1290 Page {
1291- id: appendFeedPage
1292+ id: appendFeedPageNG
1293
1294- objectName: "appendfeedpage"
1295+ objectName: "appendFeedPageNG"
1296 title: i18n.tr("Add feeds")
1297 flickable: null
1298 visible: false
1299@@ -58,15 +58,20 @@
1300 id: xmlFeedApi
1301
1302 onLoadResult: {
1303+ if (mainStack.currentPage != appendFeedPageNG) { return }
1304+
1305 if (!result.rss) {
1306 print("onLoadResult failed")
1307 }
1308 else {
1309- var f = result.rss.channel
1310+ var e = result.rss.channel
1311
1312- feedDesc = f.description ? (f.description["#text"] ? f.description["#text"] : f.description ) : ""
1313- feedTitle = f.title ? (f.title["#text"] ? f.title["#text"] : f.title ) : ""
1314- feedLink = f.link ? (f.link["#text"] ? f.link["#text"] : f.link) : ""
1315+ try {
1316+ feedDesc = e.description == undefined ? "" : e.description["#text"] == undefined ? e.description : e.description["#text"]
1317+ feedTitle = e.title == undefined ? "" : e.title["#text"] == undefined ? e.title : e.title["#text"]
1318+ feedLink = e.link == undefined ? "" : e.link["#text"] == undefined ? e.link : e.link["#text"]
1319+ }
1320+ catch (err) { ; }
1321 feedObj = {
1322 "url" : feedUrl,
1323 "title" : feedTitle,
1324@@ -129,8 +134,8 @@
1325 var isUrlEntered = (userInput.indexOf(" ") === -1 && userInput.indexOf(".") !== -1)
1326
1327 if (isUrlEntered) {
1328- if (userInput.indexOf("http://") !== 0)
1329- {userInput = "http://" + userInput}
1330+// if (userInput.indexOf("http://") !== 0)
1331+// {userInput = "http://" + userInput}
1332 feedUrl = userInput
1333 xmlFeedApi.loadFeed(userInput)
1334 }
1335
1336=== modified file 'shorts/qml/nongoogle/XmlNetwork.qml'
1337--- shorts/qml/nongoogle/XmlNetwork.qml 2016-03-11 13:04:57 +0000
1338+++ shorts/qml/nongoogle/XmlNetwork.qml 2016-06-15 16:13:25 +0000
1339@@ -1,53 +1,66 @@
1340 import QtQuick 2.4
1341-import "../utils/xml2json.js" as XJ
1342
1343 QtObject {
1344 id: rootObject
1345
1346- property bool inProgress: __doc != null
1347+// property bool inProgress: __doc != null
1348+ property bool inProgress: false
1349
1350 signal findResult(var result)
1351 signal loadResult(var result)
1352
1353 property var __doc: null
1354
1355+ property variant connObj: Connections {
1356+ id: connUtilities
1357+ target: utilities
1358+
1359+ onSigResult: {
1360+ inProgress = false
1361+ loadResult(result)
1362+ }
1363+ }
1364+
1365 /* Load feed by URL.
1366 */
1367- function loadFeed(feedUrl, num) {
1368- abort(true)
1369-
1370- if (num)
1371- num = Math.min(num, 100)
1372- else num = 50
1373-
1374- __doc = new XMLHttpRequest()
1375- var doc = __doc
1376-
1377- doc.onreadystatechange = function() {
1378-
1379-// print("xmlnetwork onreadystatechange: ", doc.readyState, doc.status, feedUrl)
1380- if (doc.readyState === XMLHttpRequest.DONE) {
1381-
1382- var resObj
1383-// print ("status & text: ", doc.status, doc.statusText, doc.responseText)
1384- if (doc.status == 200) {
1385- resObj = utilities.xmlToJson(doc.responseText)
1386-// resObj = utilities.xmlToJson(doc.responseText)
1387-// var x2js = new XJ.X2JS();
1388-// resObj = XJ.xmlToJSON.parseString(doc.responseText) //x2js.xml_str2json( doc.responseText );
1389- } else { // Error
1390- resObj = {"responseDetails" : doc.statusText,
1391- "responseStatus" : doc.status}
1392- }
1393-
1394- print ("resObj: ", resObj.rss )
1395- __doc = null
1396- loadResult(resObj)
1397- }
1398- }
1399-
1400- doc.open("GET", feedUrl, true);
1401- doc.send();
1402+ function loadFeed(feedUrl/*, num*/) {
1403+// connUtilities.target = utilities
1404+// abort(true)
1405+ inProgress = true
1406+ utilities.loadFeed(feedUrl)
1407+
1408+// if (num)
1409+// num = Math.min(num, 100)
1410+// else num = 50
1411+
1412+// __doc = new XMLHttpRequest()
1413+// var doc = __doc
1414+
1415+// doc.onreadystatechange = function() {
1416+
1417+//// print("xmlnetwork onreadystatechange: ", doc.readyState, doc.status, feedUrl)
1418+// if (doc.readyState === XMLHttpRequest.DONE) {
1419+
1420+// var resObj
1421+//// print ("status & text: ", doc.status, doc.statusText, doc.responseText)
1422+// if (doc.status == 200) {
1423+// resObj = utilities.xmlToJson(doc.responseText)
1424+//// resObj = utilities.xmlToJson(doc.responseText)
1425+//// var x2js = new XJ.X2JS();
1426+//// resObj = XJ.xmlToJSON.parseString(doc.responseText) //x2js.xml_str2json( doc.responseText );
1427+// } else { // Error
1428+// resObj = {"responseDetails" : doc.statusText,
1429+// "responseStatus" : doc.status}
1430+// }
1431+
1432+// print ("resObj: ", resObj.rss )
1433+// __doc = null
1434+// loadResult(resObj)
1435+// }
1436+// }
1437+
1438+// doc.open("GET", feedUrl, true);
1439+// doc.send();
1440 }
1441
1442 /* Param "isAbortOnly" used to preserve
1443@@ -56,11 +69,13 @@
1444 * additional recalculations.
1445 */
1446 function abort(isAbortOnly) {
1447- if (__doc != null) {
1448- __doc.abort()
1449- if (!isAbortOnly)
1450- __doc = null
1451- }
1452+// if (__doc != null) {
1453+// __doc.abort()
1454+// if (!isAbortOnly)
1455+// __doc = null
1456+// }
1457+
1458+ utilities.abort()
1459 }
1460
1461 /* Return true if some kind of errors detected.
1462
1463=== modified file 'shorts/qml/shorts-app.qml'
1464--- shorts/qml/shorts-app.qml 2016-03-04 13:27:57 +0000
1465+++ shorts/qml/shorts-app.qml 2016-06-15 16:13:25 +0000
1466@@ -30,6 +30,8 @@
1467
1468 backgroundColor: "#F5F5F5"
1469
1470+ property alias mainStack: pageStack
1471+
1472 Component.onCompleted: {
1473 // show help page in first use
1474 if (optionsKeeper.needPopup) {
1475
1476=== modified file 'shorts/qml/utils/databasemodule_v2.js'
1477--- shorts/qml/utils/databasemodule_v2.js 2016-03-04 13:27:57 +0000
1478+++ shorts/qml/utils/databasemodule_v2.js 2016-06-15 16:13:25 +0000
1479@@ -703,20 +703,20 @@
1480 // topic(tag) end, tagID is the unique id of a topic
1481
1482 // insert feed start
1483- for (var j=0; j<opml[i].children.length; j++) {
1484- if (opml[i].children[j].isSelected) {
1485+ for (var j=0; j<opml[i].outline.length; j++) {
1486+ if (opml[i].outline[j].isSelected) {
1487 /* Check uniqueness.
1488 */
1489 var feedID = -1
1490- var feedResult = tx.executeSql("SELECT * FROM feed WHERE source=?", [opml[i].children[j].xmlUrl])
1491+ var feedResult = tx.executeSql("SELECT * FROM feed WHERE source=?", [opml[i].outline[j].xmlUrl])
1492 if (feedResult.rows.length > 0) {
1493- console.log("Database, importOPMLobject: already exist feed with source: ", opml[i].children[j].xmlUrl, "ID", feedResult.rows.item(0).id)
1494+ console.log("Database, importOPMLobject: already exist feed with source: ", opml[i].outline[j].xmlUrl, "ID", feedResult.rows.item(0).id)
1495 feedID = feedResult.rows.item(0).id
1496 }
1497 else {
1498 // insert feed
1499 feedResult = tx.executeSql('INSERT INTO feed (title, source) VALUES(?, ?)',
1500- [opml[i].children[j].title , opml[i].children[j].xmlUrl])
1501+ [opml[i].outline[j].title , opml[i].outline[j].xmlUrl])
1502 feedID = feedResult.insertId
1503 console.log("Database, importOPMLobject: feed INSERT ID: ", feedID)
1504 }
1505@@ -735,6 +735,8 @@
1506 }
1507 }
1508 }
1509+
1510+
1511 }
1512 else {
1513 continue
1514
1515=== modified file 'shorts/utilities.cpp'
1516--- shorts/utilities.cpp 2016-03-11 13:04:57 +0000
1517+++ shorts/utilities.cpp 2016-06-15 16:13:25 +0000
1518@@ -4,16 +4,22 @@
1519 Utilities::Utilities(QObject *parent) :
1520 QObject(parent)
1521 {
1522-// qDebug() << "path: " << QDir::currentPath() ;
1523-// QFile xmlFile("xml");
1524-// xmlFile.open(QIODevice::ReadOnly | QIODevice::Text);
1525-
1526-// qDebug() << "json: " << xmlToJson(QString(xmlFile.readAll())).size();
1527+ _internalMgr = new QNetworkAccessManager(this);
1528+ _loadTimer = new QTimer(this);
1529+ _loadTimer->setSingleShot(true);
1530 }
1531
1532-QJsonObject Utilities::xmlToJson(const QString &xml)
1533+QJsonObject Utilities::xmlToJson(const QByteArray &xml)
1534 {
1535- QByteArray ba = xml.toLocal8Bit();
1536+ // check if the input doc is an xml doc
1537+// QString xmldoc = QString(xml);
1538+// if (xmldoc.indexOf("<?xml") != 0)
1539+// {
1540+// return QJsonDocument::fromJson(QString('{"error":4, "errorString":"not xml doc"}').toLocal8Bit()).object();
1541+// }
1542+
1543+// QByteArray ba = xml.toLocal8Bit();
1544+ QByteArray ba = xml;
1545 char* ch = ba.data();
1546 std::string json = "";
1547 try
1548@@ -30,6 +36,62 @@
1549 return QJsonDocument::fromJson(QString::fromStdString(json).toLocal8Bit()).object();
1550 }
1551
1552+void Utilities::loadFeed(const QString &feedUrl)
1553+{
1554+ _loadTimer->stop();
1555+ connect(_loadTimer, SIGNAL(timeout()), this, SLOT(_internalReplySlot()));
1556+ _loadTimer->start(20000);
1557+ _internalReply = this->_internalMgr->get(QNetworkRequest(QUrl(feedUrl)));
1558+ connect(_internalReply, SIGNAL(finished()), this, SLOT(_internalReplySlot()));
1559+ connect(_internalReply, SIGNAL(sslErrors(QList<QSslError>)),
1560+ this, SLOT(slotSslErrors(QList<QSslError>)));
1561+}
1562+
1563+void Utilities::abort()
1564+{
1565+// qDebug() << "abort0 " ;
1566+ _loadTimer->stop();
1567+ if (this->_internalReply)
1568+ {
1569+// qDebug() << "abort1 " ;
1570+ if (this->_internalReply->isRunning())
1571+ {
1572+ this->_internalReply->abort();
1573+// qDebug() << "abort2 " ;
1574+ }
1575+ }
1576+}
1577+
1578+void Utilities::_internalReplySlot()
1579+{
1580+ abort() ;
1581+ if (_internalReply->error() != QNetworkReply::NoError)
1582+ {
1583+ QString errString = '{"responseDetails": "pls check error in QNetworkReply::NetworkError","responseStatus":'
1584+ + QString::number(_internalReply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt()) + '}';
1585+ emit QJsonDocument::fromJson(errString.toLocal8Bit());
1586+ return ;
1587+ }
1588+ qDebug() << "HTTP status code: " << _internalReply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt() ;
1589+// qDebug() << "redirect url? " << _internalReply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl();
1590+ if (_internalReply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt() == 301)
1591+ {
1592+ loadFeed(_internalReply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl().toString());
1593+ return ;
1594+ }
1595+// qDebug() << "feed size: " << _internalReply->size() ;
1596+// qDebug() << "feed detail: " << _internalReply->readAll() ;
1597+ QByteArray data = _internalReply->readAll();
1598+// emit sigResult(xmlToJson(QString(data)));
1599+ emit sigResult(xmlToJson(data));
1600+// qDebug() << "signal emitted. " ;
1601+}
1602+
1603+void Utilities::slotSslErrors(QList<QSslError>)
1604+{
1605+ this->_internalReply->ignoreSslErrors();
1606+}
1607+
1608 QStringList Utilities::htmlGetImg(const QString &html)
1609 {
1610 QRegExp imgTagRegex("\\<img[^\\>]*src\\s*=\\s*\"([^\"]*)\"[^\\>]*\\>", Qt::CaseInsensitive);
1611@@ -58,11 +120,23 @@
1612 settings.setValue(key, value);
1613 }
1614
1615-// QJsonObject Utilities::test()
1616-// {
1617-// QFile xmlFile("xml");
1618-// xmlFile.open(QIODevice::ReadOnly | QIODevice::Text);
1619-//
1620-// QJsonObject obj = xmlToJson(QString(xmlFile.readAll()));
1621-// return obj;
1622-// }
1623+void Utilities::loadOpml(const QString &opmlUrl)
1624+{
1625+ QString tmpUrl = opmlUrl ;
1626+ tmpUrl = tmpUrl.replace("file://", "");
1627+ QFile *file=new QFile(tmpUrl);
1628+ bool isOpen = file->open(QIODevice::ReadOnly|QIODevice::Text);
1629+ if (!isOpen)
1630+ {
1631+ qDebug() << "error opening opml file ........" ;
1632+ return ;
1633+ }
1634+
1635+ // get all data & convert to json
1636+ QByteArray opmldata = file->readAll();
1637+ QString opmlJsonString = QString(QJsonDocument(xmlToJson(opmldata)).toJson());
1638+ opmlJsonString = opmlJsonString.replace("@", "");
1639+// qDebug() << "after replace @: " << opmlJsonString ;
1640+ //QJsonDocument::fromJson(QString::fromStdString(json).toLocal8Bit()).object();
1641+ emit sigOpmlJsom(QJsonDocument::fromJson(opmlJsonString.toLocal8Bit()).object());
1642+}
1643
1644=== modified file 'shorts/utilities.h'
1645--- shorts/utilities.h 2016-03-04 13:27:57 +0000
1646+++ shorts/utilities.h 2016-06-15 16:13:25 +0000
1647@@ -2,6 +2,7 @@
1648 #define UTILITIES_H
1649
1650 #include <QtCore>
1651+#include <QtNetwork>
1652
1653 class Utilities : public QObject
1654 {
1655@@ -9,20 +10,38 @@
1656 public:
1657 explicit Utilities(QObject *parent = 0);
1658
1659- Q_INVOKABLE QJsonObject xmlToJson(const QString &xml);
1660+ Q_INVOKABLE QJsonObject xmlToJson(const QByteArray &xml);
1661+ // load feed for non-google usage
1662+ Q_INVOKABLE void loadFeed(const QString &feedUrl);
1663+ Q_INVOKABLE void abort();
1664+
1665+ //
1666 Q_INVOKABLE QStringList htmlGetImg(const QString &html);
1667
1668 // get & set settings' values
1669 Q_INVOKABLE QString getSetting(const QString &key);
1670 Q_INVOKABLE void setSetting(const QString &key, const QString &value);
1671
1672+ // load opml file from local
1673+ Q_INVOKABLE void loadOpml(const QString &opmlUrl);
1674+
1675 // test only
1676 // Q_INVOKABLE QJsonObject test();
1677
1678 signals:
1679+ void sigResult(QJsonObject result);
1680+ void sigOpmlJsom(QJsonObject result);
1681
1682 public slots:
1683
1684+private:
1685+ QNetworkAccessManager *_internalMgr;
1686+ QNetworkReply *_internalReply;
1687+ QTimer *_loadTimer;
1688+
1689+private slots:
1690+ void _internalReplySlot();
1691+ void slotSslErrors(QList<QSslError>);
1692 };
1693
1694 #endif // UTILITIES_H
1695
1696=== modified file 'shorts/xml2json/rapidjson/allocators.h'
1697--- shorts/xml2json/rapidjson/allocators.h 2016-03-04 13:27:57 +0000
1698+++ shorts/xml2json/rapidjson/allocators.h 2016-06-15 16:13:25 +0000
1699@@ -194,6 +194,9 @@
1700 if (newSize == 0)
1701 return NULL;
1702
1703+ originalSize = RAPIDJSON_ALIGN(originalSize);
1704+ newSize = RAPIDJSON_ALIGN(newSize);
1705+
1706 // Do not shrink if new size is smaller than original
1707 if (originalSize >= newSize)
1708 return originalPtr;
1709@@ -201,7 +204,6 @@
1710 // Simply expand it if it is the last allocation and there is sufficient space
1711 if (originalPtr == reinterpret_cast<char *>(chunkHead_) + RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + chunkHead_->size - originalSize) {
1712 size_t increment = static_cast<size_t>(newSize - originalSize);
1713- increment = RAPIDJSON_ALIGN(increment);
1714 if (chunkHead_->size + increment <= chunkHead_->capacity) {
1715 chunkHead_->size += increment;
1716 return originalPtr;
1717
1718=== modified file 'shorts/xml2json/rapidjson/document.h'
1719--- shorts/xml2json/rapidjson/document.h 2016-03-04 13:27:57 +0000
1720+++ shorts/xml2json/rapidjson/document.h 2016-06-15 16:13:25 +0000
1721@@ -20,17 +20,21 @@
1722 #include "reader.h"
1723 #include "internal/meta.h"
1724 #include "internal/strfunc.h"
1725+#include "memorystream.h"
1726+#include "encodedstream.h"
1727 #include <new> // placement new
1728
1729 #ifdef _MSC_VER
1730 RAPIDJSON_DIAG_PUSH
1731 RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant
1732+RAPIDJSON_DIAG_OFF(4244) // conversion from kXxxFlags to 'uint16_t', possible loss of data
1733 #endif
1734
1735 #ifdef __clang__
1736 RAPIDJSON_DIAG_PUSH
1737 RAPIDJSON_DIAG_OFF(padded)
1738 RAPIDJSON_DIAG_OFF(switch-enum)
1739+RAPIDJSON_DIAG_OFF(c++98-compat)
1740 #endif
1741
1742 #ifdef __GNUC__
1743@@ -141,6 +145,7 @@
1744 Otherwise, the copy constructor is implicitly defined.
1745 */
1746 GenericMemberIterator(const NonConstIterator & it) : ptr_(it.ptr_) {}
1747+ Iterator& operator=(const NonConstIterator & it) { ptr_ = it.ptr_; return *this; }
1748
1749 //! @name stepping
1750 //@{
1751@@ -293,7 +298,7 @@
1752 */
1753 #endif
1754 explicit GenericStringRef(const CharType* str)
1755- : s(str), length(internal::StrLen(str)){ RAPIDJSON_ASSERT(s != NULL); }
1756+ : s(str), length(internal::StrLen(str)){ RAPIDJSON_ASSERT(s != 0); }
1757
1758 //! Create constant string reference from pointer and length
1759 #ifndef __clang__ // -Wdocumentation
1760@@ -305,7 +310,11 @@
1761 */
1762 #endif
1763 GenericStringRef(const CharType* str, SizeType len)
1764- : s(str), length(len) { RAPIDJSON_ASSERT(s != NULL); }
1765+ : s(str), length(len) { RAPIDJSON_ASSERT(s != 0); }
1766+
1767+ GenericStringRef(const GenericStringRef& rhs) : s(rhs.s), length(rhs.length) {}
1768+
1769+ GenericStringRef& operator=(const GenericStringRef& rhs) { s = rhs.s; length = rhs.length; }
1770
1771 //! implicit conversion to plain CharType pointer
1772 operator const Ch *() const { return s; }
1773@@ -314,8 +323,6 @@
1774 const SizeType length; //!< length of the string (excluding the trailing NULL terminator)
1775
1776 private:
1777- //! Disallow copy-assignment
1778- GenericStringRef operator=(const GenericStringRef&);
1779 //! Disallow construction from non-const array
1780 template<SizeType N>
1781 GenericStringRef(CharType (&str)[N]) /* = delete */;
1782@@ -394,6 +401,127 @@
1783 } // namespace internal
1784
1785 ///////////////////////////////////////////////////////////////////////////////
1786+// TypeHelper
1787+
1788+namespace internal {
1789+
1790+template <typename ValueType, typename T>
1791+struct TypeHelper {};
1792+
1793+template<typename ValueType>
1794+struct TypeHelper<ValueType, bool> {
1795+ static bool Is(const ValueType& v) { return v.IsBool(); }
1796+ static bool Get(const ValueType& v) { return v.GetBool(); }
1797+ static ValueType& Set(ValueType& v, bool data) { return v.SetBool(data); }
1798+ static ValueType& Set(ValueType& v, bool data, typename ValueType::AllocatorType&) { return v.SetBool(data); }
1799+};
1800+
1801+template<typename ValueType>
1802+struct TypeHelper<ValueType, int> {
1803+ static bool Is(const ValueType& v) { return v.IsInt(); }
1804+ static int Get(const ValueType& v) { return v.GetInt(); }
1805+ static ValueType& Set(ValueType& v, int data) { return v.SetInt(data); }
1806+ static ValueType& Set(ValueType& v, int data, typename ValueType::AllocatorType&) { return v.SetInt(data); }
1807+};
1808+
1809+template<typename ValueType>
1810+struct TypeHelper<ValueType, unsigned> {
1811+ static bool Is(const ValueType& v) { return v.IsUint(); }
1812+ static unsigned Get(const ValueType& v) { return v.GetUint(); }
1813+ static ValueType& Set(ValueType& v, unsigned data) { return v.SetUint(data); }
1814+ static ValueType& Set(ValueType& v, unsigned data, typename ValueType::AllocatorType&) { return v.SetUint(data); }
1815+};
1816+
1817+template<typename ValueType>
1818+struct TypeHelper<ValueType, int64_t> {
1819+ static bool Is(const ValueType& v) { return v.IsInt64(); }
1820+ static int64_t Get(const ValueType& v) { return v.GetInt64(); }
1821+ static ValueType& Set(ValueType& v, int64_t data) { return v.SetInt64(data); }
1822+ static ValueType& Set(ValueType& v, int64_t data, typename ValueType::AllocatorType&) { return v.SetInt64(data); }
1823+};
1824+
1825+template<typename ValueType>
1826+struct TypeHelper<ValueType, uint64_t> {
1827+ static bool Is(const ValueType& v) { return v.IsUint64(); }
1828+ static uint64_t Get(const ValueType& v) { return v.GetUint64(); }
1829+ static ValueType& Set(ValueType& v, uint64_t data) { return v.SetUint64(data); }
1830+ static ValueType& Set(ValueType& v, uint64_t data, typename ValueType::AllocatorType&) { return v.SetUint64(data); }
1831+};
1832+
1833+template<typename ValueType>
1834+struct TypeHelper<ValueType, double> {
1835+ static bool Is(const ValueType& v) { return v.IsDouble(); }
1836+ static double Get(const ValueType& v) { return v.GetDouble(); }
1837+ static ValueType& Set(ValueType& v, double data) { return v.SetDouble(data); }
1838+ static ValueType& Set(ValueType& v, double data, typename ValueType::AllocatorType&) { return v.SetDouble(data); }
1839+};
1840+
1841+template<typename ValueType>
1842+struct TypeHelper<ValueType, float> {
1843+ static bool Is(const ValueType& v) { return v.IsFloat(); }
1844+ static float Get(const ValueType& v) { return v.GetFloat(); }
1845+ static ValueType& Set(ValueType& v, float data) { return v.SetFloat(data); }
1846+ static ValueType& Set(ValueType& v, float data, typename ValueType::AllocatorType&) { return v.SetFloat(data); }
1847+};
1848+
1849+template<typename ValueType>
1850+struct TypeHelper<ValueType, const typename ValueType::Ch*> {
1851+ typedef const typename ValueType::Ch* StringType;
1852+ static bool Is(const ValueType& v) { return v.IsString(); }
1853+ static StringType Get(const ValueType& v) { return v.GetString(); }
1854+ static ValueType& Set(ValueType& v, const StringType data) { return v.SetString(typename ValueType::StringRefType(data)); }
1855+ static ValueType& Set(ValueType& v, const StringType data, typename ValueType::AllocatorType& a) { return v.SetString(data, a); }
1856+};
1857+
1858+#if RAPIDJSON_HAS_STDSTRING
1859+template<typename ValueType>
1860+struct TypeHelper<ValueType, std::basic_string<typename ValueType::Ch> > {
1861+ typedef std::basic_string<typename ValueType::Ch> StringType;
1862+ static bool Is(const ValueType& v) { return v.IsString(); }
1863+ static StringType Get(const ValueType& v) { return v.GetString(); }
1864+ static ValueType& Set(ValueType& v, const StringType& data, typename ValueType::AllocatorType& a) { return v.SetString(data, a); }
1865+};
1866+#endif
1867+
1868+template<typename ValueType>
1869+struct TypeHelper<ValueType, typename ValueType::Array> {
1870+ typedef typename ValueType::Array ArrayType;
1871+ static bool Is(const ValueType& v) { return v.IsArray(); }
1872+ static ArrayType Get(ValueType& v) { return v.GetArray(); }
1873+ static ValueType& Set(ValueType& v, ArrayType data) { return v = data; }
1874+ static ValueType& Set(ValueType& v, ArrayType data, typename ValueType::AllocatorType&) { return v = data; }
1875+};
1876+
1877+template<typename ValueType>
1878+struct TypeHelper<ValueType, typename ValueType::ConstArray> {
1879+ typedef typename ValueType::ConstArray ArrayType;
1880+ static bool Is(const ValueType& v) { return v.IsArray(); }
1881+ static ArrayType Get(const ValueType& v) { return v.GetArray(); }
1882+};
1883+
1884+template<typename ValueType>
1885+struct TypeHelper<ValueType, typename ValueType::Object> {
1886+ typedef typename ValueType::Object ObjectType;
1887+ static bool Is(const ValueType& v) { return v.IsObject(); }
1888+ static ObjectType Get(ValueType& v) { return v.GetObject(); }
1889+ static ValueType& Set(ValueType& v, ObjectType data) { return v = data; }
1890+ static ValueType& Set(ValueType& v, ObjectType data, typename ValueType::AllocatorType&) { v = data; }
1891+};
1892+
1893+template<typename ValueType>
1894+struct TypeHelper<ValueType, typename ValueType::ConstObject> {
1895+ typedef typename ValueType::ConstObject ObjectType;
1896+ static bool Is(const ValueType& v) { return v.IsObject(); }
1897+ static ObjectType Get(const ValueType& v) { return v.GetObject(); }
1898+};
1899+
1900+} // namespace internal
1901+
1902+// Forward declarations
1903+template <bool, typename> class GenericArray;
1904+template <bool, typename> class GenericObject;
1905+
1906+///////////////////////////////////////////////////////////////////////////////
1907 // GenericValue
1908
1909 //! Represents a JSON value. Use Value for UTF8 encoding and default allocator.
1910@@ -420,17 +548,21 @@
1911 typedef GenericValue* ValueIterator; //!< Value iterator for iterating in array.
1912 typedef const GenericValue* ConstValueIterator; //!< Constant value iterator for iterating in array.
1913 typedef GenericValue<Encoding, Allocator> ValueType; //!< Value type of itself.
1914+ typedef GenericArray<false, ValueType> Array;
1915+ typedef GenericArray<true, ValueType> ConstArray;
1916+ typedef GenericObject<false, ValueType> Object;
1917+ typedef GenericObject<true, ValueType> ConstObject;
1918
1919 //!@name Constructors and destructor.
1920 //@{
1921
1922 //! Default constructor creates a null value.
1923- GenericValue() RAPIDJSON_NOEXCEPT : data_(), flags_(kNullFlag) {}
1924+ GenericValue() RAPIDJSON_NOEXCEPT : data_() { data_.f.flags = kNullFlag; }
1925
1926 #if RAPIDJSON_HAS_CXX11_RVALUE_REFS
1927 //! Move constructor in C++11
1928- GenericValue(GenericValue&& rhs) RAPIDJSON_NOEXCEPT : data_(rhs.data_), flags_(rhs.flags_) {
1929- rhs.flags_ = kNullFlag; // give up contents
1930+ GenericValue(GenericValue&& rhs) RAPIDJSON_NOEXCEPT : data_(rhs.data_) {
1931+ rhs.data_.f.flags = kNullFlag; // give up contents
1932 }
1933 #endif
1934
1935@@ -455,13 +587,13 @@
1936 \param type Type of the value.
1937 \note Default content for number is zero.
1938 */
1939- explicit GenericValue(Type type) RAPIDJSON_NOEXCEPT : data_(), flags_() {
1940- static const unsigned defaultFlags[7] = {
1941+ explicit GenericValue(Type type) RAPIDJSON_NOEXCEPT : data_() {
1942+ static const uint16_t defaultFlags[7] = {
1943 kNullFlag, kFalseFlag, kTrueFlag, kObjectFlag, kArrayFlag, kShortStringFlag,
1944 kNumberAnyFlag
1945 };
1946 RAPIDJSON_ASSERT(type <= kNumberType);
1947- flags_ = defaultFlags[type];
1948+ data_.f.flags = defaultFlags[type];
1949
1950 // Use ShortString to store empty string.
1951 if (type == kStringType)
1952@@ -486,96 +618,122 @@
1953 */
1954 #ifndef RAPIDJSON_DOXYGEN_RUNNING // hide SFINAE from Doxygen
1955 template <typename T>
1956- explicit GenericValue(T b, RAPIDJSON_ENABLEIF((internal::IsSame<T,bool>))) RAPIDJSON_NOEXCEPT
1957+ explicit GenericValue(T b, RAPIDJSON_ENABLEIF((internal::IsSame<bool, T>))) RAPIDJSON_NOEXCEPT // See #472
1958 #else
1959 explicit GenericValue(bool b) RAPIDJSON_NOEXCEPT
1960 #endif
1961- : data_(), flags_(b ? kTrueFlag : kFalseFlag) {
1962+ : data_() {
1963 // safe-guard against failing SFINAE
1964 RAPIDJSON_STATIC_ASSERT((internal::IsSame<bool,T>::Value));
1965+ data_.f.flags = b ? kTrueFlag : kFalseFlag;
1966 }
1967
1968 //! Constructor for int value.
1969- explicit GenericValue(int i) RAPIDJSON_NOEXCEPT : data_(), flags_(kNumberIntFlag) {
1970+ explicit GenericValue(int i) RAPIDJSON_NOEXCEPT : data_() {
1971 data_.n.i64 = i;
1972- if (i >= 0)
1973- flags_ |= kUintFlag | kUint64Flag;
1974+ data_.f.flags = (i >= 0) ? (kNumberIntFlag | kUintFlag | kUint64Flag) : kNumberIntFlag;
1975 }
1976
1977 //! Constructor for unsigned value.
1978- explicit GenericValue(unsigned u) RAPIDJSON_NOEXCEPT : data_(), flags_(kNumberUintFlag) {
1979+ explicit GenericValue(unsigned u) RAPIDJSON_NOEXCEPT : data_() {
1980 data_.n.u64 = u;
1981- if (!(u & 0x80000000))
1982- flags_ |= kIntFlag | kInt64Flag;
1983+ data_.f.flags = (u & 0x80000000) ? kNumberUintFlag : (kNumberUintFlag | kIntFlag | kInt64Flag);
1984 }
1985
1986 //! Constructor for int64_t value.
1987- explicit GenericValue(int64_t i64) RAPIDJSON_NOEXCEPT : data_(), flags_(kNumberInt64Flag) {
1988+ explicit GenericValue(int64_t i64) RAPIDJSON_NOEXCEPT : data_() {
1989 data_.n.i64 = i64;
1990+ data_.f.flags = kNumberInt64Flag;
1991 if (i64 >= 0) {
1992- flags_ |= kNumberUint64Flag;
1993+ data_.f.flags |= kNumberUint64Flag;
1994 if (!(static_cast<uint64_t>(i64) & RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x00000000)))
1995- flags_ |= kUintFlag;
1996+ data_.f.flags |= kUintFlag;
1997 if (!(static_cast<uint64_t>(i64) & RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x80000000)))
1998- flags_ |= kIntFlag;
1999+ data_.f.flags |= kIntFlag;
2000 }
2001 else if (i64 >= static_cast<int64_t>(RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x80000000)))
2002- flags_ |= kIntFlag;
2003+ data_.f.flags |= kIntFlag;
2004 }
2005
2006 //! Constructor for uint64_t value.
2007- explicit GenericValue(uint64_t u64) RAPIDJSON_NOEXCEPT : data_(), flags_(kNumberUint64Flag) {
2008+ explicit GenericValue(uint64_t u64) RAPIDJSON_NOEXCEPT : data_() {
2009 data_.n.u64 = u64;
2010+ data_.f.flags = kNumberUint64Flag;
2011 if (!(u64 & RAPIDJSON_UINT64_C2(0x80000000, 0x00000000)))
2012- flags_ |= kInt64Flag;
2013+ data_.f.flags |= kInt64Flag;
2014 if (!(u64 & RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x00000000)))
2015- flags_ |= kUintFlag;
2016+ data_.f.flags |= kUintFlag;
2017 if (!(u64 & RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x80000000)))
2018- flags_ |= kIntFlag;
2019+ data_.f.flags |= kIntFlag;
2020 }
2021
2022 //! Constructor for double value.
2023- explicit GenericValue(double d) RAPIDJSON_NOEXCEPT : data_(), flags_(kNumberDoubleFlag) { data_.n.d = d; }
2024-
2025- //! Constructor for constant string (i.e. do not make a copy of string)
2026- GenericValue(const Ch* s, SizeType length) RAPIDJSON_NOEXCEPT : data_(), flags_() { SetStringRaw(StringRef(s, length)); }
2027-
2028- //! Constructor for constant string (i.e. do not make a copy of string)
2029- explicit GenericValue(StringRefType s) RAPIDJSON_NOEXCEPT : data_(), flags_() { SetStringRaw(s); }
2030-
2031- //! Constructor for copy-string (i.e. do make a copy of string)
2032- GenericValue(const Ch* s, SizeType length, Allocator& allocator) : data_(), flags_() { SetStringRaw(StringRef(s, length), allocator); }
2033-
2034- //! Constructor for copy-string (i.e. do make a copy of string)
2035- GenericValue(const Ch*s, Allocator& allocator) : data_(), flags_() { SetStringRaw(StringRef(s), allocator); }
2036+ explicit GenericValue(double d) RAPIDJSON_NOEXCEPT : data_() { data_.n.d = d; data_.f.flags = kNumberDoubleFlag; }
2037+
2038+ //! Constructor for constant string (i.e. do not make a copy of string)
2039+ GenericValue(const Ch* s, SizeType length) RAPIDJSON_NOEXCEPT : data_() { SetStringRaw(StringRef(s, length)); }
2040+
2041+ //! Constructor for constant string (i.e. do not make a copy of string)
2042+ explicit GenericValue(StringRefType s) RAPIDJSON_NOEXCEPT : data_() { SetStringRaw(s); }
2043+
2044+ //! Constructor for copy-string (i.e. do make a copy of string)
2045+ GenericValue(const Ch* s, SizeType length, Allocator& allocator) : data_() { SetStringRaw(StringRef(s, length), allocator); }
2046+
2047+ //! Constructor for copy-string (i.e. do make a copy of string)
2048+ GenericValue(const Ch*s, Allocator& allocator) : data_() { SetStringRaw(StringRef(s), allocator); }
2049
2050 #if RAPIDJSON_HAS_STDSTRING
2051 //! Constructor for copy-string from a string object (i.e. do make a copy of string)
2052 /*! \note Requires the definition of the preprocessor symbol \ref RAPIDJSON_HAS_STDSTRING.
2053 */
2054- GenericValue(const std::basic_string<Ch>& s, Allocator& allocator) : data_(), flags_() { SetStringRaw(StringRef(s), allocator); }
2055+ GenericValue(const std::basic_string<Ch>& s, Allocator& allocator) : data_() { SetStringRaw(StringRef(s), allocator); }
2056 #endif
2057
2058+ //! Constructor for Array.
2059+ /*!
2060+ \param a An array obtained by \c GetArray().
2061+ \note \c Array is always pass-by-value.
2062+ \note the source array is moved into this value and the sourec array becomes empty.
2063+ */
2064+ GenericValue(Array a) RAPIDJSON_NOEXCEPT : data_(a.value_.data_) {
2065+ a.value_.data_ = Data();
2066+ a.value_.data_.f.flags = kArrayFlag;
2067+ }
2068+
2069+ //! Constructor for Object.
2070+ /*!
2071+ \param o An object obtained by \c GetObject().
2072+ \note \c Object is always pass-by-value.
2073+ \note the source object is moved into this value and the sourec object becomes empty.
2074+ */
2075+ GenericValue(Object o) RAPIDJSON_NOEXCEPT : data_(o.value_.data_) {
2076+ o.value_.data_ = Data();
2077+ o.value_.data_.f.flags = kObjectFlag;
2078+ }
2079+
2080 //! Destructor.
2081 /*! Need to destruct elements of array, members of object, or copy-string.
2082 */
2083 ~GenericValue() {
2084 if (Allocator::kNeedFree) { // Shortcut by Allocator's trait
2085- switch(flags_) {
2086+ switch(data_.f.flags) {
2087 case kArrayFlag:
2088- for (GenericValue* v = data_.a.elements; v != data_.a.elements + data_.a.size; ++v)
2089- v->~GenericValue();
2090- Allocator::Free(data_.a.elements);
2091+ {
2092+ GenericValue* e = GetElementsPointer();
2093+ for (GenericValue* v = e; v != e + data_.a.size; ++v)
2094+ v->~GenericValue();
2095+ Allocator::Free(e);
2096+ }
2097 break;
2098
2099 case kObjectFlag:
2100 for (MemberIterator m = MemberBegin(); m != MemberEnd(); ++m)
2101 m->~Member();
2102- Allocator::Free(data_.o.members);
2103+ Allocator::Free(GetMembersPointer());
2104 break;
2105
2106 case kCopyStringFlag:
2107- Allocator::Free(const_cast<Ch*>(data_.s.str));
2108+ Allocator::Free(const_cast<Ch*>(GetStringPointer()));
2109 break;
2110
2111 default:
2112@@ -773,20 +931,51 @@
2113 //!@name Type
2114 //@{
2115
2116- Type GetType() const { return static_cast<Type>(flags_ & kTypeMask); }
2117- bool IsNull() const { return flags_ == kNullFlag; }
2118- bool IsFalse() const { return flags_ == kFalseFlag; }
2119- bool IsTrue() const { return flags_ == kTrueFlag; }
2120- bool IsBool() const { return (flags_ & kBoolFlag) != 0; }
2121- bool IsObject() const { return flags_ == kObjectFlag; }
2122- bool IsArray() const { return flags_ == kArrayFlag; }
2123- bool IsNumber() const { return (flags_ & kNumberFlag) != 0; }
2124- bool IsInt() const { return (flags_ & kIntFlag) != 0; }
2125- bool IsUint() const { return (flags_ & kUintFlag) != 0; }
2126- bool IsInt64() const { return (flags_ & kInt64Flag) != 0; }
2127- bool IsUint64() const { return (flags_ & kUint64Flag) != 0; }
2128- bool IsDouble() const { return (flags_ & kDoubleFlag) != 0; }
2129- bool IsString() const { return (flags_ & kStringFlag) != 0; }
2130+ Type GetType() const { return static_cast<Type>(data_.f.flags & kTypeMask); }
2131+ bool IsNull() const { return data_.f.flags == kNullFlag; }
2132+ bool IsFalse() const { return data_.f.flags == kFalseFlag; }
2133+ bool IsTrue() const { return data_.f.flags == kTrueFlag; }
2134+ bool IsBool() const { return (data_.f.flags & kBoolFlag) != 0; }
2135+ bool IsObject() const { return data_.f.flags == kObjectFlag; }
2136+ bool IsArray() const { return data_.f.flags == kArrayFlag; }
2137+ bool IsNumber() const { return (data_.f.flags & kNumberFlag) != 0; }
2138+ bool IsInt() const { return (data_.f.flags & kIntFlag) != 0; }
2139+ bool IsUint() const { return (data_.f.flags & kUintFlag) != 0; }
2140+ bool IsInt64() const { return (data_.f.flags & kInt64Flag) != 0; }
2141+ bool IsUint64() const { return (data_.f.flags & kUint64Flag) != 0; }
2142+ bool IsDouble() const { return (data_.f.flags & kDoubleFlag) != 0; }
2143+ bool IsString() const { return (data_.f.flags & kStringFlag) != 0; }
2144+
2145+ // Checks whether a number can be losslessly converted to a double.
2146+ bool IsLosslessDouble() const {
2147+ if (!IsNumber()) return false;
2148+ if (IsUint64()) {
2149+ uint64_t u = GetUint64();
2150+ volatile double d = static_cast<double>(u);
2151+ return static_cast<uint64_t>(d) == u;
2152+ }
2153+ if (IsInt64()) {
2154+ int64_t i = GetInt64();
2155+ volatile double d = static_cast<double>(i);
2156+ return static_cast< int64_t>(d) == i;
2157+ }
2158+ return true; // double, int, uint are always lossless
2159+ }
2160+
2161+ // Checks whether a number is a float (possible lossy).
2162+ bool IsFloat() const {
2163+ if ((data_.f.flags & kDoubleFlag) == 0)
2164+ return false;
2165+ double d = GetDouble();
2166+ return d >= -3.4028234e38 && d <= 3.4028234e38;
2167+ }
2168+ // Checks whether a number can be losslessly converted to a float.
2169+ bool IsLosslessFloat() const {
2170+ if (!IsNumber()) return false;
2171+ double a = GetDouble();
2172+ double b = static_cast<double>(static_cast<float>(a));
2173+ return a >= b && a <= b; // Prevent -Wfloat-equal
2174+ }
2175
2176 //@}
2177
2178@@ -800,7 +989,7 @@
2179 //!@name Bool
2180 //@{
2181
2182- bool GetBool() const { RAPIDJSON_ASSERT(IsBool()); return flags_ == kTrueFlag; }
2183+ bool GetBool() const { RAPIDJSON_ASSERT(IsBool()); return data_.f.flags == kTrueFlag; }
2184 //!< Set boolean value
2185 /*! \post IsBool() == true */
2186 GenericValue& SetBool(bool b) { this->~GenericValue(); new (this) GenericValue(b); return *this; }
2187@@ -874,16 +1063,16 @@
2188
2189 //! Const member iterator
2190 /*! \pre IsObject() == true */
2191- ConstMemberIterator MemberBegin() const { RAPIDJSON_ASSERT(IsObject()); return ConstMemberIterator(data_.o.members); }
2192+ ConstMemberIterator MemberBegin() const { RAPIDJSON_ASSERT(IsObject()); return ConstMemberIterator(GetMembersPointer()); }
2193 //! Const \em past-the-end member iterator
2194 /*! \pre IsObject() == true */
2195- ConstMemberIterator MemberEnd() const { RAPIDJSON_ASSERT(IsObject()); return ConstMemberIterator(data_.o.members + data_.o.size); }
2196+ ConstMemberIterator MemberEnd() const { RAPIDJSON_ASSERT(IsObject()); return ConstMemberIterator(GetMembersPointer() + data_.o.size); }
2197 //! Member iterator
2198 /*! \pre IsObject() == true */
2199- MemberIterator MemberBegin() { RAPIDJSON_ASSERT(IsObject()); return MemberIterator(data_.o.members); }
2200+ MemberIterator MemberBegin() { RAPIDJSON_ASSERT(IsObject()); return MemberIterator(GetMembersPointer()); }
2201 //! \em Past-the-end member iterator
2202 /*! \pre IsObject() == true */
2203- MemberIterator MemberEnd() { RAPIDJSON_ASSERT(IsObject()); return MemberIterator(data_.o.members + data_.o.size); }
2204+ MemberIterator MemberEnd() { RAPIDJSON_ASSERT(IsObject()); return MemberIterator(GetMembersPointer() + data_.o.size); }
2205
2206 //! Check whether a member exists in the object.
2207 /*!
2208@@ -989,20 +1178,21 @@
2209 RAPIDJSON_ASSERT(IsObject());
2210 RAPIDJSON_ASSERT(name.IsString());
2211
2212- Object& o = data_.o;
2213+ ObjectData& o = data_.o;
2214 if (o.size >= o.capacity) {
2215 if (o.capacity == 0) {
2216 o.capacity = kDefaultObjectCapacity;
2217- o.members = reinterpret_cast<Member*>(allocator.Malloc(o.capacity * sizeof(Member)));
2218+ SetMembersPointer(reinterpret_cast<Member*>(allocator.Malloc(o.capacity * sizeof(Member))));
2219 }
2220 else {
2221 SizeType oldCapacity = o.capacity;
2222 o.capacity += (oldCapacity + 1) / 2; // grow by factor 1.5
2223- o.members = reinterpret_cast<Member*>(allocator.Realloc(o.members, oldCapacity * sizeof(Member), o.capacity * sizeof(Member)));
2224+ SetMembersPointer(reinterpret_cast<Member*>(allocator.Realloc(GetMembersPointer(), oldCapacity * sizeof(Member), o.capacity * sizeof(Member))));
2225 }
2226 }
2227- o.members[o.size].name.RawAssign(name);
2228- o.members[o.size].value.RawAssign(value);
2229+ Member* members = GetMembersPointer();
2230+ members[o.size].name.RawAssign(name);
2231+ members[o.size].value.RawAssign(value);
2232 o.size++;
2233 return *this;
2234 }
2235@@ -1181,18 +1371,14 @@
2236 MemberIterator RemoveMember(MemberIterator m) {
2237 RAPIDJSON_ASSERT(IsObject());
2238 RAPIDJSON_ASSERT(data_.o.size > 0);
2239- RAPIDJSON_ASSERT(data_.o.members != 0);
2240+ RAPIDJSON_ASSERT(GetMembersPointer() != 0);
2241 RAPIDJSON_ASSERT(m >= MemberBegin() && m < MemberEnd());
2242
2243- MemberIterator last(data_.o.members + (data_.o.size - 1));
2244- if (data_.o.size > 1 && m != last) {
2245- // Move the last one to this place
2246- *m = *last;
2247- }
2248- else {
2249- // Only one left, just destroy
2250- m->~Member();
2251- }
2252+ MemberIterator last(GetMembersPointer() + (data_.o.size - 1));
2253+ if (data_.o.size > 1 && m != last)
2254+ *m = *last; // Move the last one to this place
2255+ else
2256+ m->~Member(); // Only one left, just destroy
2257 --data_.o.size;
2258 return m;
2259 }
2260@@ -1222,7 +1408,7 @@
2261 MemberIterator EraseMember(ConstMemberIterator first, ConstMemberIterator last) {
2262 RAPIDJSON_ASSERT(IsObject());
2263 RAPIDJSON_ASSERT(data_.o.size > 0);
2264- RAPIDJSON_ASSERT(data_.o.members != 0);
2265+ RAPIDJSON_ASSERT(GetMembersPointer() != 0);
2266 RAPIDJSON_ASSERT(first >= MemberBegin());
2267 RAPIDJSON_ASSERT(first <= last);
2268 RAPIDJSON_ASSERT(last <= MemberEnd());
2269@@ -1260,6 +1446,9 @@
2270 return false;
2271 }
2272
2273+ Object GetObject() { RAPIDJSON_ASSERT(IsObject()); return Object(*this); }
2274+ ConstObject GetObject() const { RAPIDJSON_ASSERT(IsObject()); return ConstObject(*this); }
2275+
2276 //@}
2277
2278 //!@name Array
2279@@ -1267,7 +1456,7 @@
2280
2281 //! Set this value as an empty array.
2282 /*! \post IsArray == true */
2283- GenericValue& SetArray() { this->~GenericValue(); new (this) GenericValue(kArrayType); return *this; }
2284+ GenericValue& SetArray() { this->~GenericValue(); new (this) GenericValue(kArrayType); return *this; }
2285
2286 //! Get the number of elements in array.
2287 SizeType Size() const { RAPIDJSON_ASSERT(IsArray()); return data_.a.size; }
2288@@ -1284,8 +1473,9 @@
2289 */
2290 void Clear() {
2291 RAPIDJSON_ASSERT(IsArray());
2292- for (SizeType i = 0; i < data_.a.size; ++i)
2293- data_.a.elements[i].~GenericValue();
2294+ GenericValue* e = GetElementsPointer();
2295+ for (GenericValue* v = e; v != e + data_.a.size; ++v)
2296+ v->~GenericValue();
2297 data_.a.size = 0;
2298 }
2299
2300@@ -1297,16 +1487,16 @@
2301 GenericValue& operator[](SizeType index) {
2302 RAPIDJSON_ASSERT(IsArray());
2303 RAPIDJSON_ASSERT(index < data_.a.size);
2304- return data_.a.elements[index];
2305+ return GetElementsPointer()[index];
2306 }
2307 const GenericValue& operator[](SizeType index) const { return const_cast<GenericValue&>(*this)[index]; }
2308
2309 //! Element iterator
2310 /*! \pre IsArray() == true */
2311- ValueIterator Begin() { RAPIDJSON_ASSERT(IsArray()); return data_.a.elements; }
2312+ ValueIterator Begin() { RAPIDJSON_ASSERT(IsArray()); return GetElementsPointer(); }
2313 //! \em Past-the-end element iterator
2314 /*! \pre IsArray() == true */
2315- ValueIterator End() { RAPIDJSON_ASSERT(IsArray()); return data_.a.elements + data_.a.size; }
2316+ ValueIterator End() { RAPIDJSON_ASSERT(IsArray()); return GetElementsPointer() + data_.a.size; }
2317 //! Constant element iterator
2318 /*! \pre IsArray() == true */
2319 ConstValueIterator Begin() const { return const_cast<GenericValue&>(*this).Begin(); }
2320@@ -1323,7 +1513,7 @@
2321 GenericValue& Reserve(SizeType newCapacity, Allocator &allocator) {
2322 RAPIDJSON_ASSERT(IsArray());
2323 if (newCapacity > data_.a.capacity) {
2324- data_.a.elements = static_cast<GenericValue*>(allocator.Realloc(data_.a.elements, data_.a.capacity * sizeof(GenericValue), newCapacity * sizeof(GenericValue)));
2325+ SetElementsPointer(reinterpret_cast<GenericValue*>(allocator.Realloc(GetElementsPointer(), data_.a.capacity * sizeof(GenericValue), newCapacity * sizeof(GenericValue))));
2326 data_.a.capacity = newCapacity;
2327 }
2328 return *this;
2329@@ -1343,7 +1533,7 @@
2330 RAPIDJSON_ASSERT(IsArray());
2331 if (data_.a.size >= data_.a.capacity)
2332 Reserve(data_.a.capacity == 0 ? kDefaultArrayCapacity : (data_.a.capacity + (data_.a.capacity + 1) / 2), allocator);
2333- data_.a.elements[data_.a.size++].RawAssign(value);
2334+ GetElementsPointer()[data_.a.size++].RawAssign(value);
2335 return *this;
2336 }
2337
2338@@ -1397,7 +1587,7 @@
2339 GenericValue& PopBack() {
2340 RAPIDJSON_ASSERT(IsArray());
2341 RAPIDJSON_ASSERT(!Empty());
2342- data_.a.elements[--data_.a.size].~GenericValue();
2343+ GetElementsPointer()[--data_.a.size].~GenericValue();
2344 return *this;
2345 }
2346
2347@@ -1423,7 +1613,7 @@
2348 ValueIterator Erase(ConstValueIterator first, ConstValueIterator last) {
2349 RAPIDJSON_ASSERT(IsArray());
2350 RAPIDJSON_ASSERT(data_.a.size > 0);
2351- RAPIDJSON_ASSERT(data_.a.elements != 0);
2352+ RAPIDJSON_ASSERT(GetElementsPointer() != 0);
2353 RAPIDJSON_ASSERT(first >= Begin());
2354 RAPIDJSON_ASSERT(first <= last);
2355 RAPIDJSON_ASSERT(last <= End());
2356@@ -1435,23 +1625,36 @@
2357 return pos;
2358 }
2359
2360+ Array GetArray() { RAPIDJSON_ASSERT(IsArray()); return Array(*this); }
2361+ ConstArray GetArray() const { RAPIDJSON_ASSERT(IsArray()); return ConstArray(*this); }
2362+
2363 //@}
2364
2365 //!@name Number
2366 //@{
2367
2368- int GetInt() const { RAPIDJSON_ASSERT(flags_ & kIntFlag); return data_.n.i.i; }
2369- unsigned GetUint() const { RAPIDJSON_ASSERT(flags_ & kUintFlag); return data_.n.u.u; }
2370- int64_t GetInt64() const { RAPIDJSON_ASSERT(flags_ & kInt64Flag); return data_.n.i64; }
2371- uint64_t GetUint64() const { RAPIDJSON_ASSERT(flags_ & kUint64Flag); return data_.n.u64; }
2372+ int GetInt() const { RAPIDJSON_ASSERT(data_.f.flags & kIntFlag); return data_.n.i.i; }
2373+ unsigned GetUint() const { RAPIDJSON_ASSERT(data_.f.flags & kUintFlag); return data_.n.u.u; }
2374+ int64_t GetInt64() const { RAPIDJSON_ASSERT(data_.f.flags & kInt64Flag); return data_.n.i64; }
2375+ uint64_t GetUint64() const { RAPIDJSON_ASSERT(data_.f.flags & kUint64Flag); return data_.n.u64; }
2376
2377+ //! Get the value as double type.
2378+ /*! \note If the value is 64-bit integer type, it may lose precision. Use \c IsLosslessDouble() to check whether the converison is lossless.
2379+ */
2380 double GetDouble() const {
2381 RAPIDJSON_ASSERT(IsNumber());
2382- if ((flags_ & kDoubleFlag) != 0) return data_.n.d; // exact type, no conversion.
2383- if ((flags_ & kIntFlag) != 0) return data_.n.i.i; // int -> double
2384- if ((flags_ & kUintFlag) != 0) return data_.n.u.u; // unsigned -> double
2385- if ((flags_ & kInt64Flag) != 0) return static_cast<double>(data_.n.i64); // int64_t -> double (may lose precision)
2386- RAPIDJSON_ASSERT((flags_ & kUint64Flag) != 0); return static_cast<double>(data_.n.u64); // uint64_t -> double (may lose precision)
2387+ if ((data_.f.flags & kDoubleFlag) != 0) return data_.n.d; // exact type, no conversion.
2388+ if ((data_.f.flags & kIntFlag) != 0) return data_.n.i.i; // int -> double
2389+ if ((data_.f.flags & kUintFlag) != 0) return data_.n.u.u; // unsigned -> double
2390+ if ((data_.f.flags & kInt64Flag) != 0) return static_cast<double>(data_.n.i64); // int64_t -> double (may lose precision)
2391+ RAPIDJSON_ASSERT((data_.f.flags & kUint64Flag) != 0); return static_cast<double>(data_.n.u64); // uint64_t -> double (may lose precision)
2392+ }
2393+
2394+ //! Get the value as float type.
2395+ /*! \note If the value is 64-bit integer type, it may lose precision. Use \c IsLosslessFloat() to check whether the converison is lossless.
2396+ */
2397+ float GetFloat() const {
2398+ return static_cast<float>(GetDouble());
2399 }
2400
2401 GenericValue& SetInt(int i) { this->~GenericValue(); new (this) GenericValue(i); return *this; }
2402@@ -1459,18 +1662,19 @@
2403 GenericValue& SetInt64(int64_t i64) { this->~GenericValue(); new (this) GenericValue(i64); return *this; }
2404 GenericValue& SetUint64(uint64_t u64) { this->~GenericValue(); new (this) GenericValue(u64); return *this; }
2405 GenericValue& SetDouble(double d) { this->~GenericValue(); new (this) GenericValue(d); return *this; }
2406+ GenericValue& SetFloat(float f) { this->~GenericValue(); new (this) GenericValue(f); return *this; }
2407
2408 //@}
2409
2410 //!@name String
2411 //@{
2412
2413- const Ch* GetString() const { RAPIDJSON_ASSERT(IsString()); return ((flags_ & kInlineStrFlag) ? data_.ss.str : data_.s.str); }
2414+ const Ch* GetString() const { RAPIDJSON_ASSERT(IsString()); return (data_.f.flags & kInlineStrFlag) ? data_.ss.str : GetStringPointer(); }
2415
2416 //! Get the length of string.
2417 /*! Since rapidjson permits "\\u0000" in the json string, strlen(v.GetString()) may not equal to v.GetStringLength().
2418 */
2419- SizeType GetStringLength() const { RAPIDJSON_ASSERT(IsString()); return ((flags_ & kInlineStrFlag) ? (data_.ss.GetLength()) : data_.s.length); }
2420+ SizeType GetStringLength() const { RAPIDJSON_ASSERT(IsString()); return ((data_.f.flags & kInlineStrFlag) ? (data_.ss.GetLength()) : data_.s.length); }
2421
2422 //! Set this value as a string without copying source string.
2423 /*! This version has better performance with supplied length, and also support string containing null character.
2424@@ -1520,6 +1724,30 @@
2425
2426 //@}
2427
2428+ //!@name Array
2429+ //@{
2430+
2431+ //! Templated version for checking whether this value is type T.
2432+ /*!
2433+ \tparam T Either \c bool, \c int, \c unsigned, \c int64_t, \c uint64_t, \c double, \c float, \c const \c char*, \c std::basic_string<Ch>
2434+ */
2435+ template <typename T>
2436+ bool Is() const { return internal::TypeHelper<ValueType, T>::Is(*this); }
2437+
2438+ template <typename T>
2439+ T Get() const { return internal::TypeHelper<ValueType, T>::Get(*this); }
2440+
2441+ template <typename T>
2442+ T Get() { return internal::TypeHelper<ValueType, T>::Get(*this); }
2443+
2444+ template<typename T>
2445+ ValueType& Set(const T& data) { return internal::TypeHelper<ValueType, T>::Set(*this, data); }
2446+
2447+ template<typename T>
2448+ ValueType& Set(const T& data, AllocatorType& allocator) { return internal::TypeHelper<ValueType, T>::Set(*this, data, allocator); }
2449+
2450+ //@}
2451+
2452 //! Generate events of this value to a Handler.
2453 /*! This function adopts the GoF visitor pattern.
2454 Typical usage is to output this JSON value as JSON text via Writer, which is a Handler.
2455@@ -1535,35 +1763,35 @@
2456 case kTrueType: return handler.Bool(true);
2457
2458 case kObjectType:
2459- if (!handler.StartObject())
2460+ if (RAPIDJSON_UNLIKELY(!handler.StartObject()))
2461 return false;
2462 for (ConstMemberIterator m = MemberBegin(); m != MemberEnd(); ++m) {
2463 RAPIDJSON_ASSERT(m->name.IsString()); // User may change the type of name by MemberIterator.
2464- if (!handler.Key(m->name.GetString(), m->name.GetStringLength(), (m->name.flags_ & kCopyFlag) != 0))
2465+ if (RAPIDJSON_UNLIKELY(!handler.Key(m->name.GetString(), m->name.GetStringLength(), (m->name.data_.f.flags & kCopyFlag) != 0)))
2466 return false;
2467- if (!m->value.Accept(handler))
2468+ if (RAPIDJSON_UNLIKELY(!m->value.Accept(handler)))
2469 return false;
2470 }
2471 return handler.EndObject(data_.o.size);
2472
2473 case kArrayType:
2474- if (!handler.StartArray())
2475+ if (RAPIDJSON_UNLIKELY(!handler.StartArray()))
2476 return false;
2477- for (GenericValue* v = data_.a.elements; v != data_.a.elements + data_.a.size; ++v)
2478- if (!v->Accept(handler))
2479+ for (const GenericValue* v = Begin(); v != End(); ++v)
2480+ if (RAPIDJSON_UNLIKELY(!v->Accept(handler)))
2481 return false;
2482 return handler.EndArray(data_.a.size);
2483
2484 case kStringType:
2485- return handler.String(GetString(), GetStringLength(), (flags_ & kCopyFlag) != 0);
2486+ return handler.String(GetString(), GetStringLength(), (data_.f.flags & kCopyFlag) != 0);
2487
2488 default:
2489 RAPIDJSON_ASSERT(GetType() == kNumberType);
2490- if (IsInt()) return handler.Int(data_.n.i.i);
2491+ if (IsDouble()) return handler.Double(data_.n.d);
2492+ else if (IsInt()) return handler.Int(data_.n.i.i);
2493 else if (IsUint()) return handler.Uint(data_.n.u.u);
2494 else if (IsInt64()) return handler.Int64(data_.n.i64);
2495- else if (IsUint64()) return handler.Uint64(data_.n.u64);
2496- else return handler.Double(data_.n.d);
2497+ else return handler.Uint64(data_.n.u64);
2498 }
2499 }
2500
2501@@ -1572,16 +1800,16 @@
2502 template <typename, typename, typename> friend class GenericDocument;
2503
2504 enum {
2505- kBoolFlag = 0x100,
2506- kNumberFlag = 0x200,
2507- kIntFlag = 0x400,
2508- kUintFlag = 0x800,
2509- kInt64Flag = 0x1000,
2510- kUint64Flag = 0x2000,
2511- kDoubleFlag = 0x4000,
2512- kStringFlag = 0x100000,
2513- kCopyFlag = 0x200000,
2514- kInlineStrFlag = 0x400000,
2515+ kBoolFlag = 0x0008,
2516+ kNumberFlag = 0x0010,
2517+ kIntFlag = 0x0020,
2518+ kUintFlag = 0x0040,
2519+ kInt64Flag = 0x0080,
2520+ kUint64Flag = 0x0100,
2521+ kDoubleFlag = 0x0200,
2522+ kStringFlag = 0x0400,
2523+ kCopyFlag = 0x0800,
2524+ kInlineStrFlag = 0x1000,
2525
2526 // Initial flags of different types.
2527 kNullFlag = kNullType,
2528@@ -1599,16 +1827,27 @@
2529 kObjectFlag = kObjectType,
2530 kArrayFlag = kArrayType,
2531
2532- kTypeMask = 0xFF // bitwise-and with mask of 0xFF can be optimized by compiler
2533+ kTypeMask = 0x07
2534 };
2535
2536 static const SizeType kDefaultArrayCapacity = 16;
2537 static const SizeType kDefaultObjectCapacity = 16;
2538
2539+ struct Flag {
2540+#if RAPIDJSON_48BITPOINTER_OPTIMIZATION
2541+ char payload[sizeof(SizeType) * 2 + 6]; // 2 x SizeType + lower 48-bit pointer
2542+#elif RAPIDJSON_64BIT
2543+ char payload[sizeof(SizeType) * 2 + sizeof(void*) + 6]; // 6 padding bytes
2544+#else
2545+ char payload[sizeof(SizeType) * 2 + sizeof(void*) + 2]; // 2 padding bytes
2546+#endif
2547+ uint16_t flags;
2548+ };
2549+
2550 struct String {
2551+ SizeType length;
2552+ SizeType hashcode; //!< reserved
2553 const Ch* str;
2554- SizeType length;
2555- unsigned hashcode; //!< reserved
2556 }; // 12 bytes in 32-bit mode, 16 bytes in 64-bit mode
2557
2558 // implementation detail: ShortString can represent zero-terminated strings up to MaxSize chars
2559@@ -1617,10 +1856,10 @@
2560 // to store has the maximal length of MaxSize then str[LenPos] will be 0 and therefore act as
2561 // the string terminator as well. For getting the string length back from that value just use
2562 // "MaxSize - str[LenPos]".
2563- // This allows to store 11-chars strings in 32-bit mode and 15-chars strings in 64-bit mode
2564- // inline (for `UTF8`-encoded strings).
2565+ // This allows to store 13-chars strings in 32-bit mode, 21-chars strings in 64-bit mode,
2566+ // 13-chars strings for RAPIDJSON_48BITPOINTER_OPTIMIZATION=1 inline (for `UTF8`-encoded strings).
2567 struct ShortString {
2568- enum { MaxChars = sizeof(String) / sizeof(Ch), MaxSize = MaxChars - 1, LenPos = MaxSize };
2569+ enum { MaxChars = sizeof(static_cast<Flag*>(0)->payload) / sizeof(Ch), MaxSize = MaxChars - 1, LenPos = MaxSize };
2570 Ch str[MaxChars];
2571
2572 inline static bool Usable(SizeType len) { return (MaxSize >= len); }
2573@@ -1654,69 +1893,79 @@
2574 double d;
2575 }; // 8 bytes
2576
2577- struct Object {
2578+ struct ObjectData {
2579+ SizeType size;
2580+ SizeType capacity;
2581 Member* members;
2582+ }; // 12 bytes in 32-bit mode, 16 bytes in 64-bit mode
2583+
2584+ struct ArrayData {
2585 SizeType size;
2586 SizeType capacity;
2587- }; // 12 bytes in 32-bit mode, 16 bytes in 64-bit mode
2588-
2589- struct Array {
2590 GenericValue* elements;
2591- SizeType size;
2592- SizeType capacity;
2593 }; // 12 bytes in 32-bit mode, 16 bytes in 64-bit mode
2594
2595 union Data {
2596 String s;
2597 ShortString ss;
2598 Number n;
2599- Object o;
2600- Array a;
2601- }; // 12 bytes in 32-bit mode, 16 bytes in 64-bit mode
2602+ ObjectData o;
2603+ ArrayData a;
2604+ Flag f;
2605+ }; // 16 bytes in 32-bit mode, 24 bytes in 64-bit mode, 16 bytes in 64-bit with RAPIDJSON_48BITPOINTER_OPTIMIZATION
2606+
2607+ RAPIDJSON_FORCEINLINE const Ch* GetStringPointer() const { return RAPIDJSON_GETPOINTER(Ch, data_.s.str); }
2608+ RAPIDJSON_FORCEINLINE const Ch* SetStringPointer(const Ch* str) { return RAPIDJSON_SETPOINTER(Ch, data_.s.str, str); }
2609+ RAPIDJSON_FORCEINLINE GenericValue* GetElementsPointer() const { return RAPIDJSON_GETPOINTER(GenericValue, data_.a.elements); }
2610+ RAPIDJSON_FORCEINLINE GenericValue* SetElementsPointer(GenericValue* elements) { return RAPIDJSON_SETPOINTER(GenericValue, data_.a.elements, elements); }
2611+ RAPIDJSON_FORCEINLINE Member* GetMembersPointer() const { return RAPIDJSON_GETPOINTER(Member, data_.o.members); }
2612+ RAPIDJSON_FORCEINLINE Member* SetMembersPointer(Member* members) { return RAPIDJSON_SETPOINTER(Member, data_.o.members, members); }
2613
2614 // Initialize this value as array with initial data, without calling destructor.
2615 void SetArrayRaw(GenericValue* values, SizeType count, Allocator& allocator) {
2616- flags_ = kArrayFlag;
2617+ data_.f.flags = kArrayFlag;
2618 if (count) {
2619- data_.a.elements = static_cast<GenericValue*>(allocator.Malloc(count * sizeof(GenericValue)));
2620- std::memcpy(data_.a.elements, values, count * sizeof(GenericValue));
2621+ GenericValue* e = static_cast<GenericValue*>(allocator.Malloc(count * sizeof(GenericValue)));
2622+ SetElementsPointer(e);
2623+ std::memcpy(e, values, count * sizeof(GenericValue));
2624 }
2625 else
2626- data_.a.elements = NULL;
2627+ SetElementsPointer(0);
2628 data_.a.size = data_.a.capacity = count;
2629 }
2630
2631 //! Initialize this value as object with initial data, without calling destructor.
2632 void SetObjectRaw(Member* members, SizeType count, Allocator& allocator) {
2633- flags_ = kObjectFlag;
2634+ data_.f.flags = kObjectFlag;
2635 if (count) {
2636- data_.o.members = static_cast<Member*>(allocator.Malloc(count * sizeof(Member)));
2637- std::memcpy(data_.o.members, members, count * sizeof(Member));
2638+ Member* m = static_cast<Member*>(allocator.Malloc(count * sizeof(Member)));
2639+ SetMembersPointer(m);
2640+ std::memcpy(m, members, count * sizeof(Member));
2641 }
2642 else
2643- data_.o.members = NULL;
2644+ SetMembersPointer(0);
2645 data_.o.size = data_.o.capacity = count;
2646 }
2647
2648 //! Initialize this value as constant string, without calling destructor.
2649 void SetStringRaw(StringRefType s) RAPIDJSON_NOEXCEPT {
2650- flags_ = kConstStringFlag;
2651- data_.s.str = s;
2652+ data_.f.flags = kConstStringFlag;
2653+ SetStringPointer(s);
2654 data_.s.length = s.length;
2655 }
2656
2657 //! Initialize this value as copy string with initial data, without calling destructor.
2658 void SetStringRaw(StringRefType s, Allocator& allocator) {
2659- Ch* str = NULL;
2660- if(ShortString::Usable(s.length)) {
2661- flags_ = kShortStringFlag;
2662+ Ch* str = 0;
2663+ if (ShortString::Usable(s.length)) {
2664+ data_.f.flags = kShortStringFlag;
2665 data_.ss.SetLength(s.length);
2666 str = data_.ss.str;
2667 } else {
2668- flags_ = kCopyStringFlag;
2669+ data_.f.flags = kCopyStringFlag;
2670 data_.s.length = s.length;
2671 str = static_cast<Ch *>(allocator.Malloc((s.length + 1) * sizeof(Ch)));
2672- data_.s.str = str;
2673+ SetStringPointer(str);
2674 }
2675 std::memcpy(str, s, s.length * sizeof(Ch));
2676 str[s.length] = '\0';
2677@@ -1725,8 +1974,8 @@
2678 //! Assignment without calling destructor
2679 void RawAssign(GenericValue& rhs) RAPIDJSON_NOEXCEPT {
2680 data_ = rhs.data_;
2681- flags_ = rhs.flags_;
2682- rhs.flags_ = kNullFlag;
2683+ // data_.f.flags = rhs.data_.f.flags;
2684+ rhs.data_.f.flags = kNullFlag;
2685 }
2686
2687 template <typename SourceAllocator>
2688@@ -1746,7 +1995,6 @@
2689 }
2690
2691 Data data_;
2692- unsigned flags_;
2693 };
2694
2695 //! GenericValue with UTF8 encoding
2696@@ -1869,6 +2117,21 @@
2697 */
2698 friend inline void swap(GenericDocument& a, GenericDocument& b) RAPIDJSON_NOEXCEPT { a.Swap(b); }
2699
2700+ //! Populate this document by a generator which produces SAX events.
2701+ /*! \tparam Generator A functor with <tt>bool f(Handler)</tt> prototype.
2702+ \param g Generator functor which sends SAX events to the parameter.
2703+ \return The document itself for fluent API.
2704+ */
2705+ template <typename Generator>
2706+ GenericDocument& Populate(Generator& g) {
2707+ ClearStackOnExit scope(*this);
2708+ if (g(*this)) {
2709+ RAPIDJSON_ASSERT(stack_.GetSize() == sizeof(ValueType)); // Got one and only one root object
2710+ ValueType::operator=(*stack_.template Pop<ValueType>(1));// Move value from stack to document
2711+ }
2712+ return *this;
2713+ }
2714+
2715 //!@name Parse from stream
2716 //!@{
2717
2718@@ -1967,6 +2230,42 @@
2719 GenericDocument& Parse(const Ch* str) {
2720 return Parse<kParseDefaultFlags>(str);
2721 }
2722+
2723+ template <unsigned parseFlags, typename SourceEncoding>
2724+ GenericDocument& Parse(const typename SourceEncoding::Ch* str, size_t length) {
2725+ RAPIDJSON_ASSERT(!(parseFlags & kParseInsituFlag));
2726+ MemoryStream ms(static_cast<const char*>(str), length * sizeof(typename SourceEncoding::Ch));
2727+ EncodedInputStream<SourceEncoding, MemoryStream> is(ms);
2728+ ParseStream<parseFlags, SourceEncoding>(is);
2729+ return *this;
2730+ }
2731+
2732+ template <unsigned parseFlags>
2733+ GenericDocument& Parse(const Ch* str, size_t length) {
2734+ return Parse<parseFlags, Encoding>(str, length);
2735+ }
2736+
2737+ GenericDocument& Parse(const Ch* str, size_t length) {
2738+ return Parse<kParseDefaultFlags>(str, length);
2739+ }
2740+
2741+#if RAPIDJSON_HAS_STDSTRING
2742+ template <unsigned parseFlags, typename SourceEncoding>
2743+ GenericDocument& Parse(const std::basic_string<typename SourceEncoding::Ch>& str) {
2744+ // c_str() is constant complexity according to standard. Should be faster than Parse(const char*, size_t)
2745+ return Parse<parseFlags, SourceEncoding>(str.c_str());
2746+ }
2747+
2748+ template <unsigned parseFlags>
2749+ GenericDocument& Parse(const std::basic_string<Ch>& str) {
2750+ return Parse<parseFlags, Encoding>(str.c_str());
2751+ }
2752+
2753+ GenericDocument& Parse(const std::basic_string<Ch>& str) {
2754+ return Parse<kParseDefaultFlags>(str);
2755+ }
2756+#endif // RAPIDJSON_HAS_STDSTRING
2757+
2758 //!@}
2759
2760 //!@name Handling parse errors
2761@@ -2017,9 +2316,10 @@
2762 };
2763
2764 // callers of the following private Handler functions
2765- template <typename,typename,typename> friend class GenericReader; // for parsing
2766+ // template <typename,typename,typename> friend class GenericReader; // for parsing
2767 template <typename, typename> friend class GenericValue; // for deep copying
2768
2769+public:
2770 // Implementation of Handler
2771 bool Null() { new (stack_.template Push<ValueType>()) ValueType(); return true; }
2772 bool Bool(bool b) { new (stack_.template Push<ValueType>()) ValueType(b); return true; }
2773@@ -2029,6 +2329,14 @@
2774 bool Uint64(uint64_t i) { new (stack_.template Push<ValueType>()) ValueType(i); return true; }
2775 bool Double(double d) { new (stack_.template Push<ValueType>()) ValueType(d); return true; }
2776
2777+ bool RawNumber(const Ch* str, SizeType length, bool copy) {
2778+ if (copy)
2779+ new (stack_.template Push<ValueType>()) ValueType(str, length, GetAllocator());
2780+ else
2781+ new (stack_.template Push<ValueType>()) ValueType(str, length);
2782+ return true;
2783+ }
2784+
2785 bool String(const Ch* str, SizeType length, bool copy) {
2786 if (copy)
2787 new (stack_.template Push<ValueType>()) ValueType(str, length, GetAllocator());
2788@@ -2099,20 +2407,159 @@
2789 }
2790 break;
2791 case kStringType:
2792- if (rhs.flags_ == kConstStringFlag) {
2793- flags_ = rhs.flags_;
2794+ if (rhs.data_.f.flags == kConstStringFlag) {
2795+ data_.f.flags = rhs.data_.f.flags;
2796 data_ = *reinterpret_cast<const Data*>(&rhs.data_);
2797 } else {
2798 SetStringRaw(StringRef(rhs.GetString(), rhs.GetStringLength()), allocator);
2799 }
2800 break;
2801 default:
2802- flags_ = rhs.flags_;
2803+ data_.f.flags = rhs.data_.f.flags;
2804 data_ = *reinterpret_cast<const Data*>(&rhs.data_);
2805 break;
2806 }
2807 }
2808
2809+//! Helper class for accessing Value of array type.
2810+/*!
2811+ Instance of this helper class is obtained by \c GenericValue::GetArray().
2812+ In addition to all APIs for array type, it provides range-based for loop if \c RAPIDJSON_HAS_CXX11_RANGE_FOR=1.
2813+*/
2814+template <bool Const, typename ValueT>
2815+class GenericArray {
2816+public:
2817+ typedef GenericArray<true, ValueT> ConstArray;
2818+ typedef GenericArray<false, ValueT> Array;
2819+ typedef ValueT PlainType;
2820+ typedef typename internal::MaybeAddConst<Const,PlainType>::Type ValueType;
2821+ typedef ValueType* ValueIterator; // This may be const or non-const iterator
2822+ typedef const ValueT* ConstValueIterator;
2823+ typedef typename ValueType::AllocatorType AllocatorType;
2824+ typedef typename ValueType::StringRefType StringRefType;
2825+
2826+ template <typename, typename>
2827+ friend class GenericValue;
2828+
2829+ GenericArray(const GenericArray& rhs) : value_(rhs.value_) {}
2830+ GenericArray& operator=(const GenericArray& rhs) { value_ = rhs.value_; return *this; }
2831+ ~GenericArray() {}
2832+
2833+ SizeType Size() const { return value_.Size(); }
2834+ SizeType Capacity() const { return value_.Capacity(); }
2835+ bool Empty() const { return value_.Empty(); }
2836+ void Clear() const { value_.Clear(); }
2837+ ValueType& operator[](SizeType index) const { return value_[index]; }
2838+ ValueIterator Begin() const { return value_.Begin(); }
2839+ ValueIterator End() const { return value_.End(); }
2840+ GenericArray Reserve(SizeType newCapacity, AllocatorType &allocator) const { value_.Reserve(newCapacity, allocator); return *this; }
2841+ GenericArray PushBack(ValueType& value, AllocatorType& allocator) const { value_.PushBack(value, allocator); return *this; }
2842+#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
2843+ GenericArray PushBack(ValueType&& value, AllocatorType& allocator) const { value_.PushBack(value, allocator); return *this; }
2844+#endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS
2845+ GenericArray PushBack(StringRefType value, AllocatorType& allocator) const { value_.PushBack(value, allocator); return *this; }
2846+ template <typename T> RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >), (const GenericArray&)) PushBack(T value, AllocatorType& allocator) const { value_.PushBack(value, allocator); return *this; }
2847+ GenericArray PopBack() const { value_.PopBack(); return *this; }
2848+ ValueIterator Erase(ConstValueIterator pos) const { return value_.Erase(pos); }
2849+ ValueIterator Erase(ConstValueIterator first, ConstValueIterator last) const { return value_.Erase(first, last); }
2850+
2851+#if RAPIDJSON_HAS_CXX11_RANGE_FOR
2852+ ValueIterator begin() const { return value_.Begin(); }
2853+ ValueIterator end() const { return value_.End(); }
2854+#endif
2855+
2856+private:
2857+ GenericArray();
2858+ GenericArray(ValueType& value) : value_(value) {}
2859+ ValueType& value_;
2860+};
2861+
2862+//! Helper class for accessing Value of object type.
2863+/*!
2864+ Instance of this helper class is obtained by \c GenericValue::GetObject().
2865+ In addition to all APIs for array type, it provides range-based for loop if \c RAPIDJSON_HAS_CXX11_RANGE_FOR=1.
2866+*/
2867+template <bool Const, typename ValueT>
2868+class GenericObject {
2869+public:
2870+ typedef GenericObject<true, ValueT> ConstObject;
2871+ typedef GenericObject<false, ValueT> Object;
2872+ typedef ValueT PlainType;
2873+ typedef typename internal::MaybeAddConst<Const,PlainType>::Type ValueType;
2874+ typedef GenericMemberIterator<Const, typename ValueT::EncodingType, typename ValueT::AllocatorType> MemberIterator; // This may be const or non-const iterator
2875+ typedef GenericMemberIterator<true, typename ValueT::EncodingType, typename ValueT::AllocatorType> ConstMemberIterator;
2876+ typedef typename ValueType::AllocatorType AllocatorType;
2877+ typedef typename ValueType::StringRefType StringRefType;
2878+ typedef typename ValueType::EncodingType EncodingType;
2879+ typedef typename ValueType::Ch Ch;
2880+
2881+ template <typename, typename>
2882+ friend class GenericValue;
2883+
2884+ GenericObject(const GenericObject& rhs) : value_(rhs.value_) {}
2885+ GenericObject& operator=(const GenericObject& rhs) { value_ = rhs.value_; return *this; }
2886+ ~GenericObject() {}
2887+
2888+ SizeType MemberCount() const { return value_.MemberCount(); }
2889+ bool ObjectEmpty() const { return value_.ObjectEmpty(); }
2890+ template <typename T> ValueType& operator[](T* name) const { return value_[name]; }
2891+ template <typename SourceAllocator> ValueType& operator[](const GenericValue<EncodingType, SourceAllocator>& name) const { return value_[name]; }
2892+#if RAPIDJSON_HAS_STDSTRING
2893+ ValueType& operator[](const std::basic_string<Ch>& name) const { return value_[name]; }
2894+#endif
2895+ MemberIterator MemberBegin() const { return value_.MemberBegin(); }
2896+ MemberIterator MemberEnd() const { return value_.MemberEnd(); }
2897+ bool HasMember(const Ch* name) const { return value_.HasMember(name); }
2898+#if RAPIDJSON_HAS_STDSTRING
2899+ bool HasMember(const std::basic_string<Ch>& name) const { return value_.HasMember(name); }
2900+#endif
2901+ template <typename SourceAllocator> bool HasMember(const GenericValue<EncodingType, SourceAllocator>& name) const { return value_.HasMember(name); }
2902+ MemberIterator FindMember(const Ch* name) const { return value_.FindMember(name); }
2903+ template <typename SourceAllocator> MemberIterator FindMember(const GenericValue<EncodingType, SourceAllocator>& name) const { return value_.FindMember(name); }
2904+#if RAPIDJSON_HAS_STDSTRING
2905+ MemberIterator FindMember(const std::basic_string<Ch>& name) const { return value_.FindMember(name); }
2906+#endif
2907+ GenericObject AddMember(ValueType& name, ValueType& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; }
2908+ GenericObject AddMember(ValueType& name, StringRefType value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; }
2909+#if RAPIDJSON_HAS_STDSTRING
2910+ GenericObject AddMember(ValueType& name, std::basic_string<Ch>& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; }
2911+#endif
2912+ template <typename T> RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >), (ValueType&)) AddMember(ValueType& name, T value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; }
2913+#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
2914+ GenericObject AddMember(ValueType&& name, ValueType&& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; }
2915+ GenericObject AddMember(ValueType&& name, ValueType& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; }
2916+ GenericObject AddMember(ValueType& name, ValueType&& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; }
2917+ GenericObject AddMember(StringRefType name, ValueType&& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; }
2918+#endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS
2919+ GenericObject AddMember(StringRefType name, ValueType& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; }
2920+ GenericObject AddMember(StringRefType name, StringRefType value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; }
2921+ template <typename T> RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >), (GenericObject)) AddMember(StringRefType name, T value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; }
2922+ void RemoveAllMembers() { return value_.RemoveAllMembers(); }
2923+ bool RemoveMember(const Ch* name) const { return value_.RemoveMember(name); }
2924+#if RAPIDJSON_HAS_STDSTRING
2925+ bool RemoveMember(const std::basic_string<Ch>& name) const { return value_.RemoveMember(name); }
2926+#endif
2927+ template <typename SourceAllocator> bool RemoveMember(const GenericValue<EncodingType, SourceAllocator>& name) const { return value_.RemoveMember(name); }
2928+ MemberIterator RemoveMember(MemberIterator m) const { return value_.RemoveMember(m); }
2929+ MemberIterator EraseMember(ConstMemberIterator pos) const { return value_.EraseMember(pos); }
2930+ MemberIterator EraseMember(ConstMemberIterator first, ConstMemberIterator last) const { return value_.EraseMember(first, last); }
2931+ bool EraseMember(const Ch* name) const { return value_.EraseMember(name); }
2932+#if RAPIDJSON_HAS_STDSTRING
2933+ bool EraseMember(const std::basic_string<Ch>& name) const { return EraseMember(ValueType(StringRef(name))); }
2934+#endif
2935+ template <typename SourceAllocator> bool EraseMember(const GenericValue<EncodingType, SourceAllocator>& name) const { return value_.EraseMember(name); }
2936+
2937+#if RAPIDJSON_HAS_CXX11_RANGE_FOR
2938+ MemberIterator begin() const { return value_.MemberBegin(); }
2939+ MemberIterator end() const { return value_.MemberEnd(); }
2940+#endif
2941+
2942+private:
2943+ GenericObject();
2944+ GenericObject(ValueType& value) : value_(value) {}
2945+ ValueType& value_;
2946+};
2947+
2948 RAPIDJSON_NAMESPACE_END
2949
2950 #ifdef _MSC_VER
2951
2952=== modified file 'shorts/xml2json/rapidjson/encodedstream.h'
2953--- shorts/xml2json/rapidjson/encodedstream.h 2016-03-04 13:27:57 +0000
2954+++ shorts/xml2json/rapidjson/encodedstream.h 2016-06-15 16:13:25 +0000
2955@@ -15,7 +15,8 @@
2956 #ifndef RAPIDJSON_ENCODEDSTREAM_H_
2957 #define RAPIDJSON_ENCODEDSTREAM_H_
2958
2959-#include "rapidjson.h"
2960+#include "stream.h"
2961+#include "memorystream.h"
2962
2963 #ifdef __GNUC__
2964 RAPIDJSON_DIAG_PUSH
2965@@ -62,6 +63,34 @@
2966 Ch current_;
2967 };
2968
2969+//! Specialized for UTF8 MemoryStream.
2970+template <>
2971+class EncodedInputStream<UTF8<>, MemoryStream> {
2972+public:
2973+ typedef UTF8<>::Ch Ch;
2974+
2975+ EncodedInputStream(MemoryStream& is) : is_(is) {
2976+ if (static_cast<unsigned char>(is_.Peek()) == 0xEFu) is_.Take();
2977+ if (static_cast<unsigned char>(is_.Peek()) == 0xBBu) is_.Take();
2978+ if (static_cast<unsigned char>(is_.Peek()) == 0xBFu) is_.Take();
2979+ }
2980+ Ch Peek() const { return is_.Peek(); }
2981+ Ch Take() { return is_.Take(); }
2982+ size_t Tell() const { return is_.Tell(); }
2983+
2984+ // Not implemented
2985+ void Put(Ch) {}
2986+ void Flush() {}
2987+ Ch* PutBegin() { return 0; }
2988+ size_t PutEnd(Ch*) { return 0; }
2989+
2990+ MemoryStream& is_;
2991+
2992+private:
2993+ EncodedInputStream(const EncodedInputStream&);
2994+ EncodedInputStream& operator=(const EncodedInputStream&);
2995+};
2996+
2997 //! Output byte stream wrapper with statically bound encoding.
2998 /*!
2999 \tparam Encoding The interpretation of encoding of the stream. Either UTF8, UTF16LE, UTF16BE, UTF32LE, UTF32BE.
3000
3001=== modified file 'shorts/xml2json/rapidjson/encodings.h'
3002--- shorts/xml2json/rapidjson/encodings.h 2016-03-04 13:27:57 +0000
3003+++ shorts/xml2json/rapidjson/encodings.h 2016-06-15 16:13:25 +0000
3004@@ -120,6 +120,28 @@
3005 }
3006 }
3007
3008+ template<typename OutputStream>
3009+ static void EncodeUnsafe(OutputStream& os, unsigned codepoint) {
3010+ if (codepoint <= 0x7F)
3011+ PutUnsafe(os, static_cast<Ch>(codepoint & 0xFF));
3012+ else if (codepoint <= 0x7FF) {
3013+ PutUnsafe(os, static_cast<Ch>(0xC0 | ((codepoint >> 6) & 0xFF)));
3014+ PutUnsafe(os, static_cast<Ch>(0x80 | ((codepoint & 0x3F))));
3015+ }
3016+ else if (codepoint <= 0xFFFF) {
3017+ PutUnsafe(os, static_cast<Ch>(0xE0 | ((codepoint >> 12) & 0xFF)));
3018+ PutUnsafe(os, static_cast<Ch>(0x80 | ((codepoint >> 6) & 0x3F)));
3019+ PutUnsafe(os, static_cast<Ch>(0x80 | (codepoint & 0x3F)));
3020+ }
3021+ else {
3022+ RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
3023+ PutUnsafe(os, static_cast<Ch>(0xF0 | ((codepoint >> 18) & 0xFF)));
3024+ PutUnsafe(os, static_cast<Ch>(0x80 | ((codepoint >> 12) & 0x3F)));
3025+ PutUnsafe(os, static_cast<Ch>(0x80 | ((codepoint >> 6) & 0x3F)));
3026+ PutUnsafe(os, static_cast<Ch>(0x80 | (codepoint & 0x3F)));
3027+ }
3028+ }
3029+
3030 template <typename InputStream>
3031 static bool Decode(InputStream& is, unsigned* codepoint) {
3032 #define COPY() c = is.Take(); *codepoint = (*codepoint << 6) | (static_cast<unsigned char>(c) & 0x3Fu)
3033@@ -261,6 +283,22 @@
3034 }
3035 }
3036
3037+
3038+ template<typename OutputStream>
3039+ static void EncodeUnsafe(OutputStream& os, unsigned codepoint) {
3040+ RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 2);
3041+ if (codepoint <= 0xFFFF) {
3042+ RAPIDJSON_ASSERT(codepoint < 0xD800 || codepoint > 0xDFFF); // Code point itself cannot be surrogate pair
3043+ PutUnsafe(os, static_cast<typename OutputStream::Ch>(codepoint));
3044+ }
3045+ else {
3046+ RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
3047+ unsigned v = codepoint - 0x10000;
3048+ PutUnsafe(os, static_cast<typename OutputStream::Ch>((v >> 10) | 0xD800));
3049+ PutUnsafe(os, (v & 0x3FF) | 0xDC00);
3050+ }
3051+ }
3052+
3053 template <typename InputStream>
3054 static bool Decode(InputStream& is, unsigned* codepoint) {
3055 RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 2);
3056@@ -386,6 +424,13 @@
3057 os.Put(codepoint);
3058 }
3059
3060+ template<typename OutputStream>
3061+ static void EncodeUnsafe(OutputStream& os, unsigned codepoint) {
3062+ RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 4);
3063+ RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
3064+ PutUnsafe(os, codepoint);
3065+ }
3066+
3067 template <typename InputStream>
3068 static bool Decode(InputStream& is, unsigned* codepoint) {
3069 RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 4);
3070@@ -501,6 +546,12 @@
3071 os.Put(static_cast<Ch>(codepoint & 0xFF));
3072 }
3073
3074+ template<typename OutputStream>
3075+ static void EncodeUnsafe(OutputStream& os, unsigned codepoint) {
3076+ RAPIDJSON_ASSERT(codepoint <= 0x7F);
3077+ PutUnsafe(os, static_cast<Ch>(codepoint & 0xFF));
3078+ }
3079+
3080 template <typename InputStream>
3081 static bool Decode(InputStream& is, unsigned* codepoint) {
3082 uint8_t c = static_cast<uint8_t>(is.Take());
3083@@ -571,6 +622,13 @@
3084 (*f[os.GetType()])(os, codepoint);
3085 }
3086
3087+ template<typename OutputStream>
3088+ RAPIDJSON_FORCEINLINE static void EncodeUnsafe(OutputStream& os, unsigned codepoint) {
3089+ typedef void (*EncodeFunc)(OutputStream&, unsigned);
3090+ static const EncodeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(EncodeUnsafe) };
3091+ (*f[os.GetType()])(os, codepoint);
3092+ }
3093+
3094 template <typename InputStream>
3095 RAPIDJSON_FORCEINLINE static bool Decode(InputStream& is, unsigned* codepoint) {
3096 typedef bool (*DecodeFunc)(InputStream&, unsigned*);
3097@@ -604,6 +662,15 @@
3098 return true;
3099 }
3100
3101+ template<typename InputStream, typename OutputStream>
3102+ RAPIDJSON_FORCEINLINE static bool TranscodeUnsafe(InputStream& is, OutputStream& os) {
3103+ unsigned codepoint;
3104+ if (!SourceEncoding::Decode(is, &codepoint))
3105+ return false;
3106+ TargetEncoding::EncodeUnsafe(os, codepoint);
3107+ return true;
3108+ }
3109+
3110 //! Validate one Unicode codepoint from an encoded stream.
3111 template<typename InputStream, typename OutputStream>
3112 RAPIDJSON_FORCEINLINE static bool Validate(InputStream& is, OutputStream& os) {
3113@@ -611,6 +678,10 @@
3114 }
3115 };
3116
3117+// Forward declaration.
3118+template<typename Stream>
3119+inline void PutUnsafe(Stream& stream, typename Stream::Ch c);
3120+
3121 //! Specialization of Transcoder with same source and target encoding.
3122 template<typename Encoding>
3123 struct Transcoder<Encoding, Encoding> {
3124@@ -621,6 +692,12 @@
3125 }
3126
3127 template<typename InputStream, typename OutputStream>
3128+ RAPIDJSON_FORCEINLINE static bool TranscodeUnsafe(InputStream& is, OutputStream& os) {
3129+ PutUnsafe(os, is.Take()); // Just copy one code unit. This semantic is different from primary template class.
3130+ return true;
3131+ }
3132+
3133+ template<typename InputStream, typename OutputStream>
3134 RAPIDJSON_FORCEINLINE static bool Validate(InputStream& is, OutputStream& os) {
3135 return Encoding::Validate(is, os); // source/target encoding are the same
3136 }
3137
3138=== modified file 'shorts/xml2json/rapidjson/filereadstream.h'
3139--- shorts/xml2json/rapidjson/filereadstream.h 2016-03-04 13:27:57 +0000
3140+++ shorts/xml2json/rapidjson/filereadstream.h 2016-06-15 16:13:25 +0000
3141@@ -15,7 +15,7 @@
3142 #ifndef RAPIDJSON_FILEREADSTREAM_H_
3143 #define RAPIDJSON_FILEREADSTREAM_H_
3144
3145-#include "rapidjson.h"
3146+#include "stream.h"
3147 #include <cstdio>
3148
3149 #ifdef __clang__
3150
3151=== modified file 'shorts/xml2json/rapidjson/filewritestream.h'
3152--- shorts/xml2json/rapidjson/filewritestream.h 2016-03-04 13:27:57 +0000
3153+++ shorts/xml2json/rapidjson/filewritestream.h 2016-06-15 16:13:25 +0000
3154@@ -15,7 +15,7 @@
3155 #ifndef RAPIDJSON_FILEWRITESTREAM_H_
3156 #define RAPIDJSON_FILEWRITESTREAM_H_
3157
3158-#include "rapidjson.h"
3159+#include "stream.h"
3160 #include <cstdio>
3161
3162 #ifdef __clang__
3163
3164=== added file 'shorts/xml2json/rapidjson/fwd.h'
3165--- shorts/xml2json/rapidjson/fwd.h 1970-01-01 00:00:00 +0000
3166+++ shorts/xml2json/rapidjson/fwd.h 2016-06-15 16:13:25 +0000
3167@@ -0,0 +1,151 @@
3168+// Tencent is pleased to support the open source community by making RapidJSON available.
3169+//
3170+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
3171+//
3172+// Licensed under the MIT License (the "License"); you may not use this file except
3173+// in compliance with the License. You may obtain a copy of the License at
3174+//
3175+// http://opensource.org/licenses/MIT
3176+//
3177+// Unless required by applicable law or agreed to in writing, software distributed
3178+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
3179+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
3180+// specific language governing permissions and limitations under the License.
3181+
3182+#ifndef RAPIDJSON_FWD_H_
3183+#define RAPIDJSON_FWD_H_
3184+
3185+#include "rapidjson.h"
3186+
3187+RAPIDJSON_NAMESPACE_BEGIN
3188+
3189+// encodings.h
3190+
3191+template<typename CharType> struct UTF8;
3192+template<typename CharType> struct UTF16;
3193+template<typename CharType> struct UTF16BE;
3194+template<typename CharType> struct UTF16LE;
3195+template<typename CharType> struct UTF32;
3196+template<typename CharType> struct UTF32BE;
3197+template<typename CharType> struct UTF32LE;
3198+template<typename CharType> struct ASCII;
3199+template<typename CharType> struct AutoUTF;
3200+
3201+template<typename SourceEncoding, typename TargetEncoding>
3202+struct Transcoder;
3203+
3204+// allocators.h
3205+
3206+class CrtAllocator;
3207+
3208+template <typename BaseAllocator>
3209+class MemoryPoolAllocator;
3210+
3211+// stream.h
3212+
3213+template <typename Encoding>
3214+struct GenericStringStream;
3215+
3216+typedef GenericStringStream<UTF8<char> > StringStream;
3217+
3218+template <typename Encoding>
3219+struct GenericInsituStringStream;
3220+
3221+typedef GenericInsituStringStream<UTF8<char> > InsituStringStream;
3222+
3223+// stringbuffer.h
3224+
3225+template <typename Encoding, typename Allocator>
3226+class GenericStringBuffer;
3227+
3228+typedef GenericStringBuffer<UTF8<char>, CrtAllocator> StringBuffer;
3229+
3230+// filereadstream.h
3231+
3232+class FileReadStream;
3233+
3234+// filewritestream.h
3235+
3236+class FileWriteStream;
3237+
3238+// memorybuffer.h
3239+
3240+template <typename Allocator>
3241+struct GenericMemoryBuffer;
3242+
3243+typedef GenericMemoryBuffer<CrtAllocator> MemoryBuffer;
3244+
3245+// memorystream.h
3246+
3247+struct MemoryStream;
3248+
3249+// reader.h
3250+
3251+template<typename Encoding, typename Derived>
3252+struct BaseReaderHandler;
3253+
3254+template <typename SourceEncoding, typename TargetEncoding, typename StackAllocator>
3255+class GenericReader;
3256+
3257+typedef GenericReader<UTF8<char>, UTF8<char>, CrtAllocator> Reader;
3258+
3259+// writer.h
3260+
3261+template<typename OutputStream, typename SourceEncoding, typename TargetEncoding, typename StackAllocator, unsigned writeFlags>
3262+class Writer;
3263+
3264+// prettywriter.h
3265+
3266+template<typename OutputStream, typename SourceEncoding, typename TargetEncoding, typename StackAllocator, unsigned writeFlags>
3267+class PrettyWriter;
3268+
3269+// document.h
3270+
3271+template <typename Encoding, typename Allocator>
3272+struct GenericMember;
3273+
3274+template <bool Const, typename Encoding, typename Allocator>
3275+class GenericMemberIterator;
3276+
3277+template<typename CharType>
3278+struct GenericStringRef;
3279+
3280+template <typename Encoding, typename Allocator>
3281+class GenericValue;
3282+
3283+typedef GenericValue<UTF8<char>, MemoryPoolAllocator<CrtAllocator> > Value;
3284+
3285+template <typename Encoding, typename Allocator, typename StackAllocator>
3286+class GenericDocument;
3287+
3288+typedef GenericDocument<UTF8<char>, MemoryPoolAllocator<CrtAllocator>, CrtAllocator> Document;
3289+
3290+// pointer.h
3291+
3292+template <typename ValueType, typename Allocator>
3293+class GenericPointer;
3294+
3295+typedef GenericPointer<Value, CrtAllocator> Pointer;
3296+
3297+// schema.h
3298+
3299+template <typename SchemaDocumentType>
3300+class IGenericRemoteSchemaDocumentProvider;
3301+
3302+template <typename ValueT, typename Allocator>
3303+class GenericSchemaDocument;
3304+
3305+typedef GenericSchemaDocument<Value, CrtAllocator> SchemaDocument;
3306+typedef IGenericRemoteSchemaDocumentProvider<SchemaDocument> IRemoteSchemaDocumentProvider;
3307+
3308+template <
3309+ typename SchemaDocumentType,
3310+ typename OutputHandler,
3311+ typename StateAllocator>
3312+class GenericSchemaValidator;
3313+
3314+typedef GenericSchemaValidator<SchemaDocument, BaseReaderHandler<UTF8<char>, void>, CrtAllocator> SchemaValidator;
3315+
3316+RAPIDJSON_NAMESPACE_END
3317+
3318+#endif // RAPIDJSON_RAPIDJSONFWD_H_
3319
3320=== modified file 'shorts/xml2json/rapidjson/internal/biginteger.h' (properties changed: -x to +x)
3321=== modified file 'shorts/xml2json/rapidjson/internal/diyfp.h'
3322--- shorts/xml2json/rapidjson/internal/diyfp.h 2016-03-04 13:27:57 +0000
3323+++ shorts/xml2json/rapidjson/internal/diyfp.h 2016-06-15 16:13:25 +0000
3324@@ -41,7 +41,7 @@
3325 #endif
3326
3327 struct DiyFp {
3328- DiyFp() {}
3329+ DiyFp() : f(), e() {}
3330
3331 DiyFp(uint64_t fp, int exp) : f(fp), e(exp) {}
3332
3333
3334=== modified file 'shorts/xml2json/rapidjson/internal/dtoa.h'
3335--- shorts/xml2json/rapidjson/internal/dtoa.h 2016-03-04 13:27:57 +0000
3336+++ shorts/xml2json/rapidjson/internal/dtoa.h 2016-06-15 16:13:25 +0000
3337@@ -29,6 +29,7 @@
3338 #ifdef __GNUC__
3339 RAPIDJSON_DIAG_PUSH
3340 RAPIDJSON_DIAG_OFF(effc++)
3341+RAPIDJSON_DIAG_OFF(array-bounds) // some gcc versions generate wrong warnings https://gcc.gnu.org/bugzilla/show_bug.cgi?id=59124
3342 #endif
3343
3344 inline void GrisuRound(char* buffer, int len, uint64_t delta, uint64_t rest, uint64_t ten_kappa, uint64_t wp_w) {
3345@@ -145,10 +146,10 @@
3346 return buffer;
3347 }
3348
3349-inline char* Prettify(char* buffer, int length, int k) {
3350+inline char* Prettify(char* buffer, int length, int k, int maxDecimalPlaces) {
3351 const int kk = length + k; // 10^(kk-1) <= v < 10^kk
3352
3353- if (length <= kk && kk <= 21) {
3354+ if (0 <= k && kk <= 21) {
3355 // 1234e7 -> 12340000000
3356 for (int i = length; i < kk; i++)
3357 buffer[i] = '0';
3358@@ -160,7 +161,16 @@
3359 // 1234e-2 -> 12.34
3360 std::memmove(&buffer[kk + 1], &buffer[kk], static_cast<size_t>(length - kk));
3361 buffer[kk] = '.';
3362- return &buffer[length + 1];
3363+ if (0 > k + maxDecimalPlaces) {
3364+ // When maxDecimalPlaces = 2, 1.2345 -> 1.23, 1.102 -> 1.1
3365+ // Remove extra trailing zeros (at least one) after truncation.
3366+ for (int i = kk + maxDecimalPlaces; i > kk + 1; i--)
3367+ if (buffer[i] != '0')
3368+ return &buffer[i + 1];
3369+ return &buffer[kk + 2]; // Reserve one zero
3370+ }
3371+ else
3372+ return &buffer[length + 1];
3373 }
3374 else if (-6 < kk && kk <= 0) {
3375 // 1234e-6 -> 0.001234
3376@@ -170,7 +180,23 @@
3377 buffer[1] = '.';
3378 for (int i = 2; i < offset; i++)
3379 buffer[i] = '0';
3380- return &buffer[length + offset];
3381+ if (length - kk > maxDecimalPlaces) {
3382+ // When maxDecimalPlaces = 2, 0.123 -> 0.12, 0.102 -> 0.1
3383+ // Remove extra trailing zeros (at least one) after truncation.
3384+ for (int i = maxDecimalPlaces + 1; i > 2; i--)
3385+ if (buffer[i] != '0')
3386+ return &buffer[i + 1];
3387+ return &buffer[3]; // Reserve one zero
3388+ }
3389+ else
3390+ return &buffer[length + offset];
3391+ }
3392+ else if (kk < -maxDecimalPlaces) {
3393+ // Truncate to zero
3394+ buffer[0] = '0';
3395+ buffer[1] = '.';
3396+ buffer[2] = '0';
3397+ return &buffer[3];
3398 }
3399 else if (length == 1) {
3400 // 1e30
3401@@ -186,7 +212,8 @@
3402 }
3403 }
3404
3405-inline char* dtoa(double value, char* buffer) {
3406+inline char* dtoa(double value, char* buffer, int maxDecimalPlaces = 324) {
3407+ RAPIDJSON_ASSERT(maxDecimalPlaces >= 1);
3408 Double d(value);
3409 if (d.IsZero()) {
3410 if (d.Sign())
3411@@ -203,7 +230,7 @@
3412 }
3413 int length, K;
3414 Grisu2(value, buffer, &length, &K);
3415- return Prettify(buffer, length, K);
3416+ return Prettify(buffer, length, K, maxDecimalPlaces);
3417 }
3418 }
3419
3420
3421=== modified file 'shorts/xml2json/rapidjson/internal/ieee754.h'
3422--- shorts/xml2json/rapidjson/internal/ieee754.h 2016-03-04 13:27:57 +0000
3423+++ shorts/xml2json/rapidjson/internal/ieee754.h 2016-06-15 16:13:25 +0000
3424@@ -40,6 +40,7 @@
3425
3426 bool IsNan() const { return (u_ & kExponentMask) == kExponentMask && Significand() != 0; }
3427 bool IsInf() const { return (u_ & kExponentMask) == kExponentMask && Significand() == 0; }
3428+ bool IsNanOrInf() const { return (u_ & kExponentMask) == kExponentMask; }
3429 bool IsNormal() const { return (u_ & kExponentMask) != 0 || Significand() == 0; }
3430 bool IsZero() const { return (u_ & (kExponentMask | kSignificandMask)) == 0; }
3431
3432
3433=== added file 'shorts/xml2json/rapidjson/internal/regex.h'
3434--- shorts/xml2json/rapidjson/internal/regex.h 1970-01-01 00:00:00 +0000
3435+++ shorts/xml2json/rapidjson/internal/regex.h 2016-06-15 16:13:25 +0000
3436@@ -0,0 +1,705 @@
3437+// Tencent is pleased to support the open source community by making RapidJSON available.
3438+//
3439+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
3440+//
3441+// Licensed under the MIT License (the "License"); you may not use this file except
3442+// in compliance with the License. You may obtain a copy of the License at
3443+//
3444+// http://opensource.org/licenses/MIT
3445+//
3446+// Unless required by applicable law or agreed to in writing, software distributed
3447+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
3448+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
3449+// specific language governing permissions and limitations under the License.
3450+
3451+#ifndef RAPIDJSON_INTERNAL_REGEX_H_
3452+#define RAPIDJSON_INTERNAL_REGEX_H_
3453+
3454+#include "../allocators.h"
3455+#include "../stream.h"
3456+#include "stack.h"
3457+
3458+#ifdef __clang__
3459+RAPIDJSON_DIAG_PUSH
3460+RAPIDJSON_DIAG_OFF(padded)
3461+RAPIDJSON_DIAG_OFF(switch-enum)
3462+RAPIDJSON_DIAG_OFF(implicit-fallthrough)
3463+#endif
3464+
3465+#ifdef __GNUC__
3466+RAPIDJSON_DIAG_PUSH
3467+RAPIDJSON_DIAG_OFF(effc++)
3468+#endif
3469+
3470+#ifdef _MSC_VER
3471+RAPIDJSON_DIAG_PUSH
3472+RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated
3473+#endif
3474+
3475+#ifndef RAPIDJSON_REGEX_VERBOSE
3476+#define RAPIDJSON_REGEX_VERBOSE 0
3477+#endif
3478+
3479+RAPIDJSON_NAMESPACE_BEGIN
3480+namespace internal {
3481+
3482+///////////////////////////////////////////////////////////////////////////////
3483+// GenericRegex
3484+
3485+static const SizeType kRegexInvalidState = ~SizeType(0); //!< Represents an invalid index in GenericRegex::State::out, out1
3486+static const SizeType kRegexInvalidRange = ~SizeType(0);
3487+
3488+//! Regular expression engine with subset of ECMAscript grammar.
3489+/*!
3490+ Supported regular expression syntax:
3491+ - \c ab Concatenation
3492+ - \c a|b Alternation
3493+ - \c a? Zero or one
3494+ - \c a* Zero or more
3495+ - \c a+ One or more
3496+ - \c a{3} Exactly 3 times
3497+ - \c a{3,} At least 3 times
3498+ - \c a{3,5} 3 to 5 times
3499+ - \c (ab) Grouping
3500+ - \c ^a At the beginning
3501+ - \c a$ At the end
3502+ - \c . Any character
3503+ - \c [abc] Character classes
3504+ - \c [a-c] Character class range
3505+ - \c [a-z0-9_] Character class combination
3506+ - \c [^abc] Negated character classes
3507+ - \c [^a-c] Negated character class range
3508+ - \c [\b] Backspace (U+0008)
3509+ - \c \\| \\\\ ... Escape characters
3510+ - \c \\f Form feed (U+000C)
3511+ - \c \\n Line feed (U+000A)
3512+ - \c \\r Carriage return (U+000D)
3513+ - \c \\t Tab (U+0009)
3514+ - \c \\v Vertical tab (U+000B)
3515+
3516+ \note This is a Thompson NFA engine, implemented with reference to
3517+ Cox, Russ. "Regular Expression Matching Can Be Simple And Fast (but is slow in Java, Perl, PHP, Python, Ruby,...).",
3518+ https://swtch.com/~rsc/regexp/regexp1.html
3519+*/
3520+template <typename Encoding, typename Allocator = CrtAllocator>
3521+class GenericRegex {
3522+public:
3523+ typedef typename Encoding::Ch Ch;
3524+
3525+ GenericRegex(const Ch* source, Allocator* allocator = 0) :
3526+ states_(allocator, 256), ranges_(allocator, 256), root_(kRegexInvalidState), stateCount_(), rangeCount_(),
3527+ stateSet_(), state0_(allocator, 0), state1_(allocator, 0), anchorBegin_(), anchorEnd_()
3528+ {
3529+ GenericStringStream<Encoding> ss(source);
3530+ DecodedStream<GenericStringStream<Encoding> > ds(ss);
3531+ Parse(ds);
3532+ }
3533+
3534+ ~GenericRegex() {
3535+ Allocator::Free(stateSet_);
3536+ }
3537+
3538+ bool IsValid() const {
3539+ return root_ != kRegexInvalidState;
3540+ }
3541+
3542+ template <typename InputStream>
3543+ bool Match(InputStream& is) const {
3544+ return SearchWithAnchoring(is, true, true);
3545+ }
3546+
3547+ bool Match(const Ch* s) const {
3548+ GenericStringStream<Encoding> is(s);
3549+ return Match(is);
3550+ }
3551+
3552+ template <typename InputStream>
3553+ bool Search(InputStream& is) const {
3554+ return SearchWithAnchoring(is, anchorBegin_, anchorEnd_);
3555+ }
3556+
3557+ bool Search(const Ch* s) const {
3558+ GenericStringStream<Encoding> is(s);
3559+ return Search(is);
3560+ }
3561+
3562+private:
3563+ enum Operator {
3564+ kZeroOrOne,
3565+ kZeroOrMore,
3566+ kOneOrMore,
3567+ kConcatenation,
3568+ kAlternation,
3569+ kLeftParenthesis
3570+ };
3571+
3572+ static const unsigned kAnyCharacterClass = 0xFFFFFFFF; //!< For '.'
3573+ static const unsigned kRangeCharacterClass = 0xFFFFFFFE;
3574+ static const unsigned kRangeNegationFlag = 0x80000000;
3575+
3576+ struct Range {
3577+ unsigned start; //
3578+ unsigned end;
3579+ SizeType next;
3580+ };
3581+
3582+ struct State {
3583+ SizeType out; //!< Equals to kInvalid for matching state
3584+ SizeType out1; //!< Equals to non-kInvalid for split
3585+ SizeType rangeStart;
3586+ unsigned codepoint;
3587+ };
3588+
3589+ struct Frag {
3590+ Frag(SizeType s, SizeType o, SizeType m) : start(s), out(o), minIndex(m) {}
3591+ SizeType start;
3592+ SizeType out; //!< link-list of all output states
3593+ SizeType minIndex;
3594+ };
3595+
3596+ template <typename SourceStream>
3597+ class DecodedStream {
3598+ public:
3599+ DecodedStream(SourceStream& ss) : ss_(ss), codepoint_() { Decode(); }
3600+ unsigned Peek() { return codepoint_; }
3601+ unsigned Take() {
3602+ unsigned c = codepoint_;
3603+ if (c) // No further decoding when '\0'
3604+ Decode();
3605+ return c;
3606+ }
3607+
3608+ private:
3609+ void Decode() {
3610+ if (!Encoding::Decode(ss_, &codepoint_))
3611+ codepoint_ = 0;
3612+ }
3613+
3614+ SourceStream& ss_;
3615+ unsigned codepoint_;
3616+ };
3617+
3618+ State& GetState(SizeType index) {
3619+ RAPIDJSON_ASSERT(index < stateCount_);
3620+ return states_.template Bottom<State>()[index];
3621+ }
3622+
3623+ const State& GetState(SizeType index) const {
3624+ RAPIDJSON_ASSERT(index < stateCount_);
3625+ return states_.template Bottom<State>()[index];
3626+ }
3627+
3628+ Range& GetRange(SizeType index) {
3629+ RAPIDJSON_ASSERT(index < rangeCount_);
3630+ return ranges_.template Bottom<Range>()[index];
3631+ }
3632+
3633+ const Range& GetRange(SizeType index) const {
3634+ RAPIDJSON_ASSERT(index < rangeCount_);
3635+ return ranges_.template Bottom<Range>()[index];
3636+ }
3637+
3638+ template <typename InputStream>
3639+ void Parse(DecodedStream<InputStream>& ds) {
3640+ Allocator allocator;
3641+ Stack<Allocator> operandStack(&allocator, 256); // Frag
3642+ Stack<Allocator> operatorStack(&allocator, 256); // Operator
3643+ Stack<Allocator> atomCountStack(&allocator, 256); // unsigned (Atom per parenthesis)
3644+
3645+ *atomCountStack.template Push<unsigned>() = 0;
3646+
3647+ unsigned codepoint;
3648+ while (ds.Peek() != 0) {
3649+ switch (codepoint = ds.Take()) {
3650+ case '^':
3651+ anchorBegin_ = true;
3652+ break;
3653+
3654+ case '$':
3655+ anchorEnd_ = true;
3656+ break;
3657+
3658+ case '|':
3659+ while (!operatorStack.Empty() && *operatorStack.template Top<Operator>() < kAlternation)
3660+ if (!Eval(operandStack, *operatorStack.template Pop<Operator>(1)))
3661+ return;
3662+ *operatorStack.template Push<Operator>() = kAlternation;
3663+ *atomCountStack.template Top<unsigned>() = 0;
3664+ break;
3665+
3666+ case '(':
3667+ *operatorStack.template Push<Operator>() = kLeftParenthesis;
3668+ *atomCountStack.template Push<unsigned>() = 0;
3669+ break;
3670+
3671+ case ')':
3672+ while (!operatorStack.Empty() && *operatorStack.template Top<Operator>() != kLeftParenthesis)
3673+ if (!Eval(operandStack, *operatorStack.template Pop<Operator>(1)))
3674+ return;
3675+ if (operatorStack.Empty())
3676+ return;
3677+ operatorStack.template Pop<Operator>(1);
3678+ atomCountStack.template Pop<unsigned>(1);
3679+ ImplicitConcatenation(atomCountStack, operatorStack);
3680+ break;
3681+
3682+ case '?':
3683+ if (!Eval(operandStack, kZeroOrOne))
3684+ return;
3685+ break;
3686+
3687+ case '*':
3688+ if (!Eval(operandStack, kZeroOrMore))
3689+ return;
3690+ break;
3691+
3692+ case '+':
3693+ if (!Eval(operandStack, kOneOrMore))
3694+ return;
3695+ break;
3696+
3697+ case '{':
3698+ {
3699+ unsigned n, m;
3700+ if (!ParseUnsigned(ds, &n))
3701+ return;
3702+
3703+ if (ds.Peek() == ',') {
3704+ ds.Take();
3705+ if (ds.Peek() == '}')
3706+ m = kInfinityQuantifier;
3707+ else if (!ParseUnsigned(ds, &m) || m < n)
3708+ return;
3709+ }
3710+ else
3711+ m = n;
3712+
3713+ if (!EvalQuantifier(operandStack, n, m) || ds.Peek() != '}')
3714+ return;
3715+ ds.Take();
3716+ }
3717+ break;
3718+
3719+ case '.':
3720+ PushOperand(operandStack, kAnyCharacterClass);
3721+ ImplicitConcatenation(atomCountStack, operatorStack);
3722+ break;
3723+
3724+ case '[':
3725+ {
3726+ SizeType range;
3727+ if (!ParseRange(ds, &range))
3728+ return;
3729+ SizeType s = NewState(kRegexInvalidState, kRegexInvalidState, kRangeCharacterClass);
3730+ GetState(s).rangeStart = range;
3731+ *operandStack.template Push<Frag>() = Frag(s, s, s);
3732+ }
3733+ ImplicitConcatenation(atomCountStack, operatorStack);
3734+ break;
3735+
3736+ case '\\': // Escape character
3737+ if (!CharacterEscape(ds, &codepoint))
3738+ return; // Unsupported escape character
3739+ // fall through to default
3740+
3741+ default: // Pattern character
3742+ PushOperand(operandStack, codepoint);
3743+ ImplicitConcatenation(atomCountStack, operatorStack);
3744+ }
3745+ }
3746+
3747+ while (!operatorStack.Empty())
3748+ if (!Eval(operandStack, *operatorStack.template Pop<Operator>(1)))
3749+ return;
3750+
3751+ // Link the operand to matching state.
3752+ if (operandStack.GetSize() == sizeof(Frag)) {
3753+ Frag* e = operandStack.template Pop<Frag>(1);
3754+ Patch(e->out, NewState(kRegexInvalidState, kRegexInvalidState, 0));
3755+ root_ = e->start;
3756+
3757+#if RAPIDJSON_REGEX_VERBOSE
3758+ printf("root: %d\n", root_);
3759+ for (SizeType i = 0; i < stateCount_ ; i++) {
3760+ State& s = GetState(i);
3761+ printf("[%2d] out: %2d out1: %2d c: '%c'\n", i, s.out, s.out1, (char)s.codepoint);
3762+ }
3763+ printf("\n");
3764+#endif
3765+ }
3766+
3767+ // Preallocate buffer for SearchWithAnchoring()
3768+ RAPIDJSON_ASSERT(stateSet_ == 0);
3769+ if (stateCount_ > 0) {
3770+ stateSet_ = static_cast<unsigned*>(states_.GetAllocator().Malloc(GetStateSetSize()));
3771+ state0_.template Reserve<SizeType>(stateCount_);
3772+ state1_.template Reserve<SizeType>(stateCount_);
3773+ }
3774+ }
3775+
3776+ SizeType NewState(SizeType out, SizeType out1, unsigned codepoint) {
3777+ State* s = states_.template Push<State>();
3778+ s->out = out;
3779+ s->out1 = out1;
3780+ s->codepoint = codepoint;
3781+ s->rangeStart = kRegexInvalidRange;
3782+ return stateCount_++;
3783+ }
3784+
3785+ void PushOperand(Stack<Allocator>& operandStack, unsigned codepoint) {
3786+ SizeType s = NewState(kRegexInvalidState, kRegexInvalidState, codepoint);
3787+ *operandStack.template Push<Frag>() = Frag(s, s, s);
3788+ }
3789+
3790+ void ImplicitConcatenation(Stack<Allocator>& atomCountStack, Stack<Allocator>& operatorStack) {
3791+ if (*atomCountStack.template Top<unsigned>())
3792+ *operatorStack.template Push<Operator>() = kConcatenation;
3793+ (*atomCountStack.template Top<unsigned>())++;
3794+ }
3795+
3796+ SizeType Append(SizeType l1, SizeType l2) {
3797+ SizeType old = l1;
3798+ while (GetState(l1).out != kRegexInvalidState)
3799+ l1 = GetState(l1).out;
3800+ GetState(l1).out = l2;
3801+ return old;
3802+ }
3803+
3804+ void Patch(SizeType l, SizeType s) {
3805+ for (SizeType next; l != kRegexInvalidState; l = next) {
3806+ next = GetState(l).out;
3807+ GetState(l).out = s;
3808+ }
3809+ }
3810+
3811+ bool Eval(Stack<Allocator>& operandStack, Operator op) {
3812+ switch (op) {
3813+ case kConcatenation:
3814+ if (operandStack.GetSize() >= sizeof(Frag) * 2) {
3815+ Frag e2 = *operandStack.template Pop<Frag>(1);
3816+ Frag e1 = *operandStack.template Pop<Frag>(1);
3817+ Patch(e1.out, e2.start);
3818+ *operandStack.template Push<Frag>() = Frag(e1.start, e2.out, Min(e1.minIndex, e2.minIndex));
3819+ return true;
3820+ }
3821+ return false;
3822+
3823+ case kAlternation:
3824+ if (operandStack.GetSize() >= sizeof(Frag) * 2) {
3825+ Frag e2 = *operandStack.template Pop<Frag>(1);
3826+ Frag e1 = *operandStack.template Pop<Frag>(1);
3827+ SizeType s = NewState(e1.start, e2.start, 0);
3828+ *operandStack.template Push<Frag>() = Frag(s, Append(e1.out, e2.out), Min(e1.minIndex, e2.minIndex));
3829+ return true;
3830+ }
3831+ return false;
3832+
3833+ case kZeroOrOne:
3834+ if (operandStack.GetSize() >= sizeof(Frag)) {
3835+ Frag e = *operandStack.template Pop<Frag>(1);
3836+ SizeType s = NewState(kRegexInvalidState, e.start, 0);
3837+ *operandStack.template Push<Frag>() = Frag(s, Append(e.out, s), e.minIndex);
3838+ return true;
3839+ }
3840+ return false;
3841+
3842+ case kZeroOrMore:
3843+ if (operandStack.GetSize() >= sizeof(Frag)) {
3844+ Frag e = *operandStack.template Pop<Frag>(1);
3845+ SizeType s = NewState(kRegexInvalidState, e.start, 0);
3846+ Patch(e.out, s);
3847+ *operandStack.template Push<Frag>() = Frag(s, s, e.minIndex);
3848+ return true;
3849+ }
3850+ return false;
3851+
3852+ case kOneOrMore:
3853+ if (operandStack.GetSize() >= sizeof(Frag)) {
3854+ Frag e = *operandStack.template Pop<Frag>(1);
3855+ SizeType s = NewState(kRegexInvalidState, e.start, 0);
3856+ Patch(e.out, s);
3857+ *operandStack.template Push<Frag>() = Frag(e.start, s, e.minIndex);
3858+ return true;
3859+ }
3860+ return false;
3861+
3862+ default:
3863+ return false;
3864+ }
3865+ }
3866+
3867+ bool EvalQuantifier(Stack<Allocator>& operandStack, unsigned n, unsigned m) {
3868+ RAPIDJSON_ASSERT(n <= m);
3869+ if (operandStack.GetSize() < sizeof(Frag))
3870+ return false;
3871+
3872+ if (n == 0) {
3873+ if (m == 0) // a{0} not support
3874+ return false;
3875+ else if (m == kInfinityQuantifier)
3876+ Eval(operandStack, kZeroOrMore); // a{0,} -> a*
3877+ else {
3878+ Eval(operandStack, kZeroOrOne); // a{0,5} -> a?
3879+ for (unsigned i = 0; i < m - 1; i++)
3880+ CloneTopOperand(operandStack); // a{0,5} -> a? a? a? a? a?
3881+ for (unsigned i = 0; i < m - 1; i++)
3882+ Eval(operandStack, kConcatenation); // a{0,5} -> a?a?a?a?a?
3883+ }
3884+ return true;
3885+ }
3886+
3887+ for (unsigned i = 0; i < n - 1; i++) // a{3} -> a a a
3888+ CloneTopOperand(operandStack);
3889+
3890+ if (m == kInfinityQuantifier)
3891+ Eval(operandStack, kOneOrMore); // a{3,} -> a a a+
3892+ else if (m > n) {
3893+ CloneTopOperand(operandStack); // a{3,5} -> a a a a
3894+ Eval(operandStack, kZeroOrOne); // a{3,5} -> a a a a?
3895+ for (unsigned i = n; i < m - 1; i++)
3896+ CloneTopOperand(operandStack); // a{3,5} -> a a a a? a?
3897+ for (unsigned i = n; i < m; i++)
3898+ Eval(operandStack, kConcatenation); // a{3,5} -> a a aa?a?
3899+ }
3900+
3901+ for (unsigned i = 0; i < n - 1; i++)
3902+ Eval(operandStack, kConcatenation); // a{3} -> aaa, a{3,} -> aaa+, a{3.5} -> aaaa?a?
3903+
3904+ return true;
3905+ }
3906+
3907+ static SizeType Min(SizeType a, SizeType b) { return a < b ? a : b; }
3908+
3909+ void CloneTopOperand(Stack<Allocator>& operandStack) {
3910+ const Frag *src = operandStack.template Top<Frag>();
3911+ SizeType count = stateCount_ - src->minIndex; // Assumes top operand contains states in [src->minIndex, stateCount_)
3912+ State* s = states_.template Push<State>(count);
3913+ memcpy(s, &GetState(src->minIndex), count * sizeof(State));
3914+ for (SizeType j = 0; j < count; j++) {
3915+ if (s[j].out != kRegexInvalidState)
3916+ s[j].out += count;
3917+ if (s[j].out1 != kRegexInvalidState)
3918+ s[j].out1 += count;
3919+ }
3920+ *operandStack.template Push<Frag>() = Frag(src->start + count, src->out + count, src->minIndex + count);
3921+ stateCount_ += count;
3922+ }
3923+
3924+ template <typename InputStream>
3925+ bool ParseUnsigned(DecodedStream<InputStream>& ds, unsigned* u) {
3926+ unsigned r = 0;
3927+ if (ds.Peek() < '0' || ds.Peek() > '9')
3928+ return false;
3929+ while (ds.Peek() >= '0' && ds.Peek() <= '9') {
3930+ if (r >= 429496729 && ds.Peek() > '5') // 2^32 - 1 = 4294967295
3931+ return false; // overflow
3932+ r = r * 10 + (ds.Take() - '0');
3933+ }
3934+ *u = r;
3935+ return true;
3936+ }
3937+
3938+ template <typename InputStream>
3939+ bool ParseRange(DecodedStream<InputStream>& ds, SizeType* range) {
3940+ bool isBegin = true;
3941+ bool negate = false;
3942+ int step = 0;
3943+ SizeType start = kRegexInvalidRange;
3944+ SizeType current = kRegexInvalidRange;
3945+ unsigned codepoint;
3946+ while ((codepoint = ds.Take()) != 0) {
3947+ if (isBegin) {
3948+ isBegin = false;
3949+ if (codepoint == '^') {
3950+ negate = true;
3951+ continue;
3952+ }
3953+ }
3954+
3955+ switch (codepoint) {
3956+ case ']':
3957+ if (start == kRegexInvalidRange)
3958+ return false; // Error: nothing inside []
3959+ if (step == 2) { // Add trailing '-'
3960+ SizeType r = NewRange('-');
3961+ RAPIDJSON_ASSERT(current != kRegexInvalidRange);
3962+ GetRange(current).next = r;
3963+ }
3964+ if (negate)
3965+ GetRange(start).start |= kRangeNegationFlag;
3966+ *range = start;
3967+ return true;
3968+
3969+ case '\\':
3970+ if (ds.Peek() == 'b') {
3971+ ds.Take();
3972+ codepoint = 0x0008; // Escape backspace character
3973+ }
3974+ else if (!CharacterEscape(ds, &codepoint))
3975+ return false;
3976+ // fall through to default
3977+
3978+ default:
3979+ switch (step) {
3980+ case 1:
3981+ if (codepoint == '-') {
3982+ step++;
3983+ break;
3984+ }
3985+ // fall through to step 0 for other characters
3986+
3987+ case 0:
3988+ {
3989+ SizeType r = NewRange(codepoint);
3990+ if (current != kRegexInvalidRange)
3991+ GetRange(current).next = r;
3992+ if (start == kRegexInvalidRange)
3993+ start = r;
3994+ current = r;
3995+ }
3996+ step = 1;
3997+ break;
3998+
3999+ default:
4000+ RAPIDJSON_ASSERT(step == 2);
4001+ GetRange(current).end = codepoint;
4002+ step = 0;
4003+ }
4004+ }
4005+ }
4006+ return false;
4007+ }
4008+
4009+ SizeType NewRange(unsigned codepoint) {
4010+ Range* r = ranges_.template Push<Range>();
4011+ r->start = r->end = codepoint;
4012+ r->next = kRegexInvalidRange;
4013+ return rangeCount_++;
4014+ }
4015+
4016+ template <typename InputStream>
4017+ bool CharacterEscape(DecodedStream<InputStream>& ds, unsigned* escapedCodepoint) {
4018+ unsigned codepoint;
4019+ switch (codepoint = ds.Take()) {
4020+ case '^':
4021+ case '$':
4022+ case '|':
4023+ case '(':
4024+ case ')':
4025+ case '?':
4026+ case '*':
4027+ case '+':
4028+ case '.':
4029+ case '[':
4030+ case ']':
4031+ case '{':
4032+ case '}':
4033+ case '\\':
4034+ *escapedCodepoint = codepoint; return true;
4035+ case 'f': *escapedCodepoint = 0x000C; return true;
4036+ case 'n': *escapedCodepoint = 0x000A; return true;
4037+ case 'r': *escapedCodepoint = 0x000D; return true;
4038+ case 't': *escapedCodepoint = 0x0009; return true;
4039+ case 'v': *escapedCodepoint = 0x000B; return true;
4040+ default:
4041+ return false; // Unsupported escape character
4042+ }
4043+ }
4044+
4045+ template <typename InputStream>
4046+ bool SearchWithAnchoring(InputStream& is, bool anchorBegin, bool anchorEnd) const {
4047+ RAPIDJSON_ASSERT(IsValid());
4048+ DecodedStream<InputStream> ds(is);
4049+
4050+ state0_.Clear();
4051+ Stack<Allocator> *current = &state0_, *next = &state1_;
4052+ const size_t stateSetSize = GetStateSetSize();
4053+ std::memset(stateSet_, 0, stateSetSize);
4054+
4055+ bool matched = AddState(*current, root_);
4056+ unsigned codepoint;
4057+ while (!current->Empty() && (codepoint = ds.Take()) != 0) {
4058+ std::memset(stateSet_, 0, stateSetSize);
4059+ next->Clear();
4060+ matched = false;
4061+ for (const SizeType* s = current->template Bottom<SizeType>(); s != current->template End<SizeType>(); ++s) {
4062+ const State& sr = GetState(*s);
4063+ if (sr.codepoint == codepoint ||
4064+ sr.codepoint == kAnyCharacterClass ||
4065+ (sr.codepoint == kRangeCharacterClass && MatchRange(sr.rangeStart, codepoint)))
4066+ {
4067+ matched = AddState(*next, sr.out) || matched;
4068+ if (!anchorEnd && matched)
4069+ return true;
4070+ }
4071+ if (!anchorBegin)
4072+ AddState(*next, root_);
4073+ }
4074+ internal::Swap(current, next);
4075+ }
4076+
4077+ return matched;
4078+ }
4079+
4080+ size_t GetStateSetSize() const {
4081+ return (stateCount_ + 31) / 32 * 4;
4082+ }
4083+
4084+ // Return whether the added states is a match state
4085+ bool AddState(Stack<Allocator>& l, SizeType index) const {
4086+ if (index == kRegexInvalidState)
4087+ return true;
4088+
4089+ const State& s = GetState(index);
4090+ if (s.out1 != kRegexInvalidState) { // Split
4091+ bool matched = AddState(l, s.out);
4092+ return AddState(l, s.out1) || matched;
4093+ }
4094+ else if (!(stateSet_[index >> 5] & (1 << (index & 31)))) {
4095+ stateSet_[index >> 5] |= (1 << (index & 31));
4096+ *l.template PushUnsafe<SizeType>() = index;
4097+ }
4098+ return s.out == kRegexInvalidState; // by using PushUnsafe() above, we can ensure s is not validated due to reallocation.
4099+ }
4100+
4101+ bool MatchRange(SizeType rangeIndex, unsigned codepoint) const {
4102+ bool yes = (GetRange(rangeIndex).start & kRangeNegationFlag) == 0;
4103+ while (rangeIndex != kRegexInvalidRange) {
4104+ const Range& r = GetRange(rangeIndex);
4105+ if (codepoint >= (r.start & ~kRangeNegationFlag) && codepoint <= r.end)
4106+ return yes;
4107+ rangeIndex = r.next;
4108+ }
4109+ return !yes;
4110+ }
4111+
4112+ Stack<Allocator> states_;
4113+ Stack<Allocator> ranges_;
4114+ SizeType root_;
4115+ SizeType stateCount_;
4116+ SizeType rangeCount_;
4117+
4118+ static const unsigned kInfinityQuantifier = ~0u;
4119+
4120+ // For SearchWithAnchoring()
4121+ uint32_t* stateSet_; // allocated by states_.GetAllocator()
4122+ mutable Stack<Allocator> state0_;
4123+ mutable Stack<Allocator> state1_;
4124+ bool anchorBegin_;
4125+ bool anchorEnd_;
4126+};
4127+
4128+typedef GenericRegex<UTF8<> > Regex;
4129+
4130+} // namespace internal
4131+RAPIDJSON_NAMESPACE_END
4132+
4133+#ifdef __clang__
4134+RAPIDJSON_DIAG_POP
4135+#endif
4136+
4137+#ifdef _MSC_VER
4138+RAPIDJSON_DIAG_POP
4139+#endif
4140+
4141+#endif // RAPIDJSON_INTERNAL_REGEX_H_
4142
4143=== modified file 'shorts/xml2json/rapidjson/internal/stack.h'
4144--- shorts/xml2json/rapidjson/internal/stack.h 2016-03-04 13:27:57 +0000
4145+++ shorts/xml2json/rapidjson/internal/stack.h 2016-06-15 16:13:25 +0000
4146@@ -15,9 +15,14 @@
4147 #ifndef RAPIDJSON_INTERNAL_STACK_H_
4148 #define RAPIDJSON_INTERNAL_STACK_H_
4149
4150-#include "../rapidjson.h"
4151+#include "../allocators.h"
4152 #include "swap.h"
4153
4154+#if defined(__clang__)
4155+RAPIDJSON_DIAG_PUSH
4156+RAPIDJSON_DIAG_OFF(c++98-compat)
4157+#endif
4158+
4159 RAPIDJSON_NAMESPACE_BEGIN
4160 namespace internal {
4161
4162@@ -33,7 +38,6 @@
4163 // Optimization note: Do not allocate memory for stack_ in constructor.
4164 // Do it lazily when first Push() -> Expand() -> Resize().
4165 Stack(Allocator* allocator, size_t stackCapacity) : allocator_(allocator), ownAllocator_(0), stack_(0), stackTop_(0), stackEnd_(0), initialCapacity_(stackCapacity) {
4166- RAPIDJSON_ASSERT(stackCapacity > 0);
4167 }
4168
4169 #if RAPIDJSON_HAS_CXX11_RVALUE_REFS
4170@@ -108,11 +112,21 @@
4171 // Optimization note: try to minimize the size of this function for force inline.
4172 // Expansion is run very infrequently, so it is moved to another (probably non-inline) function.
4173 template<typename T>
4174- RAPIDJSON_FORCEINLINE T* Push(size_t count = 1) {
4175+ RAPIDJSON_FORCEINLINE void Reserve(size_t count = 1) {
4176 // Expand the stack if needed
4177- if (stackTop_ + sizeof(T) * count >= stackEnd_)
4178+ if (RAPIDJSON_UNLIKELY(stackTop_ + sizeof(T) * count > stackEnd_))
4179 Expand<T>(count);
4180-
4181+ }
4182+
4183+ template<typename T>
4184+ RAPIDJSON_FORCEINLINE T* Push(size_t count = 1) {
4185+ Reserve<T>(count);
4186+ return PushUnsafe<T>(count);
4187+ }
4188+
4189+ template<typename T>
4190+ RAPIDJSON_FORCEINLINE T* PushUnsafe(size_t count = 1) {
4191+ RAPIDJSON_ASSERT(stackTop_ + sizeof(T) * count <= stackEnd_);
4192 T* ret = reinterpret_cast<T*>(stackTop_);
4193 stackTop_ += sizeof(T) * count;
4194 return ret;
4195@@ -132,8 +146,23 @@
4196 }
4197
4198 template<typename T>
4199+ const T* Top() const {
4200+ RAPIDJSON_ASSERT(GetSize() >= sizeof(T));
4201+ return reinterpret_cast<T*>(stackTop_ - sizeof(T));
4202+ }
4203+
4204+ template<typename T>
4205+ T* End() { return reinterpret_cast<T*>(stackTop_); }
4206+
4207+ template<typename T>
4208+ const T* End() const { return reinterpret_cast<T*>(stackTop_); }
4209+
4210+ template<typename T>
4211 T* Bottom() { return reinterpret_cast<T*>(stack_); }
4212
4213+ template<typename T>
4214+ const T* Bottom() const { return reinterpret_cast<T*>(stack_); }
4215+
4216 bool HasAllocator() const {
4217 return allocator_ != 0;
4218 }
4219@@ -142,6 +171,7 @@
4220 RAPIDJSON_ASSERT(allocator_);
4221 return *allocator_;
4222 }
4223+
4224 bool Empty() const { return stackTop_ == stack_; }
4225 size_t GetSize() const { return static_cast<size_t>(stackTop_ - stack_); }
4226 size_t GetCapacity() const { return static_cast<size_t>(stackEnd_ - stack_); }
4227@@ -193,4 +223,8 @@
4228 } // namespace internal
4229 RAPIDJSON_NAMESPACE_END
4230
4231+#if defined(__clang__)
4232+RAPIDJSON_DIAG_POP
4233+#endif
4234+
4235 #endif // RAPIDJSON_STACK_H_
4236
4237=== modified file 'shorts/xml2json/rapidjson/internal/strfunc.h'
4238--- shorts/xml2json/rapidjson/internal/strfunc.h 2016-03-04 13:27:57 +0000
4239+++ shorts/xml2json/rapidjson/internal/strfunc.h 2016-06-15 16:13:25 +0000
4240@@ -15,7 +15,7 @@
4241 #ifndef RAPIDJSON_INTERNAL_STRFUNC_H_
4242 #define RAPIDJSON_INTERNAL_STRFUNC_H_
4243
4244-#include "../rapidjson.h"
4245+#include "../stream.h"
4246
4247 RAPIDJSON_NAMESPACE_BEGIN
4248 namespace internal {
4249@@ -33,6 +33,22 @@
4250 return SizeType(p - s);
4251 }
4252
4253+//! Returns number of code points in a encoded string.
4254+template<typename Encoding>
4255+bool CountStringCodePoint(const typename Encoding::Ch* s, SizeType length, SizeType* outCount) {
4256+ GenericStringStream<Encoding> is(s);
4257+ const typename Encoding::Ch* end = s + length;
4258+ SizeType count = 0;
4259+ while (is.src_ < end) {
4260+ unsigned codepoint;
4261+ if (!Encoding::Decode(is, &codepoint))
4262+ return false;
4263+ count++;
4264+ }
4265+ *outCount = count;
4266+ return true;
4267+}
4268+
4269 } // namespace internal
4270 RAPIDJSON_NAMESPACE_END
4271
4272
4273=== modified file 'shorts/xml2json/rapidjson/internal/strtod.h'
4274--- shorts/xml2json/rapidjson/internal/strtod.h 2016-03-04 13:27:57 +0000
4275+++ shorts/xml2json/rapidjson/internal/strtod.h 2016-06-15 16:13:25 +0000
4276@@ -15,7 +15,6 @@
4277 #ifndef RAPIDJSON_STRTOD_
4278 #define RAPIDJSON_STRTOD_
4279
4280-#include "../rapidjson.h"
4281 #include "ieee754.h"
4282 #include "biginteger.h"
4283 #include "diyfp.h"
4284
4285=== modified file 'shorts/xml2json/rapidjson/internal/swap.h'
4286--- shorts/xml2json/rapidjson/internal/swap.h 2016-03-04 13:27:57 +0000
4287+++ shorts/xml2json/rapidjson/internal/swap.h 2016-06-15 16:13:25 +0000
4288@@ -17,6 +17,11 @@
4289
4290 #include "../rapidjson.h"
4291
4292+#if defined(__clang__)
4293+RAPIDJSON_DIAG_PUSH
4294+RAPIDJSON_DIAG_OFF(c++98-compat)
4295+#endif
4296+
4297 RAPIDJSON_NAMESPACE_BEGIN
4298 namespace internal {
4299
4300@@ -34,4 +39,8 @@
4301 } // namespace internal
4302 RAPIDJSON_NAMESPACE_END
4303
4304+#if defined(__clang__)
4305+RAPIDJSON_DIAG_POP
4306+#endif
4307+
4308 #endif // RAPIDJSON_INTERNAL_SWAP_H_
4309
4310=== added file 'shorts/xml2json/rapidjson/istreamwrapper.h'
4311--- shorts/xml2json/rapidjson/istreamwrapper.h 1970-01-01 00:00:00 +0000
4312+++ shorts/xml2json/rapidjson/istreamwrapper.h 2016-06-15 16:13:25 +0000
4313@@ -0,0 +1,110 @@
4314+// Tencent is pleased to support the open source community by making RapidJSON available.
4315+//
4316+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
4317+//
4318+// Licensed under the MIT License (the "License"); you may not use this file except
4319+// in compliance with the License. You may obtain a copy of the License at
4320+//
4321+// http://opensource.org/licenses/MIT
4322+//
4323+// Unless required by applicable law or agreed to in writing, software distributed
4324+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
4325+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
4326+// specific language governing permissions and limitations under the License.
4327+
4328+#include "stream.h"
4329+#include <iosfwd>
4330+
4331+#ifdef __clang__
4332+RAPIDJSON_DIAG_PUSH
4333+RAPIDJSON_DIAG_OFF(padded)
4334+#endif
4335+
4336+#ifdef _MSC_VER
4337+RAPIDJSON_DIAG_PUSH
4338+RAPIDJSON_DIAG_OFF(4351) // new behavior: elements of array 'array' will be default initialized
4339+#endif
4340+
4341+RAPIDJSON_NAMESPACE_BEGIN
4342+
4343+//! Wrapper of \c std::basic_istream into RapidJSON's Stream concept.
4344+/*!
4345+ The classes can be wrapped including but not limited to:
4346+
4347+ - \c std::istringstream
4348+ - \c std::stringstream
4349+ - \c std::wistringstream
4350+ - \c std::wstringstream
4351+ - \c std::ifstream
4352+ - \c std::fstream
4353+ - \c std::wifstream
4354+ - \c std::wfstream
4355+
4356+ \tparam StreamType Class derived from \c std::basic_istream.
4357+*/
4358+
4359+template <typename StreamType>
4360+class BasicIStreamWrapper {
4361+public:
4362+ typedef typename StreamType::char_type Ch;
4363+ BasicIStreamWrapper(StreamType& stream) : stream_(stream), count_(), peekBuffer_() {}
4364+
4365+ Ch Peek() const {
4366+ typename StreamType::int_type c = stream_.peek();
4367+ return RAPIDJSON_LIKELY(c != StreamType::traits_type::eof()) ? static_cast<Ch>(c) : '\0';
4368+ }
4369+
4370+ Ch Take() {
4371+ typename StreamType::int_type c = stream_.get();
4372+ if (RAPIDJSON_LIKELY(c != StreamType::traits_type::eof())) {
4373+ count_++;
4374+ return static_cast<Ch>(c);
4375+ }
4376+ else
4377+ return '\0';
4378+ }
4379+
4380+ // tellg() may return -1 when failed. So we count by ourself.
4381+ size_t Tell() const { return count_; }
4382+
4383+ Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
4384+ void Put(Ch) { RAPIDJSON_ASSERT(false); }
4385+ void Flush() { RAPIDJSON_ASSERT(false); }
4386+ size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
4387+
4388+ // For encoding detection only.
4389+ const Ch* Peek4() const {
4390+ RAPIDJSON_ASSERT(sizeof(Ch) == 1); // Only usable for byte stream.
4391+ int i;
4392+ bool hasError = false;
4393+ for (i = 0; i < 4; ++i) {
4394+ typename StreamType::int_type c = stream_.get();
4395+ if (c == StreamType::traits_type::eof()) {
4396+ hasError = true;
4397+ stream_.clear();
4398+ break;
4399+ }
4400+ peekBuffer_[i] = static_cast<Ch>(c);
4401+ }
4402+ for (--i; i >= 0; --i)
4403+ stream_.putback(peekBuffer_[i]);
4404+ return !hasError ? peekBuffer_ : 0;
4405+ }
4406+
4407+private:
4408+ BasicIStreamWrapper(const BasicIStreamWrapper&);
4409+ BasicIStreamWrapper& operator=(const BasicIStreamWrapper&);
4410+
4411+ StreamType& stream_;
4412+ size_t count_; //!< Number of characters read. Note:
4413+ mutable Ch peekBuffer_[4];
4414+};
4415+
4416+typedef BasicIStreamWrapper<std::istream> IStreamWrapper;
4417+typedef BasicIStreamWrapper<std::wistream> WIStreamWrapper;
4418+
4419+#if defined(__clang__) || defined(_MSC_VER)
4420+RAPIDJSON_DIAG_POP
4421+#endif
4422+
4423+RAPIDJSON_NAMESPACE_END
4424
4425=== modified file 'shorts/xml2json/rapidjson/memorybuffer.h'
4426--- shorts/xml2json/rapidjson/memorybuffer.h 2016-03-04 13:27:57 +0000
4427+++ shorts/xml2json/rapidjson/memorybuffer.h 2016-06-15 16:13:25 +0000
4428@@ -15,7 +15,7 @@
4429 #ifndef RAPIDJSON_MEMORYBUFFER_H_
4430 #define RAPIDJSON_MEMORYBUFFER_H_
4431
4432-#include "rapidjson.h"
4433+#include "stream.h"
4434 #include "internal/stack.h"
4435
4436 RAPIDJSON_NAMESPACE_BEGIN
4437
4438=== modified file 'shorts/xml2json/rapidjson/memorystream.h'
4439--- shorts/xml2json/rapidjson/memorystream.h 2016-03-04 13:27:57 +0000
4440+++ shorts/xml2json/rapidjson/memorystream.h 2016-06-15 16:13:25 +0000
4441@@ -15,7 +15,7 @@
4442 #ifndef RAPIDJSON_MEMORYSTREAM_H_
4443 #define RAPIDJSON_MEMORYSTREAM_H_
4444
4445-#include "rapidjson.h"
4446+#include "stream.h"
4447
4448 #ifdef __clang__
4449 RAPIDJSON_DIAG_PUSH
4450@@ -42,8 +42,8 @@
4451
4452 MemoryStream(const Ch *src, size_t size) : src_(src), begin_(src), end_(src + size), size_(size) {}
4453
4454- Ch Peek() const { return (src_ == end_) ? '\0' : *src_; }
4455- Ch Take() { return (src_ == end_) ? '\0' : *src_++; }
4456+ Ch Peek() const { return RAPIDJSON_UNLIKELY(src_ == end_) ? '\0' : *src_; }
4457+ Ch Take() { return RAPIDJSON_UNLIKELY(src_ == end_) ? '\0' : *src_++; }
4458 size_t Tell() const { return static_cast<size_t>(src_ - begin_); }
4459
4460 Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
4461
4462=== added file 'shorts/xml2json/rapidjson/ostreamwrapper.h'
4463--- shorts/xml2json/rapidjson/ostreamwrapper.h 1970-01-01 00:00:00 +0000
4464+++ shorts/xml2json/rapidjson/ostreamwrapper.h 2016-06-15 16:13:25 +0000
4465@@ -0,0 +1,76 @@
4466+// Tencent is pleased to support the open source community by making RapidJSON available.
4467+//
4468+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
4469+//
4470+// Licensed under the MIT License (the "License"); you may not use this file except
4471+// in compliance with the License. You may obtain a copy of the License at
4472+//
4473+// http://opensource.org/licenses/MIT
4474+//
4475+// Unless required by applicable law or agreed to in writing, software distributed
4476+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
4477+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
4478+// specific language governing permissions and limitations under the License.
4479+
4480+#include "stream.h"
4481+#include <iosfwd>
4482+
4483+#ifdef __clang__
4484+RAPIDJSON_DIAG_PUSH
4485+RAPIDJSON_DIAG_OFF(padded)
4486+#endif
4487+
4488+RAPIDJSON_NAMESPACE_BEGIN
4489+
4490+//! Wrapper of \c std::basic_ostream into RapidJSON's Stream concept.
4491+/*!
4492+ The classes can be wrapped including but not limited to:
4493+
4494+ - \c std::ostringstream
4495+ - \c std::stringstream
4496+ - \c std::wpstringstream
4497+ - \c std::wstringstream
4498+ - \c std::ifstream
4499+ - \c std::fstream
4500+ - \c std::wofstream
4501+ - \c std::wfstream
4502+
4503+ \tparam StreamType Class derived from \c std::basic_ostream.
4504+*/
4505+
4506+template <typename StreamType>
4507+class BasicOStreamWrapper {
4508+public:
4509+ typedef typename StreamType::char_type Ch;
4510+ BasicOStreamWrapper(StreamType& stream) : stream_(stream) {}
4511+
4512+ void Put(Ch c) {
4513+ stream_.put(c);
4514+ }
4515+
4516+ void Flush() {
4517+ stream_.flush();
4518+ }
4519+
4520+ // Not implemented
4521+ char Peek() const { RAPIDJSON_ASSERT(false); return 0; }
4522+ char Take() { RAPIDJSON_ASSERT(false); return 0; }
4523+ size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; }
4524+ char* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
4525+ size_t PutEnd(char*) { RAPIDJSON_ASSERT(false); return 0; }
4526+
4527+private:
4528+ BasicOStreamWrapper(const BasicOStreamWrapper&);
4529+ BasicOStreamWrapper& operator=(const BasicOStreamWrapper&);
4530+
4531+ StreamType& stream_;
4532+};
4533+
4534+typedef BasicOStreamWrapper<std::ostream> OStreamWrapper;
4535+typedef BasicOStreamWrapper<std::wostream> WOStreamWrapper;
4536+
4537+#ifdef __clang__
4538+RAPIDJSON_DIAG_POP
4539+#endif
4540+
4541+RAPIDJSON_NAMESPACE_END
4542
4543=== modified file 'shorts/xml2json/rapidjson/pointer.h'
4544--- shorts/xml2json/rapidjson/pointer.h 2016-03-04 13:27:57 +0000
4545+++ shorts/xml2json/rapidjson/pointer.h 2016-06-15 16:13:25 +0000
4546@@ -23,6 +23,11 @@
4547 RAPIDJSON_DIAG_OFF(switch-enum)
4548 #endif
4549
4550+#ifdef _MSC_VER
4551+RAPIDJSON_DIAG_PUSH
4552+RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated
4553+#endif
4554+
4555 RAPIDJSON_NAMESPACE_BEGIN
4556
4557 static const SizeType kPointerInvalidIndex = ~SizeType(0); //!< Represents an invalid index in GenericPointer::Token
4558@@ -101,7 +106,7 @@
4559 //@{
4560
4561 //! Default constructor.
4562- GenericPointer() : allocator_(), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) {}
4563+ GenericPointer(Allocator* allocator = 0) : allocator_(allocator), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) {}
4564
4565 //! Constructor that parses a string or URI fragment representation.
4566 /*!
4567@@ -160,7 +165,7 @@
4568 GenericPointer(const Token* tokens, size_t tokenCount) : allocator_(), ownAllocator_(), nameBuffer_(), tokens_(const_cast<Token*>(tokens)), tokenCount_(tokenCount), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) {}
4569
4570 //! Copy constructor.
4571- GenericPointer(const GenericPointer& rhs) : allocator_(), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) {
4572+ GenericPointer(const GenericPointer& rhs, Allocator* allocator = 0) : allocator_(allocator), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) {
4573 *this = rhs;
4574 }
4575
4576@@ -305,6 +310,9 @@
4577
4578 //@}
4579
4580+ //! Get the allocator of this pointer.
4581+ Allocator& GetAllocator() { return *allocator_; }
4582+
4583 //!@name Tokens
4584 //@{
4585
4586@@ -457,9 +465,18 @@
4587 //! Query a value in a subtree.
4588 /*!
4589 \param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root.
4590+ \param unresolvedTokenIndex If the pointer cannot resolve a token in the pointer, this parameter can obtain the index of unresolved token.
4591 \return Pointer to the value if it can be resolved. Otherwise null.
4592+
4593+ \note
4594+ There are only 3 situations when a value cannot be resolved:
4595+ 1. A value in the path is not an array nor object.
4596+ 2. An object value does not contain the token.
4597+ 3. A token is out of range of an array value.
4598+
4599+ Use unresolvedTokenIndex to retrieve the token index.
4600 */
4601- ValueType* Get(ValueType& root) const {
4602+ ValueType* Get(ValueType& root, size_t* unresolvedTokenIndex = 0) const {
4603 RAPIDJSON_ASSERT(IsValid());
4604 ValueType* v = &root;
4605 for (const Token *t = tokens_; t != tokens_ + tokenCount_; ++t) {
4606@@ -468,18 +485,23 @@
4607 {
4608 typename ValueType::MemberIterator m = v->FindMember(GenericStringRef<Ch>(t->name, t->length));
4609 if (m == v->MemberEnd())
4610- return 0;
4611+ break;
4612 v = &m->value;
4613 }
4614- break;
4615+ continue;
4616 case kArrayType:
4617 if (t->index == kPointerInvalidIndex || t->index >= v->Size())
4618- return 0;
4619+ break;
4620 v = &((*v)[t->index]);
4621- break;
4622+ continue;
4623 default:
4624- return 0;
4625+ break;
4626 }
4627+
4628+ // Error: unresolved token
4629+ if (unresolvedTokenIndex)
4630+ *unresolvedTokenIndex = static_cast<size_t>(t - tokens_);
4631+ return 0;
4632 }
4633 return v;
4634 }
4635@@ -489,7 +511,9 @@
4636 \param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root.
4637 \return Pointer to the value if it can be resolved. Otherwise null.
4638 */
4639- const ValueType* Get(const ValueType& root) const { return Get(const_cast<ValueType&>(root)); }
4640+ const ValueType* Get(const ValueType& root, size_t* unresolvedTokenIndex = 0) const {
4641+ return Get(const_cast<ValueType&>(root), unresolvedTokenIndex);
4642+ }
4643
4644 //@}
4645
4646@@ -968,11 +992,11 @@
4647 src_++;
4648 Ch c = 0;
4649 for (int j = 0; j < 2; j++) {
4650- c <<= 4;
4651+ c = static_cast<Ch>(c << 4);
4652 Ch h = *src_;
4653- if (h >= '0' && h <= '9') c += h - '0';
4654- else if (h >= 'A' && h <= 'F') c += h - 'A' + 10;
4655- else if (h >= 'a' && h <= 'f') c += h - 'a' + 10;
4656+ if (h >= '0' && h <= '9') c = static_cast<Ch>(c + h - '0');
4657+ else if (h >= 'A' && h <= 'F') c = static_cast<Ch>(c + h - 'A' + 10);
4658+ else if (h >= 'a' && h <= 'f') c = static_cast<Ch>(c + h - 'a' + 10);
4659 else {
4660 valid_ = false;
4661 return 0;
4662@@ -1050,23 +1074,23 @@
4663 //////////////////////////////////////////////////////////////////////////////
4664
4665 template <typename T>
4666-typename T::ValueType* GetValueByPointer(T& root, const GenericPointer<typename T::ValueType>& pointer) {
4667- return pointer.Get(root);
4668+typename T::ValueType* GetValueByPointer(T& root, const GenericPointer<typename T::ValueType>& pointer, size_t* unresolvedTokenIndex = 0) {
4669+ return pointer.Get(root, unresolvedTokenIndex);
4670 }
4671
4672 template <typename T>
4673-const typename T::ValueType* GetValueByPointer(const T& root, const GenericPointer<typename T::ValueType>& pointer) {
4674- return pointer.Get(root);
4675-}
4676-
4677-template <typename T, typename CharType, size_t N>
4678-typename T::ValueType* GetValueByPointer(T& root, const CharType (&source)[N]) {
4679- return GenericPointer<typename T::ValueType>(source, N - 1).Get(root);
4680-}
4681-
4682-template <typename T, typename CharType, size_t N>
4683-const typename T::ValueType* GetValueByPointer(const T& root, const CharType(&source)[N]) {
4684- return GenericPointer<typename T::ValueType>(source, N - 1).Get(root);
4685+const typename T::ValueType* GetValueByPointer(const T& root, const GenericPointer<typename T::ValueType>& pointer, size_t* unresolvedTokenIndex = 0) {
4686+ return pointer.Get(root, unresolvedTokenIndex);
4687+}
4688+
4689+template <typename T, typename CharType, size_t N>
4690+typename T::ValueType* GetValueByPointer(T& root, const CharType (&source)[N], size_t* unresolvedTokenIndex = 0) {
4691+ return GenericPointer<typename T::ValueType>(source, N - 1).Get(root, unresolvedTokenIndex);
4692+}
4693+
4694+template <typename T, typename CharType, size_t N>
4695+const typename T::ValueType* GetValueByPointer(const T& root, const CharType(&source)[N], size_t* unresolvedTokenIndex = 0) {
4696+ return GenericPointer<typename T::ValueType>(source, N - 1).Get(root, unresolvedTokenIndex);
4697 }
4698
4699 //////////////////////////////////////////////////////////////////////////////
4700@@ -1323,4 +1347,8 @@
4701 RAPIDJSON_DIAG_POP
4702 #endif
4703
4704+#ifdef _MSC_VER
4705+RAPIDJSON_DIAG_POP
4706+#endif
4707+
4708 #endif // RAPIDJSON_POINTER_H_
4709
4710=== modified file 'shorts/xml2json/rapidjson/prettywriter.h'
4711--- shorts/xml2json/rapidjson/prettywriter.h 2016-03-04 13:27:57 +0000
4712+++ shorts/xml2json/rapidjson/prettywriter.h 2016-06-15 16:13:25 +0000
4713@@ -24,6 +24,14 @@
4714
4715 RAPIDJSON_NAMESPACE_BEGIN
4716
4717+//! Combination of PrettyWriter format flags.
4718+/*! \see PrettyWriter::SetFormatOptions
4719+ */
4720+enum PrettyFormatOptions {
4721+ kFormatDefault = 0, //!< Default pretty formatting.
4722+ kFormatSingleLineArray = 1 //!< Format arrays on a single line.
4723+};
4724+
4725 //! Writer with indentation and spacing.
4726 /*!
4727 \tparam OutputStream Type of ouptut os.
4728@@ -31,8 +39,8 @@
4729 \tparam TargetEncoding Encoding of output stream.
4730 \tparam StackAllocator Type of allocator for allocating memory of stack.
4731 */
4732-template<typename OutputStream, typename SourceEncoding = UTF8<>, typename TargetEncoding = UTF8<>, typename StackAllocator = CrtAllocator>
4733-class PrettyWriter : public Writer<OutputStream, SourceEncoding, TargetEncoding, StackAllocator> {
4734+template<typename OutputStream, typename SourceEncoding = UTF8<>, typename TargetEncoding = UTF8<>, typename StackAllocator = CrtAllocator, unsigned writeFlags = kWriteDefaultFlags>
4735+class PrettyWriter : public Writer<OutputStream, SourceEncoding, TargetEncoding, StackAllocator, writeFlags> {
4736 public:
4737 typedef Writer<OutputStream, SourceEncoding, TargetEncoding, StackAllocator> Base;
4738 typedef typename Base::Ch Ch;
4739@@ -42,8 +50,12 @@
4740 \param allocator User supplied allocator. If it is null, it will create a private one.
4741 \param levelDepth Initial capacity of stack.
4742 */
4743- PrettyWriter(OutputStream& os, StackAllocator* allocator = 0, size_t levelDepth = Base::kDefaultLevelDepth) :
4744- Base(os, allocator, levelDepth), indentChar_(' '), indentCharCount_(4) {}
4745+ explicit PrettyWriter(OutputStream& os, StackAllocator* allocator = 0, size_t levelDepth = Base::kDefaultLevelDepth) :
4746+ Base(os, allocator, levelDepth), indentChar_(' '), indentCharCount_(4), formatOptions_(kFormatDefault) {}
4747+
4748+
4749+ explicit PrettyWriter(StackAllocator* allocator = 0, size_t levelDepth = Base::kDefaultLevelDepth) :
4750+ Base(allocator, levelDepth), indentChar_(' '), indentCharCount_(4) {}
4751
4752 //! Set custom indentation.
4753 /*! \param indentChar Character for indentation. Must be whitespace character (' ', '\\t', '\\n', '\\r').
4754@@ -57,6 +69,14 @@
4755 return *this;
4756 }
4757
4758+ //! Set pretty writer formatting options.
4759+ /*! \param options Formatting options.
4760+ */
4761+ PrettyWriter& SetFormatOptions(PrettyFormatOptions options) {
4762+ formatOptions_ = options;
4763+ return *this;
4764+ }
4765+
4766 /*! @name Implementation of Handler
4767 \see Handler
4768 */
4769@@ -70,6 +90,12 @@
4770 bool Uint64(uint64_t u64) { PrettyPrefix(kNumberType); return Base::WriteUint64(u64); }
4771 bool Double(double d) { PrettyPrefix(kNumberType); return Base::WriteDouble(d); }
4772
4773+ bool RawNumber(const Ch* str, SizeType length, bool copy = false) {
4774+ (void)copy;
4775+ PrettyPrefix(kNumberType);
4776+ return Base::WriteString(str, length);
4777+ }
4778+
4779 bool String(const Ch* str, SizeType length, bool copy = false) {
4780 (void)copy;
4781 PrettyPrefix(kStringType);
4782@@ -120,7 +146,7 @@
4783 RAPIDJSON_ASSERT(Base::level_stack_.template Top<typename Base::Level>()->inArray);
4784 bool empty = Base::level_stack_.template Pop<typename Base::Level>(1)->valueCount == 0;
4785
4786- if (!empty) {
4787+ if (!empty && !(formatOptions_ & kFormatSingleLineArray)) {
4788 Base::os_->Put('\n');
4789 WriteIndent();
4790 }
4791@@ -142,6 +168,18 @@
4792 bool Key(const Ch* str) { return Key(str, internal::StrLen(str)); }
4793
4794 //@}
4795+
4796+ //! Write a raw JSON value.
4797+ /*!
4798+ For user to write a stringified JSON as a value.
4799+
4800+ \param json A well-formed JSON value. It should not contain null character within [0, length - 1] range.
4801+ \param length Length of the json.
4802+ \param type Type of the root of json.
4803+ \note When using PrettyWriter::RawValue(), the result json may not be indented correctly.
4804+ */
4805+ bool RawValue(const Ch* json, size_t length, Type type) { PrettyPrefix(type); return Base::WriteRawValue(json, length); }
4806+
4807 protected:
4808 void PrettyPrefix(Type type) {
4809 (void)type;
4810@@ -151,11 +189,14 @@
4811 if (level->inArray) {
4812 if (level->valueCount > 0) {
4813 Base::os_->Put(','); // add comma if it is not the first element in array
4814- Base::os_->Put('\n');
4815- }
4816- else
4817- Base::os_->Put('\n');
4818- WriteIndent();
4819+ if (formatOptions_ & kFormatSingleLineArray)
4820+ Base::os_->Put(' ');
4821+ }
4822+
4823+ if (!(formatOptions_ & kFormatSingleLineArray)) {
4824+ Base::os_->Put('\n');
4825+ WriteIndent();
4826+ }
4827 }
4828 else { // in object
4829 if (level->valueCount > 0) {
4830@@ -191,6 +232,7 @@
4831
4832 Ch indentChar_;
4833 unsigned indentCharCount_;
4834+ PrettyFormatOptions formatOptions_;
4835
4836 private:
4837 // Prohibit copy constructor & assignment operator.
4838
4839=== modified file 'shorts/xml2json/rapidjson/rapidjson.h'
4840--- shorts/xml2json/rapidjson/rapidjson.h 2016-03-04 13:27:57 +0000
4841+++ shorts/xml2json/rapidjson/rapidjson.h 2016-06-15 16:13:25 +0000
4842@@ -159,7 +159,7 @@
4843 */
4844 #ifndef RAPIDJSON_NO_INT64DEFINE
4845 //!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN
4846-#ifdef _MSC_VER
4847+#if defined(_MSC_VER) && (_MSC_VER < 1800) // Visual Studio 2013
4848 #include "msinttypes/stdint.h"
4849 #include "msinttypes/inttypes.h"
4850 #else
4851@@ -178,9 +178,9 @@
4852
4853 #ifndef RAPIDJSON_FORCEINLINE
4854 //!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN
4855-#if defined(_MSC_VER) && !defined(NDEBUG)
4856+#if defined(_MSC_VER) && defined(NDEBUG)
4857 #define RAPIDJSON_FORCEINLINE __forceinline
4858-#elif defined(__GNUC__) && __GNUC__ >= 4 && !defined(NDEBUG)
4859+#elif defined(__GNUC__) && __GNUC__ >= 4 && defined(NDEBUG)
4860 #define RAPIDJSON_FORCEINLINE __attribute__((always_inline))
4861 #else
4862 #define RAPIDJSON_FORCEINLINE
4863@@ -265,7 +265,8 @@
4864 \param x pointer to align
4865
4866 Some machines require strict data alignment. Currently the default uses 4 bytes
4867- alignment. User can customize by defining the RAPIDJSON_ALIGN function macro.
4868+ alignment on 32-bit platforms and 8 bytes alignment for 64-bit platforms.
4869+ User can customize by defining the RAPIDJSON_ALIGN function macro.
4870 */
4871 #ifndef RAPIDJSON_ALIGN
4872 #if RAPIDJSON_64BIT == 1
4873@@ -289,6 +290,36 @@
4874 #endif
4875
4876 ///////////////////////////////////////////////////////////////////////////////
4877+// RAPIDJSON_48BITPOINTER_OPTIMIZATION
4878+
4879+//! Use only lower 48-bit address for some pointers.
4880+/*!
4881+ \ingroup RAPIDJSON_CONFIG
4882+
4883+ This optimization uses the fact that current X86-64 architecture only implement lower 48-bit virtual address.
4884+ The higher 16-bit can be used for storing other data.
4885+ \c GenericValue uses this optimization to reduce its size form 24 bytes to 16 bytes in 64-bit architecture.
4886+*/
4887+#ifndef RAPIDJSON_48BITPOINTER_OPTIMIZATION
4888+#if defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64) || defined(_M_X64) || defined(_M_AMD64)
4889+#define RAPIDJSON_48BITPOINTER_OPTIMIZATION 1
4890+#else
4891+#define RAPIDJSON_48BITPOINTER_OPTIMIZATION 0
4892+#endif
4893+#endif // RAPIDJSON_48BITPOINTER_OPTIMIZATION
4894+
4895+#if RAPIDJSON_48BITPOINTER_OPTIMIZATION == 1
4896+#if RAPIDJSON_64BIT != 1
4897+#error RAPIDJSON_48BITPOINTER_OPTIMIZATION can only be set to 1 when RAPIDJSON_64BIT=1
4898+#endif
4899+#define RAPIDJSON_SETPOINTER(type, p, x) (p = reinterpret_cast<type *>((reinterpret_cast<uintptr_t>(p) & static_cast<uintptr_t>(RAPIDJSON_UINT64_C2(0xFFFF0000, 0x00000000))) | reinterpret_cast<uintptr_t>(reinterpret_cast<const void*>(x))))
4900+#define RAPIDJSON_GETPOINTER(type, p) (reinterpret_cast<type *>(reinterpret_cast<uintptr_t>(p) & static_cast<uintptr_t>(RAPIDJSON_UINT64_C2(0x0000FFFF, 0xFFFFFFFF))))
4901+#else
4902+#define RAPIDJSON_SETPOINTER(type, p, x) (p = (x))
4903+#define RAPIDJSON_GETPOINTER(type, p) (p)
4904+#endif
4905+
4906+///////////////////////////////////////////////////////////////////////////////
4907 // RAPIDJSON_SSE2/RAPIDJSON_SSE42/RAPIDJSON_SIMD
4908
4909 /*! \def RAPIDJSON_SIMD
4910@@ -410,6 +441,35 @@
4911 #endif
4912
4913 ///////////////////////////////////////////////////////////////////////////////
4914+// RAPIDJSON_LIKELY, RAPIDJSON_UNLIKELY
4915+
4916+//! Compiler branching hint for expression with high probability to be true.
4917+/*!
4918+ \ingroup RAPIDJSON_CONFIG
4919+ \param x Boolean expression likely to be true.
4920+*/
4921+#ifndef RAPIDJSON_LIKELY
4922+#if defined(__GNUC__) || defined(__clang__)
4923+#define RAPIDJSON_LIKELY(x) __builtin_expect(!!(x), 1)
4924+#else
4925+#define RAPIDJSON_LIKELY(x) (x)
4926+#endif
4927+#endif
4928+
4929+//! Compiler branching hint for expression with low probability to be true.
4930+/*!
4931+ \ingroup RAPIDJSON_CONFIG
4932+ \param x Boolean expression unlikely to be true.
4933+*/
4934+#ifndef RAPIDJSON_UNLIKELY
4935+#if defined(__GNUC__) || defined(__clang__)
4936+#define RAPIDJSON_UNLIKELY(x) __builtin_expect(!!(x), 0)
4937+#else
4938+#define RAPIDJSON_UNLIKELY(x) (x)
4939+#endif
4940+#endif
4941+
4942+///////////////////////////////////////////////////////////////////////////////
4943 // Helpers
4944
4945 //!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN
4946@@ -501,6 +561,17 @@
4947 #define RAPIDJSON_HAS_CXX11_TYPETRAITS 0
4948 #endif
4949
4950+#ifndef RAPIDJSON_HAS_CXX11_RANGE_FOR
4951+#if defined(__clang__)
4952+#define RAPIDJSON_HAS_CXX11_RANGE_FOR __has_feature(cxx_range_for)
4953+#elif (defined(RAPIDJSON_GNUC) && (RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,3,0)) && defined(__GXX_EXPERIMENTAL_CXX0X__)) || \
4954+ (defined(_MSC_VER) && _MSC_VER >= 1700)
4955+#define RAPIDJSON_HAS_CXX11_RANGE_FOR 1
4956+#else
4957+#define RAPIDJSON_HAS_CXX11_RANGE_FOR 0
4958+#endif
4959+#endif // RAPIDJSON_HAS_CXX11_RANGE_FOR
4960+
4961 //!@endcond
4962
4963 ///////////////////////////////////////////////////////////////////////////////
4964@@ -516,10 +587,7 @@
4965 #endif
4966
4967 ///////////////////////////////////////////////////////////////////////////////
4968-// Allocators and Encodings
4969-
4970-#include "allocators.h"
4971-#include "encodings.h"
4972+// Type
4973
4974 /*! \namespace rapidjson
4975 \brief main RapidJSON namespace
4976@@ -527,148 +595,6 @@
4977 */
4978 RAPIDJSON_NAMESPACE_BEGIN
4979
4980-///////////////////////////////////////////////////////////////////////////////
4981-// Stream
4982-
4983-/*! \class rapidjson::Stream
4984- \brief Concept for reading and writing characters.
4985-
4986- For read-only stream, no need to implement PutBegin(), Put(), Flush() and PutEnd().
4987-
4988- For write-only stream, only need to implement Put() and Flush().
4989-
4990-\code
4991-concept Stream {
4992- typename Ch; //!< Character type of the stream.
4993-
4994- //! Read the current character from stream without moving the read cursor.
4995- Ch Peek() const;
4996-
4997- //! Read the current character from stream and moving the read cursor to next character.
4998- Ch Take();
4999-
5000- //! Get the current read cursor.
The diff has been truncated for viewing.

Subscribers

People subscribed via source and target branches