Merge lp:~qqworini/ubuntu-rssreader-app/add-non-google-support into lp:ubuntu-rssreader-app
- add-non-google-support
- Merge into reboot
Proposed by
Joey Chan
Status: | Merged |
---|---|
Approved by: | Roman Shchekin |
Approved revision: | 417 |
Merged at revision: | 415 |
Proposed branch: | lp:~qqworini/ubuntu-rssreader-app/add-non-google-support |
Merge into: | lp:ubuntu-rssreader-app |
Diff against target: |
14900 lines (+14343/-44) 52 files modified
shorts.apparmor (+3/-1) shorts/CMakeLists.txt (+1/-0) shorts/main.cpp (+5/-1) shorts/po/com.ubuntu.shorts.pot (+74/-34) shorts/qml/CMakeLists.txt (+1/-0) shorts/qml/components/NetworkManager.qml (+144/-2) shorts/qml/components/OptionsKeeper.qml (+19/-1) shorts/qml/nongoogle/AppendNGFeedPage.qml (+254/-0) shorts/qml/nongoogle/CMakeLists.txt (+6/-0) shorts/qml/nongoogle/Positioner.qml (+114/-0) shorts/qml/nongoogle/XmlNetwork.qml (+84/-0) shorts/qml/pages/PageSettings.qml (+62/-0) shorts/qml/shorts-app.qml (+56/-2) shorts/shorts.pro (+42/-3) shorts/shorts.qrc (+4/-0) shorts/xml2json/rapidjson/allocators.h (+245/-0) shorts/xml2json/rapidjson/document.h (+1969/-0) shorts/xml2json/rapidjson/encodedstream.h (+290/-0) shorts/xml2json/rapidjson/encodings.h (+630/-0) shorts/xml2json/rapidjson/error/en.h (+71/-0) shorts/xml2json/rapidjson/error/error.h (+150/-0) shorts/xml2json/rapidjson/filereadstream.h (+94/-0) shorts/xml2json/rapidjson/filestream.h (+73/-0) shorts/xml2json/rapidjson/filewritestream.h (+97/-0) shorts/xml2json/rapidjson/internal/biginteger.h (+294/-0) shorts/xml2json/rapidjson/internal/diyfp.h (+268/-0) shorts/xml2json/rapidjson/internal/dtoa.h (+225/-0) shorts/xml2json/rapidjson/internal/ieee754.h (+90/-0) shorts/xml2json/rapidjson/internal/itoa.h (+306/-0) shorts/xml2json/rapidjson/internal/meta.h (+189/-0) shorts/xml2json/rapidjson/internal/pow10.h (+59/-0) shorts/xml2json/rapidjson/internal/stack.h (+183/-0) shorts/xml2json/rapidjson/internal/strfunc.h (+43/-0) shorts/xml2json/rapidjson/internal/strtod.h (+285/-0) shorts/xml2json/rapidjson/memorybuffer.h (+76/-0) shorts/xml2json/rapidjson/memorystream.h (+67/-0) shorts/xml2json/rapidjson/msinttypes/inttypes.h (+312/-0) shorts/xml2json/rapidjson/msinttypes/stdint.h (+296/-0) shorts/xml2json/rapidjson/prettywriter.h (+211/-0) shorts/xml2json/rapidjson/rapidjson.h (+629/-0) shorts/xml2json/rapidjson/reader.h (+1444/-0) shorts/xml2json/rapidjson/stringbuffer.h (+99/-0) shorts/xml2json/rapidjson/writer.h (+401/-0) shorts/xml2json/rapidxml/license.txt (+52/-0) shorts/xml2json/rapidxml/manual.html (+406/-0) shorts/xml2json/rapidxml/rapidxml.hpp (+2924/-0) shorts/xml2json/rapidxml/rapidxml_iterators.hpp (+174/-0) shorts/xml2json/rapidxml/rapidxml_print.hpp (+425/-0) shorts/xml2json/rapidxml/rapidxml_utils.hpp (+122/-0) shorts/xml2json/utilities.cpp (+46/-0) shorts/xml2json/utilities.h (+24/-0) shorts/xml2json/xml2json.hpp (+205/-0) |
To merge this branch: | bzr merge lp:~qqworini/ubuntu-rssreader-app/add-non-google-support |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Roman Shchekin | Needs Fixing | ||
Jenkins Bot | continuous-integration | Approve | |
Review via email: mp+280614@code.launchpad.net |
Commit message
remove useless commented code
Description of the change
remove useless commented code
To post a comment you must log in.
Revision history for this message
Jenkins Bot (ubuntu-core-apps-jenkins-bot) wrote : | # |
review:
Approve
(continuous-integration)
Revision history for this message
Roman Shchekin (mrqtros) wrote : | # |
See inline comments.
review:
Needs Fixing
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'shorts.apparmor' |
2 | --- shorts.apparmor 2015-10-24 07:06:24 +0000 |
3 | +++ shorts.apparmor 2015-12-15 16:05:21 +0000 |
4 | @@ -1,7 +1,9 @@ |
5 | { |
6 | "policy_groups": [ |
7 | "networking", |
8 | - "content_exchange_source" |
9 | + "content_exchange_source", |
10 | + "content_exchange", |
11 | + "location" |
12 | ], |
13 | "policy_version": 1.3 |
14 | } |
15 | |
16 | === modified file 'shorts/CMakeLists.txt' |
17 | --- shorts/CMakeLists.txt 2015-08-11 12:07:22 +0000 |
18 | +++ shorts/CMakeLists.txt 2015-12-15 16:05:21 +0000 |
19 | @@ -5,6 +5,7 @@ |
20 | main.cpp |
21 | CachingNetworkManagerFactory.cpp |
22 | shorts.qrc |
23 | + xml2json/utilities.cpp |
24 | |
25 | ) |
26 | |
27 | |
28 | === modified file 'shorts/main.cpp' |
29 | --- shorts/main.cpp 2015-07-19 14:29:20 +0000 |
30 | +++ shorts/main.cpp 2015-12-15 16:05:21 +0000 |
31 | @@ -1,8 +1,9 @@ |
32 | #include <QGuiApplication> |
33 | #include <QQmlApplicationEngine> |
34 | -#include <QQuickView> |
35 | +#include <QtQuick> |
36 | |
37 | #include "CachingNetworkManagerFactory.h" |
38 | +#include "xml2json/utilities.h" |
39 | |
40 | int main(int argc, char *argv[]) |
41 | { |
42 | @@ -16,6 +17,9 @@ |
43 | CachingNetworkManagerFactory *managerFactory = new CachingNetworkManagerFactory(); |
44 | view.engine()->setNetworkAccessManagerFactory(managerFactory); |
45 | |
46 | + Utilities *utilities = new Utilities(); |
47 | + view.engine()->rootContext()->setContextProperty("utilities", utilities); |
48 | + |
49 | view.setSource(QUrl(QStringLiteral("qrc:///qml/shorts-app.qml"))); |
50 | // view.setSource(QUrl("./share/qml/shorts-app.qml")); |
51 | view.setResizeMode(QQuickView::SizeRootObjectToView); |
52 | |
53 | === modified file 'shorts/po/com.ubuntu.shorts.pot' |
54 | --- shorts/po/com.ubuntu.shorts.pot 2015-12-01 17:03:50 +0000 |
55 | +++ shorts/po/com.ubuntu.shorts.pot 2015-12-15 16:05:21 +0000 |
56 | @@ -8,7 +8,7 @@ |
57 | msgstr "" |
58 | "Project-Id-Version: \n" |
59 | "Report-Msgid-Bugs-To: \n" |
60 | -"POT-Creation-Date: 2015-12-01 17:27+0800\n" |
61 | +"POT-Creation-Date: 2015-12-03 17:59+0800\n" |
62 | "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" |
63 | "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" |
64 | "Language-Team: LANGUAGE <LL@li.org>\n" |
65 | @@ -42,11 +42,41 @@ |
66 | msgid "Large" |
67 | msgstr "" |
68 | |
69 | -#: ../qml/pages/AppendFeedPage.qml:31 ../qml/shorts-app.qml:243 |
70 | -#: ../qml/shorts-app.qml:378 |
71 | +#: ../qml/nongoogle/AppendNGFeedPage.qml:30 ../qml/pages/AppendFeedPage.qml:31 |
72 | +#: ../qml/shorts-app.qml:255 ../qml/shorts-app.qml:390 |
73 | +#: ../qml/shorts-app.qml:398 |
74 | msgid "Add feeds" |
75 | msgstr "" |
76 | |
77 | +#: ../qml/nongoogle/AppendNGFeedPage.qml:105 |
78 | +#: ../qml/pages/AppendFeedPage.qml:137 |
79 | +msgid "Type a keyword or URL" |
80 | +msgstr "" |
81 | + |
82 | +#: ../qml/nongoogle/AppendNGFeedPage.qml:162 |
83 | +msgid "Feed Title:" |
84 | +msgstr "" |
85 | + |
86 | +#: ../qml/nongoogle/AppendNGFeedPage.qml:170 |
87 | +#: ../qml/nongoogle/AppendNGFeedPage.qml:185 |
88 | +msgid "No data" |
89 | +msgstr "" |
90 | + |
91 | +#: ../qml/nongoogle/AppendNGFeedPage.qml:177 |
92 | +msgid "Feed Description:" |
93 | +msgstr "" |
94 | + |
95 | +#: ../qml/nongoogle/AppendNGFeedPage.qml:210 |
96 | +#: ../qml/pages/AppendFeedPage.qml:243 ../qml/pages/CreateTopicPage.qml:38 |
97 | +#: ../qml/pages/TopicManagement.qml:239 ../qml/shorts-app.qml:481 |
98 | +msgid "Cancel" |
99 | +msgstr "" |
100 | + |
101 | +#: ../qml/nongoogle/AppendNGFeedPage.qml:243 |
102 | +#: ../qml/pages/AppendFeedPage.qml:276 |
103 | +msgid "Next" |
104 | +msgstr "" |
105 | + |
106 | #: ../qml/pages/AppendFeedPage.qml:69 |
107 | msgid "Failed to perform a feed search by keyword" |
108 | msgstr "" |
109 | @@ -59,23 +89,10 @@ |
110 | msgid "Failed to perform a feed search by URL" |
111 | msgstr "" |
112 | |
113 | -#: ../qml/pages/AppendFeedPage.qml:137 |
114 | -msgid "Type a keyword or URL" |
115 | -msgstr "" |
116 | - |
117 | #: ../qml/pages/AppendFeedPage.qml:185 |
118 | msgid "Search results" |
119 | msgstr "" |
120 | |
121 | -#: ../qml/pages/AppendFeedPage.qml:243 ../qml/pages/CreateTopicPage.qml:38 |
122 | -#: ../qml/pages/TopicManagement.qml:239 ../qml/shorts-app.qml:456 |
123 | -msgid "Cancel" |
124 | -msgstr "" |
125 | - |
126 | -#: ../qml/pages/AppendFeedPage.qml:276 |
127 | -msgid "Next" |
128 | -msgstr "" |
129 | - |
130 | #: ../qml/pages/AppendFeedPage.qml:305 ../qml/pages/CreateTopicPage.qml:181 |
131 | msgid "No feeds" |
132 | msgstr "" |
133 | @@ -118,6 +135,7 @@ |
134 | |
135 | #: ../qml/pages/ChooseTopicPage.qml:109 ../qml/pages/ChooseTopicPage.qml:122 |
136 | #: ../qml/pages/CreateTopicPage.qml:66 ../qml/pages/CreateTopicPage.qml:78 |
137 | +#: ../qml/shorts-app.qml:568 |
138 | msgid "Warning" |
139 | msgstr "" |
140 | |
141 | @@ -161,7 +179,15 @@ |
142 | msgid "Topic: " |
143 | msgstr "" |
144 | |
145 | -#: ../qml/pages/TopicManagement.qml:13 ../qml/shorts-app.qml:217 |
146 | +#: ../qml/pages/PageSettings.qml:9 ../qml/shorts-app.qml:239 |
147 | +msgid "Settings" |
148 | +msgstr "" |
149 | + |
150 | +#: ../qml/pages/PageSettings.qml:21 |
151 | +msgid "Use Google Search: " |
152 | +msgstr "" |
153 | + |
154 | +#: ../qml/pages/TopicManagement.qml:13 ../qml/shorts-app.qml:219 |
155 | msgid "Edit topics" |
156 | msgstr "" |
157 | |
158 | @@ -173,74 +199,88 @@ |
159 | msgid "Add Feed" |
160 | msgstr "" |
161 | |
162 | -#: ../qml/shorts-app.qml:184 |
163 | +#: ../qml/shorts-app.qml:186 |
164 | msgid "Refresh" |
165 | msgstr "" |
166 | |
167 | -#: ../qml/shorts-app.qml:191 |
168 | +#: ../qml/shorts-app.qml:193 |
169 | msgid "Grid View" |
170 | msgstr "" |
171 | |
172 | -#: ../qml/shorts-app.qml:191 |
173 | +#: ../qml/shorts-app.qml:193 |
174 | msgid "List view" |
175 | msgstr "" |
176 | |
177 | -#: ../qml/shorts-app.qml:227 |
178 | +#: ../qml/shorts-app.qml:229 |
179 | msgid "Disable night mode" |
180 | msgstr "" |
181 | |
182 | -#: ../qml/shorts-app.qml:227 |
183 | +#: ../qml/shorts-app.qml:229 |
184 | msgid "Enable night mode" |
185 | msgstr "" |
186 | |
187 | -#: ../qml/shorts-app.qml:309 |
188 | +#: ../qml/shorts-app.qml:321 |
189 | msgid "Saved" |
190 | msgstr "" |
191 | |
192 | -#: ../qml/shorts-app.qml:317 shorts.desktop.in.in.h:1 |
193 | +#: ../qml/shorts-app.qml:329 shorts.desktop.in.in.h:1 |
194 | msgid "Shorts" |
195 | msgstr "" |
196 | |
197 | -#: ../qml/shorts-app.qml:448 |
198 | +#: ../qml/shorts-app.qml:473 |
199 | msgid "Checking for new articles" |
200 | msgstr "" |
201 | |
202 | -#: ../qml/shorts-app.qml:472 |
203 | +#: ../qml/shorts-app.qml:497 |
204 | msgid "Perhaps some of the channels have not been updated." |
205 | msgstr "" |
206 | |
207 | -#: ../qml/shorts-app.qml:473 |
208 | +#: ../qml/shorts-app.qml:498 |
209 | msgid "Errors occurred during the update" |
210 | msgstr "" |
211 | |
212 | -#: ../qml/shorts-app.qml:491 |
213 | +#: ../qml/shorts-app.qml:516 |
214 | msgid "+ Add feeds" |
215 | msgstr "" |
216 | |
217 | -#: ../qml/shorts-app.qml:503 |
218 | +#: ../qml/shorts-app.qml:528 |
219 | msgid "Add online accounts" |
220 | msgstr "" |
221 | |
222 | -#: ../qml/shorts-app.qml:506 |
223 | +#: ../qml/shorts-app.qml:531 |
224 | msgid "Online accounts are not available for now" |
225 | msgstr "" |
226 | |
227 | -#: ../qml/shorts-app.qml:507 ../qml/shorts-app.qml:516 |
228 | +#: ../qml/shorts-app.qml:532 ../qml/shorts-app.qml:541 |
229 | msgid "We are sorry" |
230 | msgstr "" |
231 | |
232 | -#: ../qml/shorts-app.qml:512 |
233 | +#: ../qml/shorts-app.qml:537 |
234 | msgid "Import subscriptions" |
235 | msgstr "" |
236 | |
237 | -#: ../qml/shorts-app.qml:515 |
238 | +#: ../qml/shorts-app.qml:540 |
239 | msgid "Importing subscriptions is not available for now" |
240 | msgstr "" |
241 | |
242 | -#: ../qml/shorts-app.qml:530 |
243 | +#: ../qml/shorts-app.qml:555 |
244 | msgid "Ok" |
245 | msgstr "" |
246 | |
247 | +#: ../qml/shorts-app.qml:569 |
248 | +msgid "" |
249 | +"Shorts detects that you're located in an area which blocks Google's IP." |
250 | +"<br><br>" |
251 | +msgstr "" |
252 | + |
253 | +#: ../qml/shorts-app.qml:574 |
254 | +msgid "Yes, please." |
255 | +msgstr "" |
256 | + |
257 | +#: ../qml/shorts-app.qml:584 |
258 | +msgid "No, thanks." |
259 | +msgstr "" |
260 | + |
261 | #: ../qml/tabs/BaseTab.qml:153 |
262 | msgid "There are no articles to show" |
263 | msgstr "" |
264 | |
265 | === modified file 'shorts/qml/CMakeLists.txt' |
266 | --- shorts/qml/CMakeLists.txt 2015-07-17 14:42:42 +0000 |
267 | +++ shorts/qml/CMakeLists.txt 2015-12-15 16:05:21 +0000 |
268 | @@ -19,3 +19,4 @@ |
269 | add_subdirectory(pages) |
270 | add_subdirectory(tabs) |
271 | add_subdirectory(utils) |
272 | +add_subdirectory(nongoogle) |
273 | |
274 | === modified file 'shorts/qml/components/NetworkManager.qml' |
275 | --- shorts/qml/components/NetworkManager.qml 2015-10-24 07:06:24 +0000 |
276 | +++ shorts/qml/components/NetworkManager.qml 2015-12-15 16:05:21 +0000 |
277 | @@ -9,6 +9,9 @@ |
278 | import "../utils/imgSeparator.js" as ImageUtils |
279 | import "../utils/dateutils.js" as DateUtils |
280 | |
281 | +// below import for non-google usage |
282 | +import "../nongoogle" |
283 | + |
284 | Item { |
285 | id: networkManagerRoot |
286 | |
287 | @@ -18,11 +21,21 @@ |
288 | property string operationStatus: "success" |
289 | |
290 | function updateFeeds(feedsArray, topicId) { |
291 | - d.updateFeeds(feedsArray, topicId) |
292 | + if (optionsKeeper.useGoogleSearch()) { |
293 | + d.updateFeeds(feedsArray, topicId) |
294 | + } |
295 | + else { |
296 | + dNG.updateFeeds(feedsArray, topicId) |
297 | + } |
298 | } |
299 | |
300 | function cancelDownload() { |
301 | - d.cancelDownload() |
302 | + if (optionsKeeper.useGoogleSearch()) { |
303 | + d.cancelDownload() |
304 | + } |
305 | + else { |
306 | + dNG.cancelDownload() |
307 | + } |
308 | } |
309 | |
310 | /* All private method are inside QtObject. |
311 | @@ -129,4 +142,133 @@ |
312 | } |
313 | } // GFA |
314 | } // QtObject |
315 | + |
316 | + ////////////////////////////////////////// add a new object to refresh non-google feeds |
317 | + QtObject { |
318 | + id: dNG |
319 | + |
320 | + property var feedList: [] // Feed list to update. |
321 | + property var currentFeed // Current downloading feed. |
322 | + property int tagId: 0 // Tag to update. |
323 | + |
324 | + /* Method updates feeds one by another. |
325 | + * Input: array of objects, each should include |
326 | + * source, link and id (of feed in DB) properties. |
327 | + */ |
328 | + function updateFeeds(feedsArray, topicId) { |
329 | + tagId = topicId || 0 |
330 | + |
331 | + downloadStarted(tagId) |
332 | + |
333 | + feedList = feedsArray |
334 | + operationStatus = "success" |
335 | + updateNextFeed() |
336 | + } |
337 | + |
338 | + // For inner usage only. |
339 | + function updateNextFeed() { |
340 | + if (feedList.length == 0) { |
341 | + downloadFinished(tagId) |
342 | + return |
343 | + } |
344 | + |
345 | + currentFeed = feedList.shift() |
346 | + nonGoogleFeedApi.loadFeed(currentFeed.source) |
347 | + } |
348 | + |
349 | + function cancelDownload() { |
350 | + feedList = [] |
351 | + operationStatus = "abort" |
352 | + nonGoogleFeedApi.abort() |
353 | + } |
354 | + |
355 | + function updateFeedInfo(feedId, feedLink, responseData) { |
356 | + var entries = responseData.item |
357 | + var f = responseData |
358 | + |
359 | + var fde = f.description == undefined ? "" : f.description["#text"] == undefined ? f.description : f.description["#text"] |
360 | + var fti = f.title == undefined ? "" : f.title["#text"] == undefined ? f.title : f.title["#text"] |
361 | + |
362 | + DB.updateFeedByXml(feedId, feedLink, fde, fti) |
363 | + console.log(" -------- UPDATE INFO -------- ") |
364 | + // console.log(f.title, f.link, f.feedUrl, f.description) |
365 | + |
366 | + console.time("addArticlesEx") |
367 | + |
368 | + var newArticles = [] |
369 | + var maxLength = entries.length > 50 ? 50 : entries.length |
370 | + for (var i = 0; i < maxLength; i++) { |
371 | + var e = entries[i] |
372 | + |
373 | + // print("article detail: ", JSON.stringify(e)) |
374 | + // Grab image from for article. |
375 | + // var articleImage = ImageUtils.grabArticleImage(e) |
376 | + // e.content = clearFromBadTags(e.content) |
377 | + |
378 | + var ti = e.title == undefined ? "" : e.title["#text"] == undefined ? e.title : e.title["#text"] |
379 | + var li = e.link == undefined ? "" : e.link["#text"] == undefined ? e.link : e.link["#text"] |
380 | + var au = e.author == undefined ? "" : e.author["#text"] == undefined ? e.author : e.author["#text"] |
381 | + var creator = e.creator == undefined ? "" : e.creator["#text"] == undefined ? e.creator : e.creator["#text"] |
382 | + var de = e.description == undefined ? "" : e.description["#text"] == undefined ? e.description : e.description["#text"] |
383 | + var pu = e.pubDate == undefined ? "" : e.pubDate["#text"] == undefined ? e.pubDate : e.pubDate["#text"] |
384 | + var co = e.content == undefined ? "" : e.content["#text"] == undefined ? e.content : e.content["#text"] |
385 | + var articleImage = utilities.htmlGetImg(de) |
386 | + if (articleImage.length == 0) { articleImage = utilities.htmlGetImg(co) } |
387 | + else { |
388 | + print("articleImage: ", articleImage[0]) |
389 | + } |
390 | + // print("date parse 0: ", pu, DateUtils.parseDate(pu)) |
391 | + // print("date parse 1: ", DateUtils.formatRelativeTime(i18n, DateUtils.parseDate(pu))) |
392 | + |
393 | + var temp = |
394 | + { |
395 | + "title": ti, |
396 | + "content": co == "" ? de : co, |
397 | + "link": li, |
398 | + "author": creator == "" ? au : creator, |
399 | + "description": de, |
400 | + "pubDate": DateUtils.parseDate(pu), |
401 | + "guid": Qt.md5(li + pu), |
402 | + "image" : articleImage.length > 0 ? articleImage[0] : "", |
403 | + "media_groups" : "" |
404 | + } |
405 | + |
406 | + newArticles.push(temp) |
407 | + } |
408 | +// print("new article length: ", newArticles.length) |
409 | + |
410 | + // /* Add new articles to DB and restore 'read' status of some of them. |
411 | + // */ |
412 | + // DB.addArticles(articleModel, feedId, articleProperties); |
413 | + |
414 | + /* Add new articles to DB and restore 'read' status of some of them. */ |
415 | + try { |
416 | + DB.addArticlesEx(newArticles, feedId) |
417 | + } catch (e) { |
418 | + console.log("Exception:", JSON.stringify(e)) |
419 | + } |
420 | + |
421 | + console.timeEnd("addArticlesEx") |
422 | + } |
423 | + |
424 | + function clearFromBadTags(content) { |
425 | + /* Remove non empty too. Useless anyway. |
426 | + */ |
427 | + content = content.replace(/alt=".*?"/g, "") |
428 | + content = content.replace(/title=".*?"/g, "") |
429 | + return content |
430 | + } |
431 | + |
432 | + property var nonGoogleFeedApi: XmlNetwork { |
433 | + onLoadResult: { |
434 | + if (result.rss == undefined || result.rss == "") { |
435 | +// console.log("XML NETWORK GFA:", JSON.stringify(result)) |
436 | + if (operationStatus == "success") |
437 | + operationStatus = "withErrors" |
438 | + } else dNG.updateFeedInfo(dNG.currentFeed.id, dNG.currentFeed.link, result.rss.channel) |
439 | + |
440 | + dNG.updateNextFeed() |
441 | + } |
442 | + } // GFA |
443 | + } // QtObject |
444 | } |
445 | |
446 | === modified file 'shorts/qml/components/OptionsKeeper.qml' |
447 | --- shorts/qml/components/OptionsKeeper.qml 2015-10-10 11:24:04 +0000 |
448 | +++ shorts/qml/components/OptionsKeeper.qml 2015-12-15 16:05:21 +0000 |
449 | @@ -14,6 +14,11 @@ |
450 | fontSize = getFontSize() |
451 | useDarkTheme = getUseDarkTheme() |
452 | useListMode = getUseListMode() |
453 | + |
454 | + |
455 | + if (useGoogleSearch() == undefined ) { |
456 | + setUseGoogleSearch(true) |
457 | + } |
458 | } |
459 | |
460 | onFontSizeChanged: setFontSize(fontSize) |
461 | @@ -64,6 +69,17 @@ |
462 | return settingsDocument.contents.dbLastUpdate |
463 | } |
464 | |
465 | + /////////////////////////////////////////////////////// below two functions are get/set "useGoogleSearch" value |
466 | + function useGoogleSearch() { |
467 | + return settingsDocument.contents.useGoogleSearch |
468 | + } |
469 | + |
470 | + function setUseGoogleSearch(value) { |
471 | + var cont = settingsDocument.contents |
472 | + cont.useGoogleSearch = value |
473 | + settingsDocument.contents = cont |
474 | + } |
475 | + |
476 | U1db.Database { |
477 | id: settingsDataBase |
478 | path: "ShortsOptions" |
479 | @@ -75,6 +91,8 @@ |
480 | docId: 'settingsDocument' |
481 | create: true |
482 | defaults: { "useDarkTheme" : false, "fontSize" : 1, |
483 | - "useListMode" : false, "dbVersion" : 1.2} |
484 | + "useListMode" : false, "dbVersion" : 1.2, |
485 | + "useGoogleSearch" : true |
486 | + } |
487 | } |
488 | } // Item |
489 | |
490 | === added directory 'shorts/qml/nongoogle' |
491 | === added file 'shorts/qml/nongoogle/AppendNGFeedPage.qml' |
492 | --- shorts/qml/nongoogle/AppendNGFeedPage.qml 1970-01-01 00:00:00 +0000 |
493 | +++ shorts/qml/nongoogle/AppendNGFeedPage.qml 2015-12-15 16:05:21 +0000 |
494 | @@ -0,0 +1,254 @@ |
495 | +/* |
496 | + * Copyright (C) 2013, 2014 |
497 | + * |
498 | + * This program is free software; you can redistribute it and/or modify |
499 | + * it under the terms of the GNU General Public License as published by |
500 | + * the Free Software Foundation; version 3. |
501 | + * |
502 | + * This program is distributed in the hope that it will be useful, |
503 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
504 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
505 | + * GNU General Public License for more details. |
506 | + * |
507 | + * You should have received a copy of the GNU General Public License |
508 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
509 | + */ |
510 | + |
511 | +import QtQuick 2.4 |
512 | +import QtQuick.XmlListModel 2.0 |
513 | +import Ubuntu.Components 1.3 |
514 | +import Ubuntu.Components.ListItems 1.3 as ListItem |
515 | +import Ubuntu.Components.Popups 1.3 |
516 | + |
517 | +import "../utils/databasemodule_v2.js" as DB |
518 | +import "../." |
519 | + |
520 | +Page { |
521 | + id: appendFeedPage |
522 | + |
523 | + objectName: "appendfeedpage" |
524 | + title: i18n.tr("Add feeds") |
525 | + flickable: null |
526 | + visible: false |
527 | + |
528 | + property bool isDirty: false // Need to clear all page content. |
529 | + property int selectedCount: 0 |
530 | + property bool resultsReceived: false // Indicates that at least once results were received. |
531 | + |
532 | + function reloadPageContent() { |
533 | + } |
534 | + |
535 | + /* Clear model and model's depend data. |
536 | + * Currently only selectedCount. |
537 | + */ |
538 | + function clearModelDependData() { |
539 | +// searchResultsModel.clear() |
540 | +// selectedCount = 0 |
541 | + } |
542 | + |
543 | + // ------------------------------------- XmlNetwork |
544 | + |
545 | + property string feedTitle: "" |
546 | + property string feedDesc: "" |
547 | + property string feedUrl: "" |
548 | + property string feedLink: "" |
549 | + property var feedObj |
550 | + |
551 | + XmlNetwork { |
552 | + id: xmlFeedApi |
553 | + |
554 | + onLoadResult: { |
555 | + if (result.rss == undefined || result.rss == "") { |
556 | + // TODO alert that fail retriving feed data |
557 | + print("onLoadResult failed") |
558 | + } |
559 | + else { |
560 | +// d.updateFeedInfo(d.currentFeed.id, d.currentFeed.link, result.rss.channel) |
561 | + var f = result.rss.channel |
562 | + |
563 | + feedDesc = f.description == undefined ? "" : f.description["#text"] == undefined ? f.description : f.description["#text"] |
564 | + feedTitle = f.title == undefined ? "" : f.title["#text"] == undefined ? f.title : f.title["#text"] |
565 | +// feedUrl = l |
566 | + feedLink = f.link == undefined ? "" : f.link["#text"] == undefined ? f.link : f.link["#text"] |
567 | + feedObj = { |
568 | + "url" : feedUrl, |
569 | + "title" : feedTitle, |
570 | + "description" : feedDesc, |
571 | + "link" : feedLink |
572 | + } |
573 | + } |
574 | + |
575 | + } |
576 | + } |
577 | + |
578 | + // ------------------------------------- XmlNetwork |
579 | + |
580 | + Column { |
581 | + id: appendFeedColumn |
582 | + |
583 | + anchors.top: parent.top |
584 | + anchors.topMargin: units.gu(2) |
585 | + width: parent.width |
586 | + spacing: units.gu(2) |
587 | + |
588 | + TextField { |
589 | + objectName: "tfFeedUrl" |
590 | + id: tfFeedUrl |
591 | + |
592 | + placeholderText: i18n.tr("Type a keyword or URL") |
593 | + |
594 | + width: parent.width - units.gu(4) |
595 | + // height:units.gu(5) |
596 | + anchors { |
597 | + horizontalCenter: parent.horizontalCenter |
598 | + } |
599 | + primaryItem: Image { |
600 | + height: parent.height*0.5 |
601 | + width: height |
602 | + anchors.verticalCenter: parent.verticalCenter |
603 | + // anchors.verticalCenterOffset: -units.gu(0.2) |
604 | + source: Qt.resolvedUrl("../icons_tmp/find.svg") |
605 | + smooth: true |
606 | + |
607 | + MouseArea { |
608 | + anchors.fill: parent |
609 | + onClicked: { |
610 | + if (Qt.inputMethod.visible) |
611 | + tfFeedUrl.accapt() |
612 | + } |
613 | + } |
614 | + } |
615 | + |
616 | + onAccepted: { |
617 | + accapt() |
618 | + } |
619 | + |
620 | + function accapt() { |
621 | + Qt.inputMethod.hide() |
622 | + var userInput = text |
623 | + |
624 | + if (userInput == "") |
625 | + return |
626 | + |
627 | + // Very simple logic, URL if there are no spaces and contains dots. |
628 | + // But simple not means that it is wrong. |
629 | + var isUrlEntered = (userInput.indexOf(" ") === -1 && userInput.indexOf(".") !== -1) |
630 | + |
631 | + if (isUrlEntered) { |
632 | + if (userInput.indexOf("http://") !== 0) |
633 | + {userInput = "http://" + userInput} |
634 | + feedUrl = userInput |
635 | + xmlFeedApi.loadFeed(userInput) |
636 | + } |
637 | +// else xmlFeedApi.findFeeds(text) |
638 | + else { |
639 | + // TODO alert that user input invalid |
640 | + print("input invalid") |
641 | + } |
642 | + } |
643 | + } |
644 | + |
645 | + ListItem.Header { |
646 | + |
647 | + ListItem.ThinDivider { } |
648 | + |
649 | + text: i18n.tr("Feed Title:") |
650 | + |
651 | + ListItem.ThinDivider { anchors.bottom: parent.bottom } |
652 | + } |
653 | + |
654 | + Label { |
655 | + anchors { left: parent.left;right: parent.right; margins: units.gu(2) } |
656 | + wrapMode: Text.WrapAtWordBoundaryOrAnywhere |
657 | + text: feedTitle == "" ? i18n.tr("No data") : feedTitle |
658 | + } |
659 | + |
660 | + ListItem.Header { |
661 | + |
662 | + ListItem.ThinDivider { } |
663 | + |
664 | + text: i18n.tr("Feed Description:") |
665 | + |
666 | + ListItem.ThinDivider { anchors.bottom: parent.bottom } |
667 | + } |
668 | + |
669 | + Label { |
670 | + anchors { left: parent.left;right: parent.right; margins: units.gu(2) } |
671 | + wrapMode: Text.WrapAtWordBoundaryOrAnywhere |
672 | + text: feedDesc == "" ? i18n.tr("No data") : feedDesc |
673 | + } |
674 | + } // Column |
675 | + |
676 | + Rectangle { |
677 | + id: fakePanel |
678 | + |
679 | + color: "#fafafa" |
680 | + anchors { |
681 | + left: parent.left |
682 | + right: parent.right |
683 | + bottom: parent.bottom |
684 | + } |
685 | + height: units.gu(6) |
686 | + Item { |
687 | + anchors.fill: parent |
688 | + |
689 | + Button { |
690 | + anchors { |
691 | + verticalCenter: parent.verticalCenter |
692 | + left: parent.left |
693 | + leftMargin: units.gu(1) |
694 | + } |
695 | + gradient: UbuntuColors.greyGradient |
696 | + action: Action { |
697 | + text: i18n.tr("Cancel") |
698 | + |
699 | + onTriggered: { |
700 | + xmlFeedApi.abort() |
701 | + pageStack.pop() |
702 | + } |
703 | + } |
704 | + } |
705 | + |
706 | + ActivityIndicator { |
707 | + id: checkRunning |
708 | + |
709 | + visible: xmlFeedApi.inProgress |
710 | + running: xmlFeedApi.inProgress |
711 | + |
712 | + anchors { |
713 | + verticalCenter: parent.verticalCenter |
714 | + right: nextBtn.left |
715 | + rightMargin: units.gu(1) |
716 | + } |
717 | + } |
718 | + |
719 | + Button { |
720 | + id: nextBtn |
721 | + objectName: "nextButton" |
722 | + anchors { |
723 | + verticalCenter: parent.verticalCenter |
724 | + right: parent.right |
725 | + rightMargin: units.gu(1) |
726 | + } |
727 | + |
728 | + enabled: !xmlFeedApi.inProgress && feedUrl != "" && feedTitle != "" |
729 | + action: Action { |
730 | + text: i18n.tr("Next") |
731 | + |
732 | + onTriggered: { |
733 | + if (!nextBtn.enabled) |
734 | + return |
735 | + |
736 | + var selectedFeeds = [] |
737 | + |
738 | + selectedFeeds.push(feedObj) |
739 | + |
740 | + pageStack.push(chooseTopicPage, {"feedsToAdd" : selectedFeeds}) |
741 | +// pageStack.push(Qt.resolvedUrl("../pages/ChooseTopicPage.qml"), {"feedsToAdd" : selectedFeeds}) |
742 | + } |
743 | + } |
744 | + } // Button |
745 | + } |
746 | + } // Rectangle fakePanel |
747 | + |
748 | +} |
749 | |
750 | === added file 'shorts/qml/nongoogle/CMakeLists.txt' |
751 | --- shorts/qml/nongoogle/CMakeLists.txt 1970-01-01 00:00:00 +0000 |
752 | +++ shorts/qml/nongoogle/CMakeLists.txt 2015-12-15 16:05:21 +0000 |
753 | @@ -0,0 +1,6 @@ |
754 | +file(GLOB NONGOOGLE_QML_JS_FILES *.qml *.js) |
755 | + |
756 | +# make the files visible in the qtcreator tree |
757 | +add_custom_target(ubuntu-rssreader-app_nongoogle_QMlFiles ALL SOURCES ${NONGOOGLE_QML_JS_FILES}) |
758 | + |
759 | +install(FILES ${NONGOOGLE_QML_JS_FILES} DESTINATION ${SHORTS_DIR}/nongoogle/) |
760 | \ No newline at end of file |
761 | |
762 | === added file 'shorts/qml/nongoogle/Positioner.qml' |
763 | --- shorts/qml/nongoogle/Positioner.qml 1970-01-01 00:00:00 +0000 |
764 | +++ shorts/qml/nongoogle/Positioner.qml 2015-12-15 16:05:21 +0000 |
765 | @@ -0,0 +1,114 @@ |
766 | +/* |
767 | + * Copyright (C) 2014-2015 Canonical Ltd |
768 | + * |
769 | + * This file is part of Ubuntu Clock App |
770 | + * |
771 | + * Ubuntu Clock App is free software: you can redistribute it and/or modify |
772 | + * it under the terms of the GNU General Public License version 3 as |
773 | + * published by the Free Software Foundation. |
774 | + * |
775 | + * Ubuntu Clock App is distributed in the hope that it will be useful, |
776 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
777 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
778 | + * GNU General Public License for more details. |
779 | + * |
780 | + * You should have received a copy of the GNU General Public License |
781 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
782 | + */ |
783 | + |
784 | +import QtQuick 2.4 |
785 | +import U1db 1.0 as U1db |
786 | +import QtPositioning 5.2 |
787 | +import Ubuntu.Components 1.3 |
788 | +import Ubuntu.Components.Popups 1.3 |
789 | +//import "../components" |
790 | + |
791 | +Item { |
792 | + id: positioner |
793 | + objectName: "positioner" |
794 | + |
795 | + anchors.fill: parent |
796 | + |
797 | + // Property to keep track of app cold start status |
798 | + property string countryCode: "" |
799 | + |
800 | + Component.onCompleted: { |
801 | + } |
802 | + |
803 | + PositionSource { |
804 | + id: geoposition |
805 | + |
806 | + // Property to store the time of the last GPS location update |
807 | + property var lastUpdate |
808 | + |
809 | + readonly property real userLongitude: position.coordinate.longitude |
810 | + |
811 | + readonly property real userLatitude: position.coordinate.latitude |
812 | + |
813 | + active: true |
814 | + updateInterval: 1000 |
815 | + |
816 | + onSourceErrorChanged: { |
817 | + // Stop querying user location if location service is not available |
818 | + if (sourceError !== PositionSource.NoError) { |
819 | + console.log("[Source Error]: Location Service Error") |
820 | + geoposition.stop() |
821 | + |
822 | + } |
823 | + } |
824 | + |
825 | + onPositionChanged: { |
826 | + // Do not accept an invalid user location |
827 | + if(!position.longitudeValid || !position.latitudeValid) { |
828 | + return |
829 | + } |
830 | + |
831 | + if(position.longitudeValid || position.latitudeValid) { |
832 | + print("current position: ", userLatitude, userLongitude) |
833 | + geoposition.stop() |
834 | + getCountryCode(userLatitude, userLongitude) |
835 | + } |
836 | + |
837 | + |
838 | + } |
839 | + |
840 | + /* get country code from geonames.org |
841 | + // http://api.geonames.org/countryCode?lat=23&lng=113&username=krnekhelesh |
842 | + */ |
843 | + function getCountryCode(lat, lng) { |
844 | + |
845 | + var url = "http://api.geonames.org/countryCode?lat=" + lat + "&lng=" + lng + "&username=krnekhelesh&type=JSON" |
846 | + |
847 | + var doc = new XMLHttpRequest() |
848 | + |
849 | + doc.onreadystatechange = function() { |
850 | + |
851 | + // print("positioner onreadystatechange: ", doc.readyState, doc.status, feedUrl) |
852 | + if (doc.readyState === XMLHttpRequest.DONE) { |
853 | + |
854 | + var resObj |
855 | + if (doc.status == 200) { |
856 | + resObj = JSON.parse(doc.responseText) |
857 | + } else { // Error |
858 | + resObj = {"responseDetails" : doc.statusText, |
859 | + "responseStatus" : doc.status} |
860 | +// resObj = "" |
861 | + } |
862 | + |
863 | + countryCode = resObj.countryName |
864 | + print("countryCode", resObj) |
865 | + |
866 | + if (countryCode == "China") { |
867 | + if (optionsKeeper.useGoogleSearch()) { |
868 | + PopupUtils.open(componentDialogNG, tabstabs) |
869 | + } |
870 | + } |
871 | + } |
872 | + } |
873 | + |
874 | + doc.open("GET", url, true); |
875 | + doc.send(); |
876 | + } |
877 | + } //PositionSource |
878 | + |
879 | +} |
880 | |
881 | === added file 'shorts/qml/nongoogle/XmlNetwork.qml' |
882 | --- shorts/qml/nongoogle/XmlNetwork.qml 1970-01-01 00:00:00 +0000 |
883 | +++ shorts/qml/nongoogle/XmlNetwork.qml 2015-12-15 16:05:21 +0000 |
884 | @@ -0,0 +1,84 @@ |
885 | +import QtQuick 2.4 |
886 | + |
887 | +QtObject { |
888 | + id: rootObject |
889 | + |
890 | + property bool inProgress: __doc != null |
891 | + |
892 | + signal findResult(var result) |
893 | + signal loadResult(var result) |
894 | + |
895 | + property var __doc: null |
896 | + |
897 | + /* Load feed by URL. |
898 | + */ |
899 | + function loadFeed(feedUrl, num) { |
900 | + abort(true) |
901 | + |
902 | + if (num) |
903 | + num = Math.min(num, 100) |
904 | + else num = 50 |
905 | + |
906 | + __doc = new XMLHttpRequest() |
907 | + var doc = __doc |
908 | + |
909 | + doc.onreadystatechange = function() { |
910 | + |
911 | +// print("xmlnetwork onreadystatechange: ", doc.readyState, doc.status, feedUrl) |
912 | + if (doc.readyState === XMLHttpRequest.DONE) { |
913 | + |
914 | + var resObj |
915 | + if (doc.status == 200) { |
916 | +// resObj = JSON.parse(doc.responseText) |
917 | + resObj = utilities.xmlToJson(doc.responseText) |
918 | + } else { // Error |
919 | + resObj = {"responseDetails" : doc.statusText, |
920 | + "responseStatus" : doc.status} |
921 | + } |
922 | + |
923 | + __doc = null |
924 | + loadResult(resObj) |
925 | + } |
926 | + } |
927 | + |
928 | + |
929 | + /* Number of articles to download. |
930 | + */ |
931 | +// finalRequest += "&num=" + num |
932 | + |
933 | + /* Add some optional params. |
934 | + * May be usable: |
935 | + * hl - host language, for example "hl=ru", default en. |
936 | + * num - number of entries, for example "num=50", default 4, maximum 100. |
937 | + * output - format of output, for example "output=json", may be xml, json_xml, json. |
938 | + */ |
939 | +// doc.open("GET", finalRequest, true); |
940 | + doc.open("GET", feedUrl, true); |
941 | + doc.send(); |
942 | + } |
943 | + |
944 | + /* Param "isAbortOnly" used to preserve |
945 | + * property "__doc" in not null state. |
946 | + * inProgress binded to it so we can avoid |
947 | + * additional recalculations. |
948 | + */ |
949 | + function abort(isAbortOnly) { |
950 | + if (__doc != null) { |
951 | + __doc.abort() |
952 | + if (!isAbortOnly) |
953 | + __doc = null |
954 | + } |
955 | + } |
956 | + |
957 | + /* Return true if some kind of errors detected. |
958 | + * TODO DEMO |
959 | + */ |
960 | + function checkForErrors(result) { |
961 | + if (result.responseStatus == 200 || // HTTP OK |
962 | + result.responseStatus == 0) { // ABORTED |
963 | + return false |
964 | + } |
965 | + |
966 | + return true |
967 | + } |
968 | +} // QtObject |
969 | |
970 | === added file 'shorts/qml/pages/PageSettings.qml' |
971 | --- shorts/qml/pages/PageSettings.qml 1970-01-01 00:00:00 +0000 |
972 | +++ shorts/qml/pages/PageSettings.qml 2015-12-15 16:05:21 +0000 |
973 | @@ -0,0 +1,62 @@ |
974 | +import QtQuick 2.4 |
975 | +import Ubuntu.Components 1.3 |
976 | +import Ubuntu.Components.ListItems 1.3 as ListItem |
977 | +import Ubuntu.Components.Popups 1.3 |
978 | +import "../components" |
979 | + |
980 | +Page { |
981 | + id: pageSettings |
982 | + title: i18n.tr("Settings") |
983 | + flickable: null |
984 | + |
985 | + Column { |
986 | + anchors { |
987 | + top: parent.top; topMargin: units.gu(1) |
988 | + left: parent.left; leftMargin: units.gu(1) |
989 | + right: parent.right; rightMargin: units.gu(1) |
990 | + } |
991 | + height: childrenRect.height |
992 | + spacing: units.gu(0.8) |
993 | + |
994 | + ///////////////////////////////////////////////////////////////////// Google RSS engine switch start here |
995 | + Label { |
996 | + anchors { left: parent.left; right: parent.right; margins: units.gu(2) } |
997 | + horizontalAlignment: Text.AlignHCenter |
998 | + wrapMode: Text.WrapAtWordBoundaryOrAnywhere |
999 | + text: i18n.tr("For those who living in some special regions cannot access Google, the switch below can disable Google RSS engine, Shorts will directly get data from RSS sources.") |
1000 | + } |
1001 | + |
1002 | + Item { width: 10; height: 1 } // just a separator |
1003 | + |
1004 | + Item { |
1005 | + anchors { left: parent.left; right: parent.right; } |
1006 | + height: childrenRect.height |
1007 | + |
1008 | + Label { |
1009 | + text: i18n.tr("Use Google Search: ") |
1010 | + } |
1011 | + |
1012 | + Switch { |
1013 | + anchors.right: parent.right |
1014 | + checked: optionsKeeper.useGoogleSearch() |
1015 | + |
1016 | + Component.onCompleted: { |
1017 | + if (optionsKeeper.useGoogleSearch() == undefined ) { |
1018 | + optionsKeeper.setUseGoogleSearch(true) |
1019 | + checked = true |
1020 | + } |
1021 | + } |
1022 | + |
1023 | + onCheckedChanged: { |
1024 | + optionsKeeper.setUseGoogleSearch(checked) |
1025 | + } |
1026 | + } |
1027 | + } |
1028 | + |
1029 | + ListItem.ThinDivider{} |
1030 | + ///////////////////////////////////////////////////////////////////// Google RSS engine switch end here |
1031 | + |
1032 | + |
1033 | + }// Column |
1034 | + |
1035 | +} |
1036 | |
1037 | === modified file 'shorts/qml/shorts-app.qml' |
1038 | --- shorts/qml/shorts-app.qml 2015-11-27 22:08:54 +0000 |
1039 | +++ shorts/qml/shorts-app.qml 2015-12-15 16:05:21 +0000 |
1040 | @@ -8,6 +8,8 @@ |
1041 | import "./components" |
1042 | import "./utils/databasemodule_v2.js" as DB |
1043 | |
1044 | +import "./nongoogle" |
1045 | + |
1046 | MainView { |
1047 | id: mainView |
1048 | |
1049 | @@ -119,7 +121,7 @@ |
1050 | objectName: "pageStack" |
1051 | |
1052 | property bool isListView: optionsKeeper.useListMode |
1053 | - property var commonHeadActions: [refreshAction, changeModeAction, editTopicsAction, nightModeAction] |
1054 | + property var commonHeadActions: [refreshAction, changeModeAction, editTopicsAction, nightModeAction, actionSetting] |
1055 | |
1056 | anchors.fill: parent |
1057 | focus: true |
1058 | @@ -231,6 +233,16 @@ |
1059 | } |
1060 | } |
1061 | |
1062 | + Action { |
1063 | + id: actionSetting |
1064 | + objectName:"actionSetting" |
1065 | + text: i18n.tr("Settings") |
1066 | + iconName: "settings" |
1067 | + onTriggered: { |
1068 | + pageStack.push(Qt.resolvedUrl("./pages/PageSettings.qml")) |
1069 | + } |
1070 | + } |
1071 | + |
1072 | /* -------------------------- Pages & Tabs ---------------------------- */ |
1073 | |
1074 | BottomEdgeTabs { |
1075 | @@ -239,7 +251,7 @@ |
1076 | objectName: "tabstabs" |
1077 | visible: false |
1078 | |
1079 | - bottomEdgePage: appendFeedPage |
1080 | + bottomEdgePage: optionsKeeper.useGoogleSearch() ? appendFeedPage : appendNGFeedPage |
1081 | bottomEdgeTitle: i18n.tr("Add feeds") |
1082 | bottomEdgeBackgroundColor: "#F5F5F5" // "#875864" |
1083 | bottomEdgeTipColor: "#5533b5e5"// "#E0E0E0" //"#9b616c" |
1084 | @@ -379,6 +391,14 @@ |
1085 | flickable: null |
1086 | visible: false |
1087 | } |
1088 | + |
1089 | + AppendNGFeedPage { |
1090 | + id: appendNGFeedPage |
1091 | + |
1092 | + title: i18n.tr("Add feeds") |
1093 | + flickable: null |
1094 | + visible: false |
1095 | + } |
1096 | // ******************************** Choose Topic Page ***********************/////////////// |
1097 | |
1098 | ChooseTopicPage { |
1099 | @@ -436,6 +456,11 @@ |
1100 | id: optionsKeeper |
1101 | } |
1102 | |
1103 | + // Positioner to detect current position |
1104 | + Positioner { |
1105 | + id: positionDetector |
1106 | + } |
1107 | + |
1108 | /* -------------------------- Components ---------------------------- */ |
1109 | |
1110 | Component { |
1111 | @@ -534,6 +559,35 @@ |
1112 | } |
1113 | } // Component |
1114 | |
1115 | + //////////////////////////////////////////////////////// a dialog to ask user if she/he wants to turn off the google search |
1116 | + Component { |
1117 | + id: componentDialogNG |
1118 | + |
1119 | + Dialog { |
1120 | + id: dialogNG |
1121 | + title: i18n.tr("Warning") |
1122 | + text: i18n.tr("Shorts detects that you're located in an area which blocks Google's IP.<br><br>" |
1123 | + + "We strongly reconmend you to turn off the Google search funtion." |
1124 | + + "Or you can do it in the settings page manually.") |
1125 | + |
1126 | + Button { |
1127 | + text: i18n.tr("Yes, please.") |
1128 | + color: UbuntuColors.orange |
1129 | + objectName: "dialogNGButtonYes" |
1130 | + onClicked: { |
1131 | + optionsKeeper.setUseGoogleSearch(false) |
1132 | + PopupUtils.close(dialogNG) |
1133 | + } |
1134 | + } |
1135 | + |
1136 | + Button { |
1137 | + text: i18n.tr("No, thanks.") |
1138 | + objectName: "dialogNGButtonNo" |
1139 | + onClicked: PopupUtils.close(dialogNG) |
1140 | + } |
1141 | + } |
1142 | + } // Component |
1143 | + |
1144 | /* -------------------------- Connections ---------------------------- */ |
1145 | |
1146 | Connections { |
1147 | |
1148 | === modified file 'shorts/shorts.pro' |
1149 | --- shorts/shorts.pro 2015-09-16 08:52:25 +0000 |
1150 | +++ shorts/shorts.pro 2015-12-15 16:05:21 +0000 |
1151 | @@ -6,7 +6,8 @@ |
1152 | QT += qml quick |
1153 | |
1154 | SOURCES += main.cpp \ |
1155 | - CachingNetworkManagerFactory.cpp |
1156 | + CachingNetworkManagerFactory.cpp \ |
1157 | + xml2json/utilities.cpp |
1158 | |
1159 | RESOURCES += shorts.qrc |
1160 | |
1161 | @@ -41,12 +42,16 @@ |
1162 | qml/pages/SwipeDelete.qml \ |
1163 | qml/pages/TopicComponent.qml \ |
1164 | qml/pages/TopicManagement.qml \ |
1165 | + qml/pages/PageSettings.qml \ |
1166 | qml/tabs/BaseTab.qml \ |
1167 | qml/tabs/SavedTab.qml \ |
1168 | qml/tabs/ShortsTab.qml \ |
1169 | qml/tabs/TopicTab.qml \ |
1170 | qml/shorts-app.qml \ |
1171 | - qml/content/SharePage.qml |
1172 | + qml/content/SharePage.qml \ |
1173 | + qml/nongoogle/AppendNGFeedPage.qml \ |
1174 | + qml/nongoogle/Positioner.qml \ |
1175 | + qml/nongoogle/XmlNetwork.qml |
1176 | |
1177 | #specify where the config files are installed to |
1178 | config_files.path = /. |
1179 | @@ -59,5 +64,39 @@ |
1180 | INSTALLS+=target |
1181 | |
1182 | HEADERS += \ |
1183 | - CachingNetworkManagerFactory.h |
1184 | + CachingNetworkManagerFactory.h \ |
1185 | + xml2json/utilities.h \ |
1186 | + xml2json/rapidjson/error/en.h \ |
1187 | + xml2json/rapidjson/error/error.h \ |
1188 | + xml2json/rapidjson/internal/biginteger.h \ |
1189 | + xml2json/rapidjson/internal/diyfp.h \ |
1190 | + xml2json/rapidjson/internal/dtoa.h \ |
1191 | + xml2json/rapidjson/internal/ieee754.h \ |
1192 | + xml2json/rapidjson/internal/itoa.h \ |
1193 | + xml2json/rapidjson/internal/meta.h \ |
1194 | + xml2json/rapidjson/internal/pow10.h \ |
1195 | + xml2json/rapidjson/internal/stack.h \ |
1196 | + xml2json/rapidjson/internal/strfunc.h \ |
1197 | + xml2json/rapidjson/internal/strtod.h \ |
1198 | + xml2json/rapidjson/msinttypes/inttypes.h \ |
1199 | + xml2json/rapidjson/msinttypes/stdint.h \ |
1200 | + xml2json/rapidjson/allocators.h \ |
1201 | + xml2json/rapidjson/document.h \ |
1202 | + xml2json/rapidjson/encodedstream.h \ |
1203 | + xml2json/rapidjson/encodings.h \ |
1204 | + xml2json/rapidjson/filereadstream.h \ |
1205 | + xml2json/rapidjson/filestream.h \ |
1206 | + xml2json/rapidjson/filewritestream.h \ |
1207 | + xml2json/rapidjson/memorybuffer.h \ |
1208 | + xml2json/rapidjson/memorystream.h \ |
1209 | + xml2json/rapidjson/prettywriter.h \ |
1210 | + xml2json/rapidjson/rapidjson.h \ |
1211 | + xml2json/rapidjson/reader.h \ |
1212 | + xml2json/rapidjson/stringbuffer.h \ |
1213 | + xml2json/rapidjson/writer.h \ |
1214 | + xml2json/rapidxml/rapidxml.hpp \ |
1215 | + xml2json/rapidxml/rapidxml_iterators.hpp \ |
1216 | + xml2json/rapidxml/rapidxml_print.hpp \ |
1217 | + xml2json/rapidxml/rapidxml_utils.hpp \ |
1218 | + xml2json/xml2json.hpp |
1219 | |
1220 | |
1221 | === modified file 'shorts/shorts.qrc' |
1222 | --- shorts/shorts.qrc 2015-09-16 08:52:25 +0000 |
1223 | +++ shorts/shorts.qrc 2015-12-15 16:05:21 +0000 |
1224 | @@ -32,6 +32,10 @@ |
1225 | <file>qml/shorts-app.qml</file> |
1226 | <file>qml/content/SharePage.qml</file> |
1227 | <file>qml/components/DarkModeShader.qml</file> |
1228 | + <file>qml/nongoogle/XmlNetwork.qml</file> |
1229 | + <file>qml/nongoogle/AppendNGFeedPage.qml</file> |
1230 | + <file>qml/pages/PageSettings.qml</file> |
1231 | + <file>qml/nongoogle/Positioner.qml</file> |
1232 | </qresource> |
1233 | <qresource prefix="/img"> |
1234 | <file>qml/icons/add.svg</file> |
1235 | |
1236 | === added directory 'shorts/xml2json' |
1237 | === added directory 'shorts/xml2json/rapidjson' |
1238 | === added file 'shorts/xml2json/rapidjson/allocators.h' |
1239 | --- shorts/xml2json/rapidjson/allocators.h 1970-01-01 00:00:00 +0000 |
1240 | +++ shorts/xml2json/rapidjson/allocators.h 2015-12-15 16:05:21 +0000 |
1241 | @@ -0,0 +1,245 @@ |
1242 | +// Copyright (C) 2011 Milo Yip |
1243 | +// |
1244 | +// Permission is hereby granted, free of charge, to any person obtaining a copy |
1245 | +// of this software and associated documentation files (the "Software"), to deal |
1246 | +// in the Software without restriction, including without limitation the rights |
1247 | +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
1248 | +// copies of the Software, and to permit persons to whom the Software is |
1249 | +// furnished to do so, subject to the following conditions: |
1250 | +// |
1251 | +// The above copyright notice and this permission notice shall be included in |
1252 | +// all copies or substantial portions of the Software. |
1253 | +// |
1254 | +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
1255 | +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
1256 | +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
1257 | +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
1258 | +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
1259 | +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
1260 | +// THE SOFTWARE. |
1261 | + |
1262 | +#ifndef RAPIDJSON_ALLOCATORS_H_ |
1263 | +#define RAPIDJSON_ALLOCATORS_H_ |
1264 | + |
1265 | +#include "rapidjson.h" |
1266 | + |
1267 | +RAPIDJSON_NAMESPACE_BEGIN |
1268 | + |
1269 | +/////////////////////////////////////////////////////////////////////////////// |
1270 | +// Allocator |
1271 | + |
1272 | +/*! \class rapidjson::Allocator |
1273 | + \brief Concept for allocating, resizing and freeing memory block. |
1274 | + |
1275 | + Note that Malloc() and Realloc() are non-static but Free() is static. |
1276 | + |
1277 | + So if an allocator need to support Free(), it needs to put its pointer in |
1278 | + the header of memory block. |
1279 | + |
1280 | +\code |
1281 | +concept Allocator { |
1282 | + static const bool kNeedFree; //!< Whether this allocator needs to call Free(). |
1283 | + |
1284 | + // Allocate a memory block. |
1285 | + // \param size of the memory block in bytes. |
1286 | + // \returns pointer to the memory block. |
1287 | + void* Malloc(size_t size); |
1288 | + |
1289 | + // Resize a memory block. |
1290 | + // \param originalPtr The pointer to current memory block. Null pointer is permitted. |
1291 | + // \param originalSize The current size in bytes. (Design issue: since some allocator may not book-keep this, explicitly pass to it can save memory.) |
1292 | + // \param newSize the new size in bytes. |
1293 | + void* Realloc(void* originalPtr, size_t originalSize, size_t newSize); |
1294 | + |
1295 | + // Free a memory block. |
1296 | + // \param pointer to the memory block. Null pointer is permitted. |
1297 | + static void Free(void *ptr); |
1298 | +}; |
1299 | +\endcode |
1300 | +*/ |
1301 | + |
1302 | +/////////////////////////////////////////////////////////////////////////////// |
1303 | +// CrtAllocator |
1304 | + |
1305 | +//! C-runtime library allocator. |
1306 | +/*! This class is just wrapper for standard C library memory routines. |
1307 | + \note implements Allocator concept |
1308 | +*/ |
1309 | +class CrtAllocator { |
1310 | +public: |
1311 | + static const bool kNeedFree = true; |
1312 | + void* Malloc(size_t size) { return std::malloc(size); } |
1313 | + void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) { (void)originalSize; return std::realloc(originalPtr, newSize); } |
1314 | + static void Free(void *ptr) { std::free(ptr); } |
1315 | +}; |
1316 | + |
1317 | +/////////////////////////////////////////////////////////////////////////////// |
1318 | +// MemoryPoolAllocator |
1319 | + |
1320 | +//! Default memory allocator used by the parser and DOM. |
1321 | +/*! This allocator allocate memory blocks from pre-allocated memory chunks. |
1322 | + |
1323 | + It does not free memory blocks. And Realloc() only allocate new memory. |
1324 | + |
1325 | + The memory chunks are allocated by BaseAllocator, which is CrtAllocator by default. |
1326 | + |
1327 | + User may also supply a buffer as the first chunk. |
1328 | + |
1329 | + If the user-buffer is full then additional chunks are allocated by BaseAllocator. |
1330 | + |
1331 | + The user-buffer is not deallocated by this allocator. |
1332 | + |
1333 | + \tparam BaseAllocator the allocator type for allocating memory chunks. Default is CrtAllocator. |
1334 | + \note implements Allocator concept |
1335 | +*/ |
1336 | +template <typename BaseAllocator = CrtAllocator> |
1337 | +class MemoryPoolAllocator { |
1338 | +public: |
1339 | + static const bool kNeedFree = false; //!< Tell users that no need to call Free() with this allocator. (concept Allocator) |
1340 | + |
1341 | + //! Constructor with chunkSize. |
1342 | + /*! \param chunkSize The size of memory chunk. The default is kDefaultChunkSize. |
1343 | + \param baseAllocator The allocator for allocating memory chunks. |
1344 | + */ |
1345 | + MemoryPoolAllocator(size_t chunkSize = kDefaultChunkCapacity, BaseAllocator* baseAllocator = 0) : |
1346 | + chunkHead_(0), chunk_capacity_(chunkSize), userBuffer_(0), baseAllocator_(baseAllocator), ownBaseAllocator_(0) |
1347 | + { |
1348 | + } |
1349 | + |
1350 | + //! Constructor with user-supplied buffer. |
1351 | + /*! The user buffer will be used firstly. When it is full, memory pool allocates new chunk with chunk size. |
1352 | + |
1353 | + The user buffer will not be deallocated when this allocator is destructed. |
1354 | + |
1355 | + \param buffer User supplied buffer. |
1356 | + \param size Size of the buffer in bytes. It must at least larger than sizeof(ChunkHeader). |
1357 | + \param chunkSize The size of memory chunk. The default is kDefaultChunkSize. |
1358 | + \param baseAllocator The allocator for allocating memory chunks. |
1359 | + */ |
1360 | + MemoryPoolAllocator(void *buffer, size_t size, size_t chunkSize = kDefaultChunkCapacity, BaseAllocator* baseAllocator = 0) : |
1361 | + chunkHead_(0), chunk_capacity_(chunkSize), userBuffer_(buffer), baseAllocator_(baseAllocator), ownBaseAllocator_(0) |
1362 | + { |
1363 | + RAPIDJSON_ASSERT(buffer != 0); |
1364 | + RAPIDJSON_ASSERT(size > sizeof(ChunkHeader)); |
1365 | + chunkHead_ = reinterpret_cast<ChunkHeader*>(buffer); |
1366 | + chunkHead_->capacity = size - sizeof(ChunkHeader); |
1367 | + chunkHead_->size = 0; |
1368 | + chunkHead_->next = 0; |
1369 | + } |
1370 | + |
1371 | + //! Destructor. |
1372 | + /*! This deallocates all memory chunks, excluding the user-supplied buffer. |
1373 | + */ |
1374 | + ~MemoryPoolAllocator() { |
1375 | + Clear(); |
1376 | + RAPIDJSON_DELETE(ownBaseAllocator_); |
1377 | + } |
1378 | + |
1379 | + //! Deallocates all memory chunks, excluding the user-supplied buffer. |
1380 | + void Clear() { |
1381 | + while(chunkHead_ != 0 && chunkHead_ != userBuffer_) { |
1382 | + ChunkHeader* next = chunkHead_->next; |
1383 | + baseAllocator_->Free(chunkHead_); |
1384 | + chunkHead_ = next; |
1385 | + } |
1386 | + } |
1387 | + |
1388 | + //! Computes the total capacity of allocated memory chunks. |
1389 | + /*! \return total capacity in bytes. |
1390 | + */ |
1391 | + size_t Capacity() const { |
1392 | + size_t capacity = 0; |
1393 | + for (ChunkHeader* c = chunkHead_; c != 0; c = c->next) |
1394 | + capacity += c->capacity; |
1395 | + return capacity; |
1396 | + } |
1397 | + |
1398 | + //! Computes the memory blocks allocated. |
1399 | + /*! \return total used bytes. |
1400 | + */ |
1401 | + size_t Size() const { |
1402 | + size_t size = 0; |
1403 | + for (ChunkHeader* c = chunkHead_; c != 0; c = c->next) |
1404 | + size += c->size; |
1405 | + return size; |
1406 | + } |
1407 | + |
1408 | + //! Allocates a memory block. (concept Allocator) |
1409 | + void* Malloc(size_t size) { |
1410 | + size = RAPIDJSON_ALIGN(size); |
1411 | + if (chunkHead_ == 0 || chunkHead_->size + size > chunkHead_->capacity) |
1412 | + AddChunk(chunk_capacity_ > size ? chunk_capacity_ : size); |
1413 | + |
1414 | + void *buffer = reinterpret_cast<char *>(chunkHead_ + 1) + chunkHead_->size; |
1415 | + chunkHead_->size += size; |
1416 | + return buffer; |
1417 | + } |
1418 | + |
1419 | + //! Resizes a memory block (concept Allocator) |
1420 | + void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) { |
1421 | + if (originalPtr == 0) |
1422 | + return Malloc(newSize); |
1423 | + |
1424 | + // Do not shrink if new size is smaller than original |
1425 | + if (originalSize >= newSize) |
1426 | + return originalPtr; |
1427 | + |
1428 | + // Simply expand it if it is the last allocation and there is sufficient space |
1429 | + if (originalPtr == (char *)(chunkHead_ + 1) + chunkHead_->size - originalSize) { |
1430 | + size_t increment = static_cast<size_t>(newSize - originalSize); |
1431 | + increment = RAPIDJSON_ALIGN(increment); |
1432 | + if (chunkHead_->size + increment <= chunkHead_->capacity) { |
1433 | + chunkHead_->size += increment; |
1434 | + return originalPtr; |
1435 | + } |
1436 | + } |
1437 | + |
1438 | + // Realloc process: allocate and copy memory, do not free original buffer. |
1439 | + void* newBuffer = Malloc(newSize); |
1440 | + RAPIDJSON_ASSERT(newBuffer != 0); // Do not handle out-of-memory explicitly. |
1441 | + return std::memcpy(newBuffer, originalPtr, originalSize); |
1442 | + } |
1443 | + |
1444 | + //! Frees a memory block (concept Allocator) |
1445 | + static void Free(void *ptr) { (void)ptr; } // Do nothing |
1446 | + |
1447 | +private: |
1448 | + //! Copy constructor is not permitted. |
1449 | + MemoryPoolAllocator(const MemoryPoolAllocator& rhs) /* = delete */; |
1450 | + //! Copy assignment operator is not permitted. |
1451 | + MemoryPoolAllocator& operator=(const MemoryPoolAllocator& rhs) /* = delete */; |
1452 | + |
1453 | + //! Creates a new chunk. |
1454 | + /*! \param capacity Capacity of the chunk in bytes. |
1455 | + */ |
1456 | + void AddChunk(size_t capacity) { |
1457 | + if (!baseAllocator_) |
1458 | + ownBaseAllocator_ = baseAllocator_ = RAPIDJSON_NEW(BaseAllocator()); |
1459 | + ChunkHeader* chunk = reinterpret_cast<ChunkHeader*>(baseAllocator_->Malloc(sizeof(ChunkHeader) + capacity)); |
1460 | + chunk->capacity = capacity; |
1461 | + chunk->size = 0; |
1462 | + chunk->next = chunkHead_; |
1463 | + chunkHead_ = chunk; |
1464 | + } |
1465 | + |
1466 | + static const int kDefaultChunkCapacity = 64 * 1024; //!< Default chunk capacity. |
1467 | + |
1468 | + //! Chunk header for perpending to each chunk. |
1469 | + /*! Chunks are stored as a singly linked list. |
1470 | + */ |
1471 | + struct ChunkHeader { |
1472 | + size_t capacity; //!< Capacity of the chunk in bytes (excluding the header itself). |
1473 | + size_t size; //!< Current size of allocated memory in bytes. |
1474 | + ChunkHeader *next; //!< Next chunk in the linked list. |
1475 | + }; |
1476 | + |
1477 | + ChunkHeader *chunkHead_; //!< Head of the chunk linked-list. Only the head chunk serves allocation. |
1478 | + size_t chunk_capacity_; //!< The minimum capacity of chunk when they are allocated. |
1479 | + void *userBuffer_; //!< User supplied buffer. |
1480 | + BaseAllocator* baseAllocator_; //!< base allocator for allocating memory chunks. |
1481 | + BaseAllocator* ownBaseAllocator_; //!< base allocator created by this object. |
1482 | +}; |
1483 | + |
1484 | +RAPIDJSON_NAMESPACE_END |
1485 | + |
1486 | +#endif // RAPIDJSON_ENCODINGS_H_ |
1487 | |
1488 | === added file 'shorts/xml2json/rapidjson/document.h' |
1489 | --- shorts/xml2json/rapidjson/document.h 1970-01-01 00:00:00 +0000 |
1490 | +++ shorts/xml2json/rapidjson/document.h 2015-12-15 16:05:21 +0000 |
1491 | @@ -0,0 +1,1969 @@ |
1492 | +// Copyright (C) 2011 Milo Yip |
1493 | +// |
1494 | +// Permission is hereby granted, free of charge, to any person obtaining a copy |
1495 | +// of this software and associated documentation files (the "Software"), to deal |
1496 | +// in the Software without restriction, including without limitation the rights |
1497 | +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
1498 | +// copies of the Software, and to permit persons to whom the Software is |
1499 | +// furnished to do so, subject to the following conditions: |
1500 | +// |
1501 | +// The above copyright notice and this permission notice shall be included in |
1502 | +// all copies or substantial portions of the Software. |
1503 | +// |
1504 | +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
1505 | +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
1506 | +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
1507 | +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
1508 | +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
1509 | +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
1510 | +// THE SOFTWARE. |
1511 | + |
1512 | +#ifndef RAPIDJSON_DOCUMENT_H_ |
1513 | +#define RAPIDJSON_DOCUMENT_H_ |
1514 | + |
1515 | +/*! \file document.h */ |
1516 | + |
1517 | +#include "reader.h" |
1518 | +#include "internal/meta.h" |
1519 | +#include "internal/strfunc.h" |
1520 | +#include <new> // placement new |
1521 | + |
1522 | +#ifdef _MSC_VER |
1523 | +RAPIDJSON_DIAG_PUSH |
1524 | +RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant |
1525 | +#elif defined(__GNUC__) |
1526 | +RAPIDJSON_DIAG_PUSH |
1527 | +RAPIDJSON_DIAG_OFF(effc++) |
1528 | +#endif |
1529 | + |
1530 | +/////////////////////////////////////////////////////////////////////////////// |
1531 | +// RAPIDJSON_HAS_STDSTRING |
1532 | + |
1533 | +#ifndef RAPIDJSON_HAS_STDSTRING |
1534 | +#ifdef RAPIDJSON_DOXYGEN_RUNNING |
1535 | +#define RAPIDJSON_HAS_STDSTRING 1 // force generation of documentation |
1536 | +#else |
1537 | +#define RAPIDJSON_HAS_STDSTRING 0 // no std::string support by default |
1538 | +#endif |
1539 | +/*! \def RAPIDJSON_HAS_STDSTRING |
1540 | + \ingroup RAPIDJSON_CONFIG |
1541 | + \brief Enable RapidJSON support for \c std::string |
1542 | + |
1543 | + By defining this preprocessor symbol to \c 1, several convenience functions for using |
1544 | + \ref rapidjson::GenericValue with \c std::string are enabled, especially |
1545 | + for construction and comparison. |
1546 | + |
1547 | + \hideinitializer |
1548 | +*/ |
1549 | +#include <string> |
1550 | +#endif // RAPIDJSON_HAS_STDSTRING |
1551 | + |
1552 | +#ifndef RAPIDJSON_NOMEMBERITERATORCLASS |
1553 | +#include <iterator> // std::iterator, std::random_access_iterator_tag |
1554 | +#endif |
1555 | + |
1556 | +#if RAPIDJSON_HAS_CXX11_RVALUE_REFS |
1557 | +#include <utility> // std::move |
1558 | +#endif |
1559 | + |
1560 | +RAPIDJSON_NAMESPACE_BEGIN |
1561 | + |
1562 | +// Forward declaration. |
1563 | +template <typename Encoding, typename Allocator> |
1564 | +class GenericValue; |
1565 | + |
1566 | +//! Name-value pair in a JSON object value. |
1567 | +/*! |
1568 | + This class was internal to GenericValue. It used to be a inner struct. |
1569 | + But a compiler (IBM XL C/C++ for AIX) have reported to have problem with that so it moved as a namespace scope struct. |
1570 | + https://code.google.com/p/rapidjson/issues/detail?id=64 |
1571 | +*/ |
1572 | +template <typename Encoding, typename Allocator> |
1573 | +struct GenericMember { |
1574 | + GenericValue<Encoding, Allocator> name; //!< name of member (must be a string) |
1575 | + GenericValue<Encoding, Allocator> value; //!< value of member. |
1576 | +}; |
1577 | + |
1578 | +/////////////////////////////////////////////////////////////////////////////// |
1579 | +// GenericMemberIterator |
1580 | + |
1581 | +#ifndef RAPIDJSON_NOMEMBERITERATORCLASS |
1582 | + |
1583 | +//! (Constant) member iterator for a JSON object value |
1584 | +/*! |
1585 | + \tparam Const Is this a constant iterator? |
1586 | + \tparam Encoding Encoding of the value. (Even non-string values need to have the same encoding in a document) |
1587 | + \tparam Allocator Allocator type for allocating memory of object, array and string. |
1588 | + |
1589 | + This class implements a Random Access Iterator for GenericMember elements |
1590 | + of a GenericValue, see ISO/IEC 14882:2003(E) C++ standard, 24.1 [lib.iterator.requirements]. |
1591 | + |
1592 | + \note This iterator implementation is mainly intended to avoid implicit |
1593 | + conversions from iterator values to \c NULL, |
1594 | + e.g. from GenericValue::FindMember. |
1595 | + |
1596 | + \note Define \c RAPIDJSON_NOMEMBERITERATORCLASS to fall back to a |
1597 | + pointer-based implementation, if your platform doesn't provide |
1598 | + the C++ <iterator> header. |
1599 | + |
1600 | + \see GenericMember, GenericValue::MemberIterator, GenericValue::ConstMemberIterator |
1601 | + */ |
1602 | +template <bool Const, typename Encoding, typename Allocator> |
1603 | +class GenericMemberIterator |
1604 | + : public std::iterator<std::random_access_iterator_tag |
1605 | + , typename internal::MaybeAddConst<Const,GenericMember<Encoding,Allocator> >::Type> { |
1606 | + |
1607 | + friend class GenericValue<Encoding,Allocator>; |
1608 | + template <bool, typename, typename> friend class GenericMemberIterator; |
1609 | + |
1610 | + typedef GenericMember<Encoding,Allocator> PlainType; |
1611 | + typedef typename internal::MaybeAddConst<Const,PlainType>::Type ValueType; |
1612 | + typedef std::iterator<std::random_access_iterator_tag,ValueType> BaseType; |
1613 | + |
1614 | +public: |
1615 | + //! Iterator type itself |
1616 | + typedef GenericMemberIterator Iterator; |
1617 | + //! Constant iterator type |
1618 | + typedef GenericMemberIterator<true,Encoding,Allocator> ConstIterator; |
1619 | + //! Non-constant iterator type |
1620 | + typedef GenericMemberIterator<false,Encoding,Allocator> NonConstIterator; |
1621 | + |
1622 | + //! Pointer to (const) GenericMember |
1623 | + typedef typename BaseType::pointer Pointer; |
1624 | + //! Reference to (const) GenericMember |
1625 | + typedef typename BaseType::reference Reference; |
1626 | + //! Signed integer type (e.g. \c ptrdiff_t) |
1627 | + typedef typename BaseType::difference_type DifferenceType; |
1628 | + |
1629 | + //! Default constructor (singular value) |
1630 | + /*! Creates an iterator pointing to no element. |
1631 | + \note All operations, except for comparisons, are undefined on such values. |
1632 | + */ |
1633 | + GenericMemberIterator() : ptr_() {} |
1634 | + |
1635 | + //! Iterator conversions to more const |
1636 | + /*! |
1637 | + \param it (Non-const) iterator to copy from |
1638 | + |
1639 | + Allows the creation of an iterator from another GenericMemberIterator |
1640 | + that is "less const". Especially, creating a non-constant iterator |
1641 | + from a constant iterator are disabled: |
1642 | + \li const -> non-const (not ok) |
1643 | + \li const -> const (ok) |
1644 | + \li non-const -> const (ok) |
1645 | + \li non-const -> non-const (ok) |
1646 | + |
1647 | + \note If the \c Const template parameter is already \c false, this |
1648 | + constructor effectively defines a regular copy-constructor. |
1649 | + Otherwise, the copy constructor is implicitly defined. |
1650 | + */ |
1651 | + GenericMemberIterator(const NonConstIterator & it) : ptr_(it.ptr_) {} |
1652 | + |
1653 | + //! @name stepping |
1654 | + //@{ |
1655 | + Iterator& operator++(){ ++ptr_; return *this; } |
1656 | + Iterator& operator--(){ --ptr_; return *this; } |
1657 | + Iterator operator++(int){ Iterator old(*this); ++ptr_; return old; } |
1658 | + Iterator operator--(int){ Iterator old(*this); --ptr_; return old; } |
1659 | + //@} |
1660 | + |
1661 | + //! @name increment/decrement |
1662 | + //@{ |
1663 | + Iterator operator+(DifferenceType n) const { return Iterator(ptr_+n); } |
1664 | + Iterator operator-(DifferenceType n) const { return Iterator(ptr_-n); } |
1665 | + |
1666 | + Iterator& operator+=(DifferenceType n) { ptr_+=n; return *this; } |
1667 | + Iterator& operator-=(DifferenceType n) { ptr_-=n; return *this; } |
1668 | + //@} |
1669 | + |
1670 | + //! @name relations |
1671 | + //@{ |
1672 | + bool operator==(ConstIterator that) const { return ptr_ == that.ptr_; } |
1673 | + bool operator!=(ConstIterator that) const { return ptr_ != that.ptr_; } |
1674 | + bool operator<=(ConstIterator that) const { return ptr_ <= that.ptr_; } |
1675 | + bool operator>=(ConstIterator that) const { return ptr_ >= that.ptr_; } |
1676 | + bool operator< (ConstIterator that) const { return ptr_ < that.ptr_; } |
1677 | + bool operator> (ConstIterator that) const { return ptr_ > that.ptr_; } |
1678 | + //@} |
1679 | + |
1680 | + //! @name dereference |
1681 | + //@{ |
1682 | + Reference operator*() const { return *ptr_; } |
1683 | + Pointer operator->() const { return ptr_; } |
1684 | + Reference operator[](DifferenceType n) const { return ptr_[n]; } |
1685 | + //@} |
1686 | + |
1687 | + //! Distance |
1688 | + DifferenceType operator-(ConstIterator that) const { return ptr_-that.ptr_; } |
1689 | + |
1690 | +private: |
1691 | + //! Internal constructor from plain pointer |
1692 | + explicit GenericMemberIterator(Pointer p) : ptr_(p) {} |
1693 | + |
1694 | + Pointer ptr_; //!< raw pointer |
1695 | +}; |
1696 | + |
1697 | +#else // RAPIDJSON_NOMEMBERITERATORCLASS |
1698 | + |
1699 | +// class-based member iterator implementation disabled, use plain pointers |
1700 | + |
1701 | +template <bool Const, typename Encoding, typename Allocator> |
1702 | +struct GenericMemberIterator; |
1703 | + |
1704 | +//! non-const GenericMemberIterator |
1705 | +template <typename Encoding, typename Allocator> |
1706 | +struct GenericMemberIterator<false,Encoding,Allocator> { |
1707 | + //! use plain pointer as iterator type |
1708 | + typedef GenericMember<Encoding,Allocator>* Iterator; |
1709 | +}; |
1710 | +//! const GenericMemberIterator |
1711 | +template <typename Encoding, typename Allocator> |
1712 | +struct GenericMemberIterator<true,Encoding,Allocator> { |
1713 | + //! use plain const pointer as iterator type |
1714 | + typedef const GenericMember<Encoding,Allocator>* Iterator; |
1715 | +}; |
1716 | + |
1717 | +#endif // RAPIDJSON_NOMEMBERITERATORCLASS |
1718 | + |
1719 | +/////////////////////////////////////////////////////////////////////////////// |
1720 | +// GenericStringRef |
1721 | + |
1722 | +//! Reference to a constant string (not taking a copy) |
1723 | +/*! |
1724 | + \tparam CharType character type of the string |
1725 | + |
1726 | + This helper class is used to automatically infer constant string |
1727 | + references for string literals, especially from \c const \b (!) |
1728 | + character arrays. |
1729 | + |
1730 | + The main use is for creating JSON string values without copying the |
1731 | + source string via an \ref Allocator. This requires that the referenced |
1732 | + string pointers have a sufficient lifetime, which exceeds the lifetime |
1733 | + of the associated GenericValue. |
1734 | + |
1735 | + \b Example |
1736 | + \code |
1737 | + Value v("foo"); // ok, no need to copy & calculate length |
1738 | + const char foo[] = "foo"; |
1739 | + v.SetString(foo); // ok |
1740 | + |
1741 | + const char* bar = foo; |
1742 | + // Value x(bar); // not ok, can't rely on bar's lifetime |
1743 | + Value x(StringRef(bar)); // lifetime explicitly guaranteed by user |
1744 | + Value y(StringRef(bar, 3)); // ok, explicitly pass length |
1745 | + \endcode |
1746 | + |
1747 | + \see StringRef, GenericValue::SetString |
1748 | +*/ |
1749 | +template<typename CharType> |
1750 | +struct GenericStringRef { |
1751 | + typedef CharType Ch; //!< character type of the string |
1752 | + |
1753 | + //! Create string reference from \c const character array |
1754 | + /*! |
1755 | + This constructor implicitly creates a constant string reference from |
1756 | + a \c const character array. It has better performance than |
1757 | + \ref StringRef(const CharType*) by inferring the string \ref length |
1758 | + from the array length, and also supports strings containing null |
1759 | + characters. |
1760 | + |
1761 | + \tparam N length of the string, automatically inferred |
1762 | + |
1763 | + \param str Constant character array, lifetime assumed to be longer |
1764 | + than the use of the string in e.g. a GenericValue |
1765 | + |
1766 | + \post \ref s == str |
1767 | + |
1768 | + \note Constant complexity. |
1769 | + \note There is a hidden, private overload to disallow references to |
1770 | + non-const character arrays to be created via this constructor. |
1771 | + By this, e.g. function-scope arrays used to be filled via |
1772 | + \c snprintf are excluded from consideration. |
1773 | + In such cases, the referenced string should be \b copied to the |
1774 | + GenericValue instead. |
1775 | + */ |
1776 | + template<SizeType N> |
1777 | + GenericStringRef(const CharType (&str)[N]) RAPIDJSON_NOEXCEPT |
1778 | + : s(str), length(N-1) {} |
1779 | + |
1780 | + //! Explicitly create string reference from \c const character pointer |
1781 | + /*! |
1782 | + This constructor can be used to \b explicitly create a reference to |
1783 | + a constant string pointer. |
1784 | + |
1785 | + \see StringRef(const CharType*) |
1786 | + |
1787 | + \param str Constant character pointer, lifetime assumed to be longer |
1788 | + than the use of the string in e.g. a GenericValue |
1789 | + |
1790 | + \post \ref s == str |
1791 | + |
1792 | + \note There is a hidden, private overload to disallow references to |
1793 | + non-const character arrays to be created via this constructor. |
1794 | + By this, e.g. function-scope arrays used to be filled via |
1795 | + \c snprintf are excluded from consideration. |
1796 | + In such cases, the referenced string should be \b copied to the |
1797 | + GenericValue instead. |
1798 | + */ |
1799 | + explicit GenericStringRef(const CharType* str) |
1800 | + : s(str), length(internal::StrLen(str)){ RAPIDJSON_ASSERT(s != NULL); } |
1801 | + |
1802 | + //! Create constant string reference from pointer and length |
1803 | + /*! \param str constant string, lifetime assumed to be longer than the use of the string in e.g. a GenericValue |
1804 | + \param len length of the string, excluding the trailing NULL terminator |
1805 | + |
1806 | + \post \ref s == str && \ref length == len |
1807 | + \note Constant complexity. |
1808 | + */ |
1809 | + GenericStringRef(const CharType* str, SizeType len) |
1810 | + : s(str), length(len) { RAPIDJSON_ASSERT(s != NULL); } |
1811 | + |
1812 | + //! implicit conversion to plain CharType pointer |
1813 | + operator const Ch *() const { return s; } |
1814 | + |
1815 | + const Ch* const s; //!< plain CharType pointer |
1816 | + const SizeType length; //!< length of the string (excluding the trailing NULL terminator) |
1817 | + |
1818 | +private: |
1819 | + //! Disallow copy-assignment |
1820 | + GenericStringRef operator=(const GenericStringRef&); |
1821 | + //! Disallow construction from non-const array |
1822 | + template<SizeType N> |
1823 | + GenericStringRef(CharType (&str)[N]) /* = delete */; |
1824 | +}; |
1825 | + |
1826 | +//! Mark a character pointer as constant string |
1827 | +/*! Mark a plain character pointer as a "string literal". This function |
1828 | + can be used to avoid copying a character string to be referenced as a |
1829 | + value in a JSON GenericValue object, if the string's lifetime is known |
1830 | + to be valid long enough. |
1831 | + \tparam CharType Character type of the string |
1832 | + \param str Constant string, lifetime assumed to be longer than the use of the string in e.g. a GenericValue |
1833 | + \return GenericStringRef string reference object |
1834 | + \relatesalso GenericStringRef |
1835 | + |
1836 | + \see GenericValue::GenericValue(StringRefType), GenericValue::operator=(StringRefType), GenericValue::SetString(StringRefType), GenericValue::PushBack(StringRefType, Allocator&), GenericValue::AddMember |
1837 | +*/ |
1838 | +template<typename CharType> |
1839 | +inline GenericStringRef<CharType> StringRef(const CharType* str) { |
1840 | + return GenericStringRef<CharType>(str, internal::StrLen(str)); |
1841 | +} |
1842 | + |
1843 | +//! Mark a character pointer as constant string |
1844 | +/*! Mark a plain character pointer as a "string literal". This function |
1845 | + can be used to avoid copying a character string to be referenced as a |
1846 | + value in a JSON GenericValue object, if the string's lifetime is known |
1847 | + to be valid long enough. |
1848 | + |
1849 | + This version has better performance with supplied length, and also |
1850 | + supports string containing null characters. |
1851 | + |
1852 | + \tparam CharType character type of the string |
1853 | + \param str Constant string, lifetime assumed to be longer than the use of the string in e.g. a GenericValue |
1854 | + \param length The length of source string. |
1855 | + \return GenericStringRef string reference object |
1856 | + \relatesalso GenericStringRef |
1857 | +*/ |
1858 | +template<typename CharType> |
1859 | +inline GenericStringRef<CharType> StringRef(const CharType* str, size_t length) { |
1860 | + return GenericStringRef<CharType>(str, SizeType(length)); |
1861 | +} |
1862 | + |
1863 | +#if RAPIDJSON_HAS_STDSTRING |
1864 | +//! Mark a string object as constant string |
1865 | +/*! Mark a string object (e.g. \c std::string) as a "string literal". |
1866 | + This function can be used to avoid copying a string to be referenced as a |
1867 | + value in a JSON GenericValue object, if the string's lifetime is known |
1868 | + to be valid long enough. |
1869 | + |
1870 | + \tparam CharType character type of the string |
1871 | + \param str Constant string, lifetime assumed to be longer than the use of the string in e.g. a GenericValue |
1872 | + \return GenericStringRef string reference object |
1873 | + \relatesalso GenericStringRef |
1874 | + \note Requires the definition of the preprocessor symbol \ref RAPIDJSON_HAS_STDSTRING. |
1875 | +*/ |
1876 | +template<typename CharType> |
1877 | +inline GenericStringRef<CharType> StringRef(const std::basic_string<CharType>& str) { |
1878 | + return GenericStringRef<CharType>(str.data(), SizeType(str.size())); |
1879 | +} |
1880 | +#endif |
1881 | + |
1882 | +/////////////////////////////////////////////////////////////////////////////// |
1883 | +// GenericValue type traits |
1884 | +namespace internal { |
1885 | + |
1886 | +template <typename T, typename Encoding = void, typename Allocator = void> |
1887 | +struct IsGenericValueImpl : FalseType {}; |
1888 | + |
1889 | +// select candidates according to nested encoding and allocator types |
1890 | +template <typename T> struct IsGenericValueImpl<T, typename Void<typename T::EncodingType>::Type, typename Void<typename T::AllocatorType>::Type> |
1891 | + : IsBaseOf<GenericValue<typename T::EncodingType, typename T::AllocatorType>, T>::Type {}; |
1892 | + |
1893 | +// helper to match arbitrary GenericValue instantiations, including derived classes |
1894 | +template <typename T> struct IsGenericValue : IsGenericValueImpl<T>::Type {}; |
1895 | + |
1896 | +} // namespace internal |
1897 | + |
1898 | +/////////////////////////////////////////////////////////////////////////////// |
1899 | +// GenericValue |
1900 | + |
1901 | +//! Represents a JSON value. Use Value for UTF8 encoding and default allocator. |
1902 | +/*! |
1903 | + A JSON value can be one of 7 types. This class is a variant type supporting |
1904 | + these types. |
1905 | + |
1906 | + Use the Value if UTF8 and default allocator |
1907 | + |
1908 | + \tparam Encoding Encoding of the value. (Even non-string values need to have the same encoding in a document) |
1909 | + \tparam Allocator Allocator type for allocating memory of object, array and string. |
1910 | +*/ |
1911 | +template <typename Encoding, typename Allocator = MemoryPoolAllocator<> > |
1912 | +class GenericValue { |
1913 | +public: |
1914 | + //! Name-value pair in an object. |
1915 | + typedef GenericMember<Encoding, Allocator> Member; |
1916 | + typedef Encoding EncodingType; //!< Encoding type from template parameter. |
1917 | + typedef Allocator AllocatorType; //!< Allocator type from template parameter. |
1918 | + typedef typename Encoding::Ch Ch; //!< Character type derived from Encoding. |
1919 | + typedef GenericStringRef<Ch> StringRefType; //!< Reference to a constant string |
1920 | + typedef typename GenericMemberIterator<false,Encoding,Allocator>::Iterator MemberIterator; //!< Member iterator for iterating in object. |
1921 | + typedef typename GenericMemberIterator<true,Encoding,Allocator>::Iterator ConstMemberIterator; //!< Constant member iterator for iterating in object. |
1922 | + typedef GenericValue* ValueIterator; //!< Value iterator for iterating in array. |
1923 | + typedef const GenericValue* ConstValueIterator; //!< Constant value iterator for iterating in array. |
1924 | + |
1925 | + //!@name Constructors and destructor. |
1926 | + //@{ |
1927 | + |
1928 | + //! Default constructor creates a null value. |
1929 | + GenericValue() RAPIDJSON_NOEXCEPT : data_(), flags_(kNullFlag) {} |
1930 | + |
1931 | +#if RAPIDJSON_HAS_CXX11_RVALUE_REFS |
1932 | + //! Move constructor in C++11 |
1933 | + GenericValue(GenericValue&& rhs) RAPIDJSON_NOEXCEPT : data_(rhs.data_), flags_(rhs.flags_) { |
1934 | + rhs.flags_ = kNullFlag; // give up contents |
1935 | + } |
1936 | +#endif |
1937 | + |
1938 | +private: |
1939 | + //! Copy constructor is not permitted. |
1940 | + GenericValue(const GenericValue& rhs); |
1941 | + |
1942 | +public: |
1943 | + |
1944 | + //! Constructor with JSON value type. |
1945 | + /*! This creates a Value of specified type with default content. |
1946 | + \param type Type of the value. |
1947 | + \note Default content for number is zero. |
1948 | + */ |
1949 | + explicit GenericValue(Type type) RAPIDJSON_NOEXCEPT : data_(), flags_() { |
1950 | + static const unsigned defaultFlags[7] = { |
1951 | + kNullFlag, kFalseFlag, kTrueFlag, kObjectFlag, kArrayFlag, kShortStringFlag, |
1952 | + kNumberAnyFlag |
1953 | + }; |
1954 | + RAPIDJSON_ASSERT(type <= kNumberType); |
1955 | + flags_ = defaultFlags[type]; |
1956 | + |
1957 | + // Use ShortString to store empty string. |
1958 | + if (type == kStringType) |
1959 | + data_.ss.SetLength(0); |
1960 | + } |
1961 | + |
1962 | + //! Explicit copy constructor (with allocator) |
1963 | + /*! Creates a copy of a Value by using the given Allocator |
1964 | + \tparam SourceAllocator allocator of \c rhs |
1965 | + \param rhs Value to copy from (read-only) |
1966 | + \param allocator Allocator for allocating copied elements and buffers. Commonly use GenericDocument::GetAllocator(). |
1967 | + \see CopyFrom() |
1968 | + */ |
1969 | + template< typename SourceAllocator > |
1970 | + GenericValue(const GenericValue<Encoding, SourceAllocator>& rhs, Allocator & allocator); |
1971 | + |
1972 | + //! Constructor for boolean value. |
1973 | + /*! \param b Boolean value |
1974 | + \note This constructor is limited to \em real boolean values and rejects |
1975 | + implicitly converted types like arbitrary pointers. Use an explicit cast |
1976 | + to \c bool, if you want to construct a boolean JSON value in such cases. |
1977 | + */ |
1978 | +#ifndef RAPIDJSON_DOXYGEN_RUNNING // hide SFINAE from Doxygen |
1979 | + template <typename T> |
1980 | + explicit GenericValue(T b, RAPIDJSON_ENABLEIF((internal::IsSame<T,bool>))) RAPIDJSON_NOEXCEPT |
1981 | +#else |
1982 | + explicit GenericValue(bool b) RAPIDJSON_NOEXCEPT |
1983 | +#endif |
1984 | + : data_(), flags_(b ? kTrueFlag : kFalseFlag) { |
1985 | + // safe-guard against failing SFINAE |
1986 | + RAPIDJSON_STATIC_ASSERT((internal::IsSame<bool,T>::Value)); |
1987 | + } |
1988 | + |
1989 | + //! Constructor for int value. |
1990 | + explicit GenericValue(int i) RAPIDJSON_NOEXCEPT : data_(), flags_(kNumberIntFlag) { |
1991 | + data_.n.i64 = i; |
1992 | + if (i >= 0) |
1993 | + flags_ |= kUintFlag | kUint64Flag; |
1994 | + } |
1995 | + |
1996 | + //! Constructor for unsigned value. |
1997 | + explicit GenericValue(unsigned u) RAPIDJSON_NOEXCEPT : data_(), flags_(kNumberUintFlag) { |
1998 | + data_.n.u64 = u; |
1999 | + if (!(u & 0x80000000)) |
2000 | + flags_ |= kIntFlag | kInt64Flag; |
2001 | + } |
2002 | + |
2003 | + //! Constructor for int64_t value. |
2004 | + explicit GenericValue(int64_t i64) RAPIDJSON_NOEXCEPT : data_(), flags_(kNumberInt64Flag) { |
2005 | + data_.n.i64 = i64; |
2006 | + if (i64 >= 0) { |
2007 | + flags_ |= kNumberUint64Flag; |
2008 | + if (!(static_cast<uint64_t>(i64) & RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x00000000))) |
2009 | + flags_ |= kUintFlag; |
2010 | + if (!(static_cast<uint64_t>(i64) & RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x80000000))) |
2011 | + flags_ |= kIntFlag; |
2012 | + } |
2013 | + else if (i64 >= static_cast<int64_t>(RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x80000000))) |
2014 | + flags_ |= kIntFlag; |
2015 | + } |
2016 | + |
2017 | + //! Constructor for uint64_t value. |
2018 | + explicit GenericValue(uint64_t u64) RAPIDJSON_NOEXCEPT : data_(), flags_(kNumberUint64Flag) { |
2019 | + data_.n.u64 = u64; |
2020 | + if (!(u64 & RAPIDJSON_UINT64_C2(0x80000000, 0x00000000))) |
2021 | + flags_ |= kInt64Flag; |
2022 | + if (!(u64 & RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x00000000))) |
2023 | + flags_ |= kUintFlag; |
2024 | + if (!(u64 & RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x80000000))) |
2025 | + flags_ |= kIntFlag; |
2026 | + } |
2027 | + |
2028 | + //! Constructor for double value. |
2029 | + explicit GenericValue(double d) RAPIDJSON_NOEXCEPT : data_(), flags_(kNumberDoubleFlag) { data_.n.d = d; } |
2030 | + |
2031 | + //! Constructor for constant string (i.e. do not make a copy of string) |
2032 | + GenericValue(const Ch* s, SizeType length) RAPIDJSON_NOEXCEPT : data_(), flags_() { SetStringRaw(StringRef(s, length)); } |
2033 | + |
2034 | + //! Constructor for constant string (i.e. do not make a copy of string) |
2035 | + explicit GenericValue(StringRefType s) RAPIDJSON_NOEXCEPT : data_(), flags_() { SetStringRaw(s); } |
2036 | + |
2037 | + //! Constructor for copy-string (i.e. do make a copy of string) |
2038 | + GenericValue(const Ch* s, SizeType length, Allocator& allocator) : data_(), flags_() { SetStringRaw(StringRef(s, length), allocator); } |
2039 | + |
2040 | + //! Constructor for copy-string (i.e. do make a copy of string) |
2041 | + GenericValue(const Ch*s, Allocator& allocator) : data_(), flags_() { SetStringRaw(StringRef(s), allocator); } |
2042 | + |
2043 | +#if RAPIDJSON_HAS_STDSTRING |
2044 | + //! Constructor for copy-string from a string object (i.e. do make a copy of string) |
2045 | + /*! \note Requires the definition of the preprocessor symbol \ref RAPIDJSON_HAS_STDSTRING. |
2046 | + */ |
2047 | + GenericValue(const std::basic_string<Ch>& s, Allocator& allocator) : data_(), flags_() { SetStringRaw(StringRef(s), allocator); } |
2048 | +#endif |
2049 | + |
2050 | + //! Destructor. |
2051 | + /*! Need to destruct elements of array, members of object, or copy-string. |
2052 | + */ |
2053 | + ~GenericValue() { |
2054 | + if (Allocator::kNeedFree) { // Shortcut by Allocator's trait |
2055 | + switch(flags_) { |
2056 | + case kArrayFlag: |
2057 | + for (GenericValue* v = data_.a.elements; v != data_.a.elements + data_.a.size; ++v) |
2058 | + v->~GenericValue(); |
2059 | + Allocator::Free(data_.a.elements); |
2060 | + break; |
2061 | + |
2062 | + case kObjectFlag: |
2063 | + for (MemberIterator m = MemberBegin(); m != MemberEnd(); ++m) |
2064 | + m->~Member(); |
2065 | + Allocator::Free(data_.o.members); |
2066 | + break; |
2067 | + |
2068 | + case kCopyStringFlag: |
2069 | + Allocator::Free(const_cast<Ch*>(data_.s.str)); |
2070 | + break; |
2071 | + |
2072 | + default: |
2073 | + break; // Do nothing for other types. |
2074 | + } |
2075 | + } |
2076 | + } |
2077 | + |
2078 | + //@} |
2079 | + |
2080 | + //!@name Assignment operators |
2081 | + //@{ |
2082 | + |
2083 | + //! Assignment with move semantics. |
2084 | + /*! \param rhs Source of the assignment. It will become a null value after assignment. |
2085 | + */ |
2086 | + GenericValue& operator=(GenericValue& rhs) RAPIDJSON_NOEXCEPT { |
2087 | + RAPIDJSON_ASSERT(this != &rhs); |
2088 | + this->~GenericValue(); |
2089 | + RawAssign(rhs); |
2090 | + return *this; |
2091 | + } |
2092 | + |
2093 | +#if RAPIDJSON_HAS_CXX11_RVALUE_REFS |
2094 | + //! Move assignment in C++11 |
2095 | + GenericValue& operator=(GenericValue&& rhs) RAPIDJSON_NOEXCEPT { |
2096 | + return *this = rhs.Move(); |
2097 | + } |
2098 | +#endif |
2099 | + |
2100 | + //! Assignment of constant string reference (no copy) |
2101 | + /*! \param str Constant string reference to be assigned |
2102 | + \note This overload is needed to avoid clashes with the generic primitive type assignment overload below. |
2103 | + \see GenericStringRef, operator=(T) |
2104 | + */ |
2105 | + GenericValue& operator=(StringRefType str) RAPIDJSON_NOEXCEPT { |
2106 | + GenericValue s(str); |
2107 | + return *this = s; |
2108 | + } |
2109 | + |
2110 | + //! Assignment with primitive types. |
2111 | + /*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t |
2112 | + \param value The value to be assigned. |
2113 | + |
2114 | + \note The source type \c T explicitly disallows all pointer types, |
2115 | + especially (\c const) \ref Ch*. This helps avoiding implicitly |
2116 | + referencing character strings with insufficient lifetime, use |
2117 | + \ref SetString(const Ch*, Allocator&) (for copying) or |
2118 | + \ref StringRef() (to explicitly mark the pointer as constant) instead. |
2119 | + All other pointer types would implicitly convert to \c bool, |
2120 | + use \ref SetBool() instead. |
2121 | + */ |
2122 | + template <typename T> |
2123 | + RAPIDJSON_DISABLEIF_RETURN((internal::IsPointer<T>), (GenericValue&)) |
2124 | + operator=(T value) { |
2125 | + GenericValue v(value); |
2126 | + return *this = v; |
2127 | + } |
2128 | + |
2129 | + //! Deep-copy assignment from Value |
2130 | + /*! Assigns a \b copy of the Value to the current Value object |
2131 | + \tparam SourceAllocator Allocator type of \c rhs |
2132 | + \param rhs Value to copy from (read-only) |
2133 | + \param allocator Allocator to use for copying |
2134 | + */ |
2135 | + template <typename SourceAllocator> |
2136 | + GenericValue& CopyFrom(const GenericValue<Encoding, SourceAllocator>& rhs, Allocator& allocator) { |
2137 | + RAPIDJSON_ASSERT((void*)this != (void const*)&rhs); |
2138 | + this->~GenericValue(); |
2139 | + new (this) GenericValue(rhs, allocator); |
2140 | + return *this; |
2141 | + } |
2142 | + |
2143 | + //! Exchange the contents of this value with those of other. |
2144 | + /*! |
2145 | + \param other Another value. |
2146 | + \note Constant complexity. |
2147 | + */ |
2148 | + GenericValue& Swap(GenericValue& other) RAPIDJSON_NOEXCEPT { |
2149 | + GenericValue temp; |
2150 | + temp.RawAssign(*this); |
2151 | + RawAssign(other); |
2152 | + other.RawAssign(temp); |
2153 | + return *this; |
2154 | + } |
2155 | + |
2156 | + //! Prepare Value for move semantics |
2157 | + /*! \return *this */ |
2158 | + GenericValue& Move() RAPIDJSON_NOEXCEPT { return *this; } |
2159 | + //@} |
2160 | + |
2161 | + //!@name Equal-to and not-equal-to operators |
2162 | + //@{ |
2163 | + //! Equal-to operator |
2164 | + /*! |
2165 | + \note If an object contains duplicated named member, comparing equality with any object is always \c false. |
2166 | + \note Linear time complexity (number of all values in the subtree and total lengths of all strings). |
2167 | + */ |
2168 | + template <typename SourceAllocator> |
2169 | + bool operator==(const GenericValue<Encoding, SourceAllocator>& rhs) const { |
2170 | + typedef GenericValue<Encoding, SourceAllocator> RhsType; |
2171 | + if (GetType() != rhs.GetType()) |
2172 | + return false; |
2173 | + |
2174 | + switch (GetType()) { |
2175 | + case kObjectType: // Warning: O(n^2) inner-loop |
2176 | + if (data_.o.size != rhs.data_.o.size) |
2177 | + return false; |
2178 | + for (ConstMemberIterator lhsMemberItr = MemberBegin(); lhsMemberItr != MemberEnd(); ++lhsMemberItr) { |
2179 | + typename RhsType::ConstMemberIterator rhsMemberItr = rhs.FindMember(lhsMemberItr->name); |
2180 | + if (rhsMemberItr == rhs.MemberEnd() || lhsMemberItr->value != rhsMemberItr->value) |
2181 | + return false; |
2182 | + } |
2183 | + return true; |
2184 | + |
2185 | + case kArrayType: |
2186 | + if (data_.a.size != rhs.data_.a.size) |
2187 | + return false; |
2188 | + for (SizeType i = 0; i < data_.a.size; i++) |
2189 | + if ((*this)[i] != rhs[i]) |
2190 | + return false; |
2191 | + return true; |
2192 | + |
2193 | + case kStringType: |
2194 | + return StringEqual(rhs); |
2195 | + |
2196 | + case kNumberType: |
2197 | + if (IsDouble() || rhs.IsDouble()) |
2198 | + return GetDouble() == rhs.GetDouble(); // May convert one operand from integer to double. |
2199 | + else |
2200 | + return data_.n.u64 == rhs.data_.n.u64; |
2201 | + |
2202 | + default: // kTrueType, kFalseType, kNullType |
2203 | + return true; |
2204 | + } |
2205 | + } |
2206 | + |
2207 | + //! Equal-to operator with const C-string pointer |
2208 | + bool operator==(const Ch* rhs) const { return *this == GenericValue(StringRef(rhs)); } |
2209 | + |
2210 | +#if RAPIDJSON_HAS_STDSTRING |
2211 | + //! Equal-to operator with string object |
2212 | + /*! \note Requires the definition of the preprocessor symbol \ref RAPIDJSON_HAS_STDSTRING. |
2213 | + */ |
2214 | + bool operator==(const std::basic_string<Ch>& rhs) const { return *this == GenericValue(StringRef(rhs)); } |
2215 | +#endif |
2216 | + |
2217 | + //! Equal-to operator with primitive types |
2218 | + /*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c double, \c true, \c false |
2219 | + */ |
2220 | + template <typename T> RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>,internal::IsGenericValue<T> >), (bool)) operator==(const T& rhs) const { return *this == GenericValue(rhs); } |
2221 | + |
2222 | + //! Not-equal-to operator |
2223 | + /*! \return !(*this == rhs) |
2224 | + */ |
2225 | + template <typename SourceAllocator> |
2226 | + bool operator!=(const GenericValue<Encoding, SourceAllocator>& rhs) const { return !(*this == rhs); } |
2227 | + |
2228 | + //! Not-equal-to operator with const C-string pointer |
2229 | + bool operator!=(const Ch* rhs) const { return !(*this == rhs); } |
2230 | + |
2231 | + //! Not-equal-to operator with arbitrary types |
2232 | + /*! \return !(*this == rhs) |
2233 | + */ |
2234 | + template <typename T> RAPIDJSON_DISABLEIF_RETURN((internal::IsGenericValue<T>), (bool)) operator!=(const T& rhs) const { return !(*this == rhs); } |
2235 | + |
2236 | + //! Equal-to operator with arbitrary types (symmetric version) |
2237 | + /*! \return (rhs == lhs) |
2238 | + */ |
2239 | + template <typename T> friend RAPIDJSON_DISABLEIF_RETURN((internal::IsGenericValue<T>), (bool)) operator==(const T& lhs, const GenericValue& rhs) { return rhs == lhs; } |
2240 | + |
2241 | + //! Not-Equal-to operator with arbitrary types (symmetric version) |
2242 | + /*! \return !(rhs == lhs) |
2243 | + */ |
2244 | + template <typename T> friend RAPIDJSON_DISABLEIF_RETURN((internal::IsGenericValue<T>), (bool)) operator!=(const T& lhs, const GenericValue& rhs) { return !(rhs == lhs); } |
2245 | + //@} |
2246 | + |
2247 | + //!@name Type |
2248 | + //@{ |
2249 | + |
2250 | + Type GetType() const { return static_cast<Type>(flags_ & kTypeMask); } |
2251 | + bool IsNull() const { return flags_ == kNullFlag; } |
2252 | + bool IsFalse() const { return flags_ == kFalseFlag; } |
2253 | + bool IsTrue() const { return flags_ == kTrueFlag; } |
2254 | + bool IsBool() const { return (flags_ & kBoolFlag) != 0; } |
2255 | + bool IsObject() const { return flags_ == kObjectFlag; } |
2256 | + bool IsArray() const { return flags_ == kArrayFlag; } |
2257 | + bool IsNumber() const { return (flags_ & kNumberFlag) != 0; } |
2258 | + bool IsInt() const { return (flags_ & kIntFlag) != 0; } |
2259 | + bool IsUint() const { return (flags_ & kUintFlag) != 0; } |
2260 | + bool IsInt64() const { return (flags_ & kInt64Flag) != 0; } |
2261 | + bool IsUint64() const { return (flags_ & kUint64Flag) != 0; } |
2262 | + bool IsDouble() const { return (flags_ & kDoubleFlag) != 0; } |
2263 | + bool IsString() const { return (flags_ & kStringFlag) != 0; } |
2264 | + |
2265 | + //@} |
2266 | + |
2267 | + //!@name Null |
2268 | + //@{ |
2269 | + |
2270 | + GenericValue& SetNull() { this->~GenericValue(); new (this) GenericValue(); return *this; } |
2271 | + |
2272 | + //@} |
2273 | + |
2274 | + //!@name Bool |
2275 | + //@{ |
2276 | + |
2277 | + bool GetBool() const { RAPIDJSON_ASSERT(IsBool()); return flags_ == kTrueFlag; } |
2278 | + //!< Set boolean value |
2279 | + /*! \post IsBool() == true */ |
2280 | + GenericValue& SetBool(bool b) { this->~GenericValue(); new (this) GenericValue(b); return *this; } |
2281 | + |
2282 | + //@} |
2283 | + |
2284 | + //!@name Object |
2285 | + //@{ |
2286 | + |
2287 | + //! Set this value as an empty object. |
2288 | + /*! \post IsObject() == true */ |
2289 | + GenericValue& SetObject() { this->~GenericValue(); new (this) GenericValue(kObjectType); return *this; } |
2290 | + |
2291 | + //! Get the number of members in the object. |
2292 | + SizeType MemberCount() const { RAPIDJSON_ASSERT(IsObject()); return data_.o.size; } |
2293 | + |
2294 | + //! Check whether the object is empty. |
2295 | + bool ObjectEmpty() const { RAPIDJSON_ASSERT(IsObject()); return data_.o.size == 0; } |
2296 | + |
2297 | + //! Get a value from an object associated with the name. |
2298 | + /*! \pre IsObject() == true |
2299 | + \tparam T Either \c Ch or \c const \c Ch (template used for disambiguation with \ref operator[](SizeType)) |
2300 | + \note In version 0.1x, if the member is not found, this function returns a null value. This makes issue 7. |
2301 | + Since 0.2, if the name is not correct, it will assert. |
2302 | + If user is unsure whether a member exists, user should use HasMember() first. |
2303 | + A better approach is to use FindMember(). |
2304 | + \note Linear time complexity. |
2305 | + */ |
2306 | + template <typename T> |
2307 | + RAPIDJSON_DISABLEIF_RETURN((internal::NotExpr<internal::IsSame<typename internal::RemoveConst<T>::Type, Ch> >),(GenericValue&)) operator[](T* name) { |
2308 | + GenericValue n(StringRef(name)); |
2309 | + return (*this)[n]; |
2310 | + } |
2311 | + template <typename T> |
2312 | + RAPIDJSON_DISABLEIF_RETURN((internal::NotExpr<internal::IsSame<typename internal::RemoveConst<T>::Type, Ch> >),(const GenericValue&)) operator[](T* name) const { return const_cast<GenericValue&>(*this)[name]; } |
2313 | + |
2314 | + //! Get a value from an object associated with the name. |
2315 | + /*! \pre IsObject() == true |
2316 | + \tparam SourceAllocator Allocator of the \c name value |
2317 | + |
2318 | + \note Compared to \ref operator[](T*), this version is faster because it does not need a StrLen(). |
2319 | + And it can also handle strings with embedded null characters. |
2320 | + |
2321 | + \note Linear time complexity. |
2322 | + */ |
2323 | + template <typename SourceAllocator> |
2324 | + GenericValue& operator[](const GenericValue<Encoding, SourceAllocator>& name) { |
2325 | + MemberIterator member = FindMember(name); |
2326 | + if (member != MemberEnd()) |
2327 | + return member->value; |
2328 | + else { |
2329 | + RAPIDJSON_ASSERT(false); // see above note |
2330 | + static GenericValue NullValue; |
2331 | + return NullValue; |
2332 | + } |
2333 | + } |
2334 | + template <typename SourceAllocator> |
2335 | + const GenericValue& operator[](const GenericValue<Encoding, SourceAllocator>& name) const { return const_cast<GenericValue&>(*this)[name]; } |
2336 | + |
2337 | + //! Const member iterator |
2338 | + /*! \pre IsObject() == true */ |
2339 | + ConstMemberIterator MemberBegin() const { RAPIDJSON_ASSERT(IsObject()); return ConstMemberIterator(data_.o.members); } |
2340 | + //! Const \em past-the-end member iterator |
2341 | + /*! \pre IsObject() == true */ |
2342 | + ConstMemberIterator MemberEnd() const { RAPIDJSON_ASSERT(IsObject()); return ConstMemberIterator(data_.o.members + data_.o.size); } |
2343 | + //! Member iterator |
2344 | + /*! \pre IsObject() == true */ |
2345 | + MemberIterator MemberBegin() { RAPIDJSON_ASSERT(IsObject()); return MemberIterator(data_.o.members); } |
2346 | + //! \em Past-the-end member iterator |
2347 | + /*! \pre IsObject() == true */ |
2348 | + MemberIterator MemberEnd() { RAPIDJSON_ASSERT(IsObject()); return MemberIterator(data_.o.members + data_.o.size); } |
2349 | + |
2350 | + //! Check whether a member exists in the object. |
2351 | + /*! |
2352 | + \param name Member name to be searched. |
2353 | + \pre IsObject() == true |
2354 | + \return Whether a member with that name exists. |
2355 | + \note It is better to use FindMember() directly if you need the obtain the value as well. |
2356 | + \note Linear time complexity. |
2357 | + */ |
2358 | + bool HasMember(const Ch* name) const { return FindMember(name) != MemberEnd(); } |
2359 | + |
2360 | + //! Check whether a member exists in the object with GenericValue name. |
2361 | + /*! |
2362 | + This version is faster because it does not need a StrLen(). It can also handle string with null character. |
2363 | + \param name Member name to be searched. |
2364 | + \pre IsObject() == true |
2365 | + \return Whether a member with that name exists. |
2366 | + \note It is better to use FindMember() directly if you need the obtain the value as well. |
2367 | + \note Linear time complexity. |
2368 | + */ |
2369 | + template <typename SourceAllocator> |
2370 | + bool HasMember(const GenericValue<Encoding, SourceAllocator>& name) const { return FindMember(name) != MemberEnd(); } |
2371 | + |
2372 | + //! Find member by name. |
2373 | + /*! |
2374 | + \param name Member name to be searched. |
2375 | + \pre IsObject() == true |
2376 | + \return Iterator to member, if it exists. |
2377 | + Otherwise returns \ref MemberEnd(). |
2378 | + |
2379 | + \note Earlier versions of Rapidjson returned a \c NULL pointer, in case |
2380 | + the requested member doesn't exist. For consistency with e.g. |
2381 | + \c std::map, this has been changed to MemberEnd() now. |
2382 | + \note Linear time complexity. |
2383 | + */ |
2384 | + MemberIterator FindMember(const Ch* name) { |
2385 | + GenericValue n(StringRef(name)); |
2386 | + return FindMember(n); |
2387 | + } |
2388 | + |
2389 | + ConstMemberIterator FindMember(const Ch* name) const { return const_cast<GenericValue&>(*this).FindMember(name); } |
2390 | + |
2391 | + //! Find member by name. |
2392 | + /*! |
2393 | + This version is faster because it does not need a StrLen(). It can also handle string with null character. |
2394 | + \param name Member name to be searched. |
2395 | + \pre IsObject() == true |
2396 | + \return Iterator to member, if it exists. |
2397 | + Otherwise returns \ref MemberEnd(). |
2398 | + |
2399 | + \note Earlier versions of Rapidjson returned a \c NULL pointer, in case |
2400 | + the requested member doesn't exist. For consistency with e.g. |
2401 | + \c std::map, this has been changed to MemberEnd() now. |
2402 | + \note Linear time complexity. |
2403 | + */ |
2404 | + template <typename SourceAllocator> |
2405 | + MemberIterator FindMember(const GenericValue<Encoding, SourceAllocator>& name) { |
2406 | + RAPIDJSON_ASSERT(IsObject()); |
2407 | + RAPIDJSON_ASSERT(name.IsString()); |
2408 | + MemberIterator member = MemberBegin(); |
2409 | + for ( ; member != MemberEnd(); ++member) |
2410 | + if (name.StringEqual(member->name)) |
2411 | + break; |
2412 | + return member; |
2413 | + } |
2414 | + template <typename SourceAllocator> ConstMemberIterator FindMember(const GenericValue<Encoding, SourceAllocator>& name) const { return const_cast<GenericValue&>(*this).FindMember(name); } |
2415 | + |
2416 | + //! Add a member (name-value pair) to the object. |
2417 | + /*! \param name A string value as name of member. |
2418 | + \param value Value of any type. |
2419 | + \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator(). |
2420 | + \return The value itself for fluent API. |
2421 | + \note The ownership of \c name and \c value will be transferred to this object on success. |
2422 | + \pre IsObject() && name.IsString() |
2423 | + \post name.IsNull() && value.IsNull() |
2424 | + \note Amortized Constant time complexity. |
2425 | + */ |
2426 | + GenericValue& AddMember(GenericValue& name, GenericValue& value, Allocator& allocator) { |
2427 | + RAPIDJSON_ASSERT(IsObject()); |
2428 | + RAPIDJSON_ASSERT(name.IsString()); |
2429 | + |
2430 | + Object& o = data_.o; |
2431 | + if (o.size >= o.capacity) { |
2432 | + if (o.capacity == 0) { |
2433 | + o.capacity = kDefaultObjectCapacity; |
2434 | + o.members = reinterpret_cast<Member*>(allocator.Malloc(o.capacity * sizeof(Member))); |
2435 | + } |
2436 | + else { |
2437 | + SizeType oldCapacity = o.capacity; |
2438 | + o.capacity += (oldCapacity + 1) / 2; // grow by factor 1.5 |
2439 | + o.members = reinterpret_cast<Member*>(allocator.Realloc(o.members, oldCapacity * sizeof(Member), o.capacity * sizeof(Member))); |
2440 | + } |
2441 | + } |
2442 | + o.members[o.size].name.RawAssign(name); |
2443 | + o.members[o.size].value.RawAssign(value); |
2444 | + o.size++; |
2445 | + return *this; |
2446 | + } |
2447 | + |
2448 | + //! Add a constant string value as member (name-value pair) to the object. |
2449 | + /*! \param name A string value as name of member. |
2450 | + \param value constant string reference as value of member. |
2451 | + \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator(). |
2452 | + \return The value itself for fluent API. |
2453 | + \pre IsObject() |
2454 | + \note This overload is needed to avoid clashes with the generic primitive type AddMember(GenericValue&,T,Allocator&) overload below. |
2455 | + \note Amortized Constant time complexity. |
2456 | + */ |
2457 | + GenericValue& AddMember(GenericValue& name, StringRefType value, Allocator& allocator) { |
2458 | + GenericValue v(value); |
2459 | + return AddMember(name, v, allocator); |
2460 | + } |
2461 | + |
2462 | + //! Add any primitive value as member (name-value pair) to the object. |
2463 | + /*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t |
2464 | + \param name A string value as name of member. |
2465 | + \param value Value of primitive type \c T as value of member |
2466 | + \param allocator Allocator for reallocating memory. Commonly use GenericDocument::GetAllocator(). |
2467 | + \return The value itself for fluent API. |
2468 | + \pre IsObject() |
2469 | + |
2470 | + \note The source type \c T explicitly disallows all pointer types, |
2471 | + especially (\c const) \ref Ch*. This helps avoiding implicitly |
2472 | + referencing character strings with insufficient lifetime, use |
2473 | + \ref AddMember(StringRefType, GenericValue&, Allocator&) or \ref |
2474 | + AddMember(StringRefType, StringRefType, Allocator&). |
2475 | + All other pointer types would implicitly convert to \c bool, |
2476 | + use an explicit cast instead, if needed. |
2477 | + \note Amortized Constant time complexity. |
2478 | + */ |
2479 | + template <typename T> |
2480 | + RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >), (GenericValue&)) |
2481 | + AddMember(GenericValue& name, T value, Allocator& allocator) { |
2482 | + GenericValue v(value); |
2483 | + return AddMember(name, v, allocator); |
2484 | + } |
2485 | + |
2486 | +#if RAPIDJSON_HAS_CXX11_RVALUE_REFS |
2487 | + GenericValue& AddMember(GenericValue&& name, GenericValue&& value, Allocator& allocator) { |
2488 | + return AddMember(name, value, allocator); |
2489 | + } |
2490 | + GenericValue& AddMember(GenericValue&& name, GenericValue& value, Allocator& allocator) { |
2491 | + return AddMember(name, value, allocator); |
2492 | + } |
2493 | + GenericValue& AddMember(GenericValue& name, GenericValue&& value, Allocator& allocator) { |
2494 | + return AddMember(name, value, allocator); |
2495 | + } |
2496 | + GenericValue& AddMember(StringRefType name, GenericValue&& value, Allocator& allocator) { |
2497 | + GenericValue n(name); |
2498 | + return AddMember(n, value, allocator); |
2499 | + } |
2500 | +#endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS |
2501 | + |
2502 | + |
2503 | + //! Add a member (name-value pair) to the object. |
2504 | + /*! \param name A constant string reference as name of member. |
2505 | + \param value Value of any type. |
2506 | + \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator(). |
2507 | + \return The value itself for fluent API. |
2508 | + \note The ownership of \c value will be transferred to this object on success. |
2509 | + \pre IsObject() |
2510 | + \post value.IsNull() |
2511 | + \note Amortized Constant time complexity. |
2512 | + */ |
2513 | + GenericValue& AddMember(StringRefType name, GenericValue& value, Allocator& allocator) { |
2514 | + GenericValue n(name); |
2515 | + return AddMember(n, value, allocator); |
2516 | + } |
2517 | + |
2518 | + //! Add a constant string value as member (name-value pair) to the object. |
2519 | + /*! \param name A constant string reference as name of member. |
2520 | + \param value constant string reference as value of member. |
2521 | + \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator(). |
2522 | + \return The value itself for fluent API. |
2523 | + \pre IsObject() |
2524 | + \note This overload is needed to avoid clashes with the generic primitive type AddMember(StringRefType,T,Allocator&) overload below. |
2525 | + \note Amortized Constant time complexity. |
2526 | + */ |
2527 | + GenericValue& AddMember(StringRefType name, StringRefType value, Allocator& allocator) { |
2528 | + GenericValue v(value); |
2529 | + return AddMember(name, v, allocator); |
2530 | + } |
2531 | + |
2532 | + //! Add any primitive value as member (name-value pair) to the object. |
2533 | + /*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t |
2534 | + \param name A constant string reference as name of member. |
2535 | + \param value Value of primitive type \c T as value of member |
2536 | + \param allocator Allocator for reallocating memory. Commonly use GenericDocument::GetAllocator(). |
2537 | + \return The value itself for fluent API. |
2538 | + \pre IsObject() |
2539 | + |
2540 | + \note The source type \c T explicitly disallows all pointer types, |
2541 | + especially (\c const) \ref Ch*. This helps avoiding implicitly |
2542 | + referencing character strings with insufficient lifetime, use |
2543 | + \ref AddMember(StringRefType, GenericValue&, Allocator&) or \ref |
2544 | + AddMember(StringRefType, StringRefType, Allocator&). |
2545 | + All other pointer types would implicitly convert to \c bool, |
2546 | + use an explicit cast instead, if needed. |
2547 | + \note Amortized Constant time complexity. |
2548 | + */ |
2549 | + template <typename T> |
2550 | + RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >), (GenericValue&)) |
2551 | + AddMember(StringRefType name, T value, Allocator& allocator) { |
2552 | + GenericValue n(name); |
2553 | + return AddMember(n, value, allocator); |
2554 | + } |
2555 | + |
2556 | + //! Remove all members in the object. |
2557 | + /*! This function do not deallocate memory in the object, i.e. the capacity is unchanged. |
2558 | + \note Linear time complexity. |
2559 | + */ |
2560 | + void RemoveAllMembers() { |
2561 | + RAPIDJSON_ASSERT(IsObject()); |
2562 | + for (MemberIterator m = MemberBegin(); m != MemberEnd(); ++m) |
2563 | + m->~Member(); |
2564 | + data_.o.size = 0; |
2565 | + } |
2566 | + |
2567 | + //! Remove a member in object by its name. |
2568 | + /*! \param name Name of member to be removed. |
2569 | + \return Whether the member existed. |
2570 | + \note This function may reorder the object members. Use \ref |
2571 | + EraseMember(ConstMemberIterator) if you need to preserve the |
2572 | + relative order of the remaining members. |
2573 | + \note Linear time complexity. |
2574 | + */ |
2575 | + bool RemoveMember(const Ch* name) { |
2576 | + GenericValue n(StringRef(name)); |
2577 | + return RemoveMember(n); |
2578 | + } |
2579 | + |
2580 | + template <typename SourceAllocator> |
2581 | + bool RemoveMember(const GenericValue<Encoding, SourceAllocator>& name) { |
2582 | + MemberIterator m = FindMember(name); |
2583 | + if (m != MemberEnd()) { |
2584 | + RemoveMember(m); |
2585 | + return true; |
2586 | + } |
2587 | + else |
2588 | + return false; |
2589 | + } |
2590 | + |
2591 | + //! Remove a member in object by iterator. |
2592 | + /*! \param m member iterator (obtained by FindMember() or MemberBegin()). |
2593 | + \return the new iterator after removal. |
2594 | + \note This function may reorder the object members. Use \ref |
2595 | + EraseMember(ConstMemberIterator) if you need to preserve the |
2596 | + relative order of the remaining members. |
2597 | + \note Constant time complexity. |
2598 | + */ |
2599 | + MemberIterator RemoveMember(MemberIterator m) { |
2600 | + RAPIDJSON_ASSERT(IsObject()); |
2601 | + RAPIDJSON_ASSERT(data_.o.size > 0); |
2602 | + RAPIDJSON_ASSERT(data_.o.members != 0); |
2603 | + RAPIDJSON_ASSERT(m >= MemberBegin() && m < MemberEnd()); |
2604 | + |
2605 | + MemberIterator last(data_.o.members + (data_.o.size - 1)); |
2606 | + if (data_.o.size > 1 && m != last) { |
2607 | + // Move the last one to this place |
2608 | + *m = *last; |
2609 | + } |
2610 | + else { |
2611 | + // Only one left, just destroy |
2612 | + m->~Member(); |
2613 | + } |
2614 | + --data_.o.size; |
2615 | + return m; |
2616 | + } |
2617 | + |
2618 | + //! Remove a member from an object by iterator. |
2619 | + /*! \param pos iterator to the member to remove |
2620 | + \pre IsObject() == true && \ref MemberBegin() <= \c pos < \ref MemberEnd() |
2621 | + \return Iterator following the removed element. |
2622 | + If the iterator \c pos refers to the last element, the \ref MemberEnd() iterator is returned. |
2623 | + \note This function preserves the relative order of the remaining object |
2624 | + members. If you do not need this, use the more efficient \ref RemoveMember(MemberIterator). |
2625 | + \note Linear time complexity. |
2626 | + */ |
2627 | + MemberIterator EraseMember(ConstMemberIterator pos) { |
2628 | + return EraseMember(pos, pos +1); |
2629 | + } |
2630 | + |
2631 | + //! Remove members in the range [first, last) from an object. |
2632 | + /*! \param first iterator to the first member to remove |
2633 | + \param last iterator following the last member to remove |
2634 | + \pre IsObject() == true && \ref MemberBegin() <= \c first <= \c last <= \ref MemberEnd() |
2635 | + \return Iterator following the last removed element. |
2636 | + \note This function preserves the relative order of the remaining object |
2637 | + members. |
2638 | + \note Linear time complexity. |
2639 | + */ |
2640 | + MemberIterator EraseMember(ConstMemberIterator first, ConstMemberIterator last) { |
2641 | + RAPIDJSON_ASSERT(IsObject()); |
2642 | + RAPIDJSON_ASSERT(data_.o.size > 0); |
2643 | + RAPIDJSON_ASSERT(data_.o.members != 0); |
2644 | + RAPIDJSON_ASSERT(first >= MemberBegin()); |
2645 | + RAPIDJSON_ASSERT(first <= last); |
2646 | + RAPIDJSON_ASSERT(last <= MemberEnd()); |
2647 | + |
2648 | + MemberIterator pos = MemberBegin() + (first - MemberBegin()); |
2649 | + for (MemberIterator itr = pos; itr != last; ++itr) |
2650 | + itr->~Member(); |
2651 | + std::memmove(&*pos, &*last, (MemberEnd() - last) * sizeof(Member)); |
2652 | + data_.o.size -= (last - first); |
2653 | + return pos; |
2654 | + } |
2655 | + |
2656 | + //@} |
2657 | + |
2658 | + //!@name Array |
2659 | + //@{ |
2660 | + |
2661 | + //! Set this value as an empty array. |
2662 | + /*! \post IsArray == true */ |
2663 | + GenericValue& SetArray() { this->~GenericValue(); new (this) GenericValue(kArrayType); return *this; } |
2664 | + |
2665 | + //! Get the number of elements in array. |
2666 | + SizeType Size() const { RAPIDJSON_ASSERT(IsArray()); return data_.a.size; } |
2667 | + |
2668 | + //! Get the capacity of array. |
2669 | + SizeType Capacity() const { RAPIDJSON_ASSERT(IsArray()); return data_.a.capacity; } |
2670 | + |
2671 | + //! Check whether the array is empty. |
2672 | + bool Empty() const { RAPIDJSON_ASSERT(IsArray()); return data_.a.size == 0; } |
2673 | + |
2674 | + //! Remove all elements in the array. |
2675 | + /*! This function do not deallocate memory in the array, i.e. the capacity is unchanged. |
2676 | + \note Linear time complexity. |
2677 | + */ |
2678 | + void Clear() { |
2679 | + RAPIDJSON_ASSERT(IsArray()); |
2680 | + for (SizeType i = 0; i < data_.a.size; ++i) |
2681 | + data_.a.elements[i].~GenericValue(); |
2682 | + data_.a.size = 0; |
2683 | + } |
2684 | + |
2685 | + //! Get an element from array by index. |
2686 | + /*! \pre IsArray() == true |
2687 | + \param index Zero-based index of element. |
2688 | + \see operator[](T*) |
2689 | + */ |
2690 | + GenericValue& operator[](SizeType index) { |
2691 | + RAPIDJSON_ASSERT(IsArray()); |
2692 | + RAPIDJSON_ASSERT(index < data_.a.size); |
2693 | + return data_.a.elements[index]; |
2694 | + } |
2695 | + const GenericValue& operator[](SizeType index) const { return const_cast<GenericValue&>(*this)[index]; } |
2696 | + |
2697 | + //! Element iterator |
2698 | + /*! \pre IsArray() == true */ |
2699 | + ValueIterator Begin() { RAPIDJSON_ASSERT(IsArray()); return data_.a.elements; } |
2700 | + //! \em Past-the-end element iterator |
2701 | + /*! \pre IsArray() == true */ |
2702 | + ValueIterator End() { RAPIDJSON_ASSERT(IsArray()); return data_.a.elements + data_.a.size; } |
2703 | + //! Constant element iterator |
2704 | + /*! \pre IsArray() == true */ |
2705 | + ConstValueIterator Begin() const { return const_cast<GenericValue&>(*this).Begin(); } |
2706 | + //! Constant \em past-the-end element iterator |
2707 | + /*! \pre IsArray() == true */ |
2708 | + ConstValueIterator End() const { return const_cast<GenericValue&>(*this).End(); } |
2709 | + |
2710 | + //! Request the array to have enough capacity to store elements. |
2711 | + /*! \param newCapacity The capacity that the array at least need to have. |
2712 | + \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator(). |
2713 | + \return The value itself for fluent API. |
2714 | + \note Linear time complexity. |
2715 | + */ |
2716 | + GenericValue& Reserve(SizeType newCapacity, Allocator &allocator) { |
2717 | + RAPIDJSON_ASSERT(IsArray()); |
2718 | + if (newCapacity > data_.a.capacity) { |
2719 | + data_.a.elements = (GenericValue*)allocator.Realloc(data_.a.elements, data_.a.capacity * sizeof(GenericValue), newCapacity * sizeof(GenericValue)); |
2720 | + data_.a.capacity = newCapacity; |
2721 | + } |
2722 | + return *this; |
2723 | + } |
2724 | + |
2725 | + //! Append a GenericValue at the end of the array. |
2726 | + /*! \param value Value to be appended. |
2727 | + \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator(). |
2728 | + \pre IsArray() == true |
2729 | + \post value.IsNull() == true |
2730 | + \return The value itself for fluent API. |
2731 | + \note The ownership of \c value will be transferred to this array on success. |
2732 | + \note If the number of elements to be appended is known, calls Reserve() once first may be more efficient. |
2733 | + \note Amortized constant time complexity. |
2734 | + */ |
2735 | + GenericValue& PushBack(GenericValue& value, Allocator& allocator) { |
2736 | + RAPIDJSON_ASSERT(IsArray()); |
2737 | + if (data_.a.size >= data_.a.capacity) |
2738 | + Reserve(data_.a.capacity == 0 ? kDefaultArrayCapacity : (data_.a.capacity + (data_.a.capacity + 1) / 2), allocator); |
2739 | + data_.a.elements[data_.a.size++].RawAssign(value); |
2740 | + return *this; |
2741 | + } |
2742 | + |
2743 | +#if RAPIDJSON_HAS_CXX11_RVALUE_REFS |
2744 | + GenericValue& PushBack(GenericValue&& value, Allocator& allocator) { |
2745 | + return PushBack(value, allocator); |
2746 | + } |
2747 | +#endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS |
2748 | + |
2749 | + //! Append a constant string reference at the end of the array. |
2750 | + /*! \param value Constant string reference to be appended. |
2751 | + \param allocator Allocator for reallocating memory. It must be the same one used previously. Commonly use GenericDocument::GetAllocator(). |
2752 | + \pre IsArray() == true |
2753 | + \return The value itself for fluent API. |
2754 | + \note If the number of elements to be appended is known, calls Reserve() once first may be more efficient. |
2755 | + \note Amortized constant time complexity. |
2756 | + \see GenericStringRef |
2757 | + */ |
2758 | + GenericValue& PushBack(StringRefType value, Allocator& allocator) { |
2759 | + return (*this).template PushBack<StringRefType>(value, allocator); |
2760 | + } |
2761 | + |
2762 | + //! Append a primitive value at the end of the array. |
2763 | + /*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t |
2764 | + \param value Value of primitive type T to be appended. |
2765 | + \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator(). |
2766 | + \pre IsArray() == true |
2767 | + \return The value itself for fluent API. |
2768 | + \note If the number of elements to be appended is known, calls Reserve() once first may be more efficient. |
2769 | + |
2770 | + \note The source type \c T explicitly disallows all pointer types, |
2771 | + especially (\c const) \ref Ch*. This helps avoiding implicitly |
2772 | + referencing character strings with insufficient lifetime, use |
2773 | + \ref PushBack(GenericValue&, Allocator&) or \ref |
2774 | + PushBack(StringRefType, Allocator&). |
2775 | + All other pointer types would implicitly convert to \c bool, |
2776 | + use an explicit cast instead, if needed. |
2777 | + \note Amortized constant time complexity. |
2778 | + */ |
2779 | + template <typename T> |
2780 | + RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >), (GenericValue&)) |
2781 | + PushBack(T value, Allocator& allocator) { |
2782 | + GenericValue v(value); |
2783 | + return PushBack(v, allocator); |
2784 | + } |
2785 | + |
2786 | + //! Remove the last element in the array. |
2787 | + /*! |
2788 | + \note Constant time complexity. |
2789 | + */ |
2790 | + GenericValue& PopBack() { |
2791 | + RAPIDJSON_ASSERT(IsArray()); |
2792 | + RAPIDJSON_ASSERT(!Empty()); |
2793 | + data_.a.elements[--data_.a.size].~GenericValue(); |
2794 | + return *this; |
2795 | + } |
2796 | + |
2797 | + //! Remove an element of array by iterator. |
2798 | + /*! |
2799 | + \param pos iterator to the element to remove |
2800 | + \pre IsArray() == true && \ref Begin() <= \c pos < \ref End() |
2801 | + \return Iterator following the removed element. If the iterator pos refers to the last element, the End() iterator is returned. |
2802 | + \note Linear time complexity. |
2803 | + */ |
2804 | + ValueIterator Erase(ConstValueIterator pos) { |
2805 | + return Erase(pos, pos + 1); |
2806 | + } |
2807 | + |
2808 | + //! Remove elements in the range [first, last) of the array. |
2809 | + /*! |
2810 | + \param first iterator to the first element to remove |
2811 | + \param last iterator following the last element to remove |
2812 | + \pre IsArray() == true && \ref Begin() <= \c first <= \c last <= \ref End() |
2813 | + \return Iterator following the last removed element. |
2814 | + \note Linear time complexity. |
2815 | + */ |
2816 | + ValueIterator Erase(ConstValueIterator first, ConstValueIterator last) { |
2817 | + RAPIDJSON_ASSERT(IsArray()); |
2818 | + RAPIDJSON_ASSERT(data_.a.size > 0); |
2819 | + RAPIDJSON_ASSERT(data_.a.elements != 0); |
2820 | + RAPIDJSON_ASSERT(first >= Begin()); |
2821 | + RAPIDJSON_ASSERT(first <= last); |
2822 | + RAPIDJSON_ASSERT(last <= End()); |
2823 | + ValueIterator pos = Begin() + (first - Begin()); |
2824 | + for (ValueIterator itr = pos; itr != last; ++itr) |
2825 | + itr->~GenericValue(); |
2826 | + std::memmove(pos, last, (End() - last) * sizeof(GenericValue)); |
2827 | + data_.a.size -= (last - first); |
2828 | + return pos; |
2829 | + } |
2830 | + |
2831 | + //@} |
2832 | + |
2833 | + //!@name Number |
2834 | + //@{ |
2835 | + |
2836 | + int GetInt() const { RAPIDJSON_ASSERT(flags_ & kIntFlag); return data_.n.i.i; } |
2837 | + unsigned GetUint() const { RAPIDJSON_ASSERT(flags_ & kUintFlag); return data_.n.u.u; } |
2838 | + int64_t GetInt64() const { RAPIDJSON_ASSERT(flags_ & kInt64Flag); return data_.n.i64; } |
2839 | + uint64_t GetUint64() const { RAPIDJSON_ASSERT(flags_ & kUint64Flag); return data_.n.u64; } |
2840 | + |
2841 | + double GetDouble() const { |
2842 | + RAPIDJSON_ASSERT(IsNumber()); |
2843 | + if ((flags_ & kDoubleFlag) != 0) return data_.n.d; // exact type, no conversion. |
2844 | + if ((flags_ & kIntFlag) != 0) return data_.n.i.i; // int -> double |
2845 | + if ((flags_ & kUintFlag) != 0) return data_.n.u.u; // unsigned -> double |
2846 | + if ((flags_ & kInt64Flag) != 0) return (double)data_.n.i64; // int64_t -> double (may lose precision) |
2847 | + RAPIDJSON_ASSERT((flags_ & kUint64Flag) != 0); return (double)data_.n.u64; // uint64_t -> double (may lose precision) |
2848 | + } |
2849 | + |
2850 | + GenericValue& SetInt(int i) { this->~GenericValue(); new (this) GenericValue(i); return *this; } |
2851 | + GenericValue& SetUint(unsigned u) { this->~GenericValue(); new (this) GenericValue(u); return *this; } |
2852 | + GenericValue& SetInt64(int64_t i64) { this->~GenericValue(); new (this) GenericValue(i64); return *this; } |
2853 | + GenericValue& SetUint64(uint64_t u64) { this->~GenericValue(); new (this) GenericValue(u64); return *this; } |
2854 | + GenericValue& SetDouble(double d) { this->~GenericValue(); new (this) GenericValue(d); return *this; } |
2855 | + |
2856 | + //@} |
2857 | + |
2858 | + //!@name String |
2859 | + //@{ |
2860 | + |
2861 | + const Ch* GetString() const { RAPIDJSON_ASSERT(IsString()); return ((flags_ & kInlineStrFlag) ? data_.ss.str : data_.s.str); } |
2862 | + |
2863 | + //! Get the length of string. |
2864 | + /*! Since rapidjson permits "\\u0000" in the json string, strlen(v.GetString()) may not equal to v.GetStringLength(). |
2865 | + */ |
2866 | + SizeType GetStringLength() const { RAPIDJSON_ASSERT(IsString()); return ((flags_ & kInlineStrFlag) ? (data_.ss.GetLength()) : data_.s.length); } |
2867 | + |
2868 | + //! Set this value as a string without copying source string. |
2869 | + /*! This version has better performance with supplied length, and also support string containing null character. |
2870 | + \param s source string pointer. |
2871 | + \param length The length of source string, excluding the trailing null terminator. |
2872 | + \return The value itself for fluent API. |
2873 | + \post IsString() == true && GetString() == s && GetStringLength() == length |
2874 | + \see SetString(StringRefType) |
2875 | + */ |
2876 | + GenericValue& SetString(const Ch* s, SizeType length) { return SetString(StringRef(s, length)); } |
2877 | + |
2878 | + //! Set this value as a string without copying source string. |
2879 | + /*! \param s source string reference |
2880 | + \return The value itself for fluent API. |
2881 | + \post IsString() == true && GetString() == s && GetStringLength() == s.length |
2882 | + */ |
2883 | + GenericValue& SetString(StringRefType s) { this->~GenericValue(); SetStringRaw(s); return *this; } |
2884 | + |
2885 | + //! Set this value as a string by copying from source string. |
2886 | + /*! This version has better performance with supplied length, and also support string containing null character. |
2887 | + \param s source string. |
2888 | + \param length The length of source string, excluding the trailing null terminator. |
2889 | + \param allocator Allocator for allocating copied buffer. Commonly use GenericDocument::GetAllocator(). |
2890 | + \return The value itself for fluent API. |
2891 | + \post IsString() == true && GetString() != s && strcmp(GetString(),s) == 0 && GetStringLength() == length |
2892 | + */ |
2893 | + GenericValue& SetString(const Ch* s, SizeType length, Allocator& allocator) { this->~GenericValue(); SetStringRaw(StringRef(s, length), allocator); return *this; } |
2894 | + |
2895 | + //! Set this value as a string by copying from source string. |
2896 | + /*! \param s source string. |
2897 | + \param allocator Allocator for allocating copied buffer. Commonly use GenericDocument::GetAllocator(). |
2898 | + \return The value itself for fluent API. |
2899 | + \post IsString() == true && GetString() != s && strcmp(GetString(),s) == 0 && GetStringLength() == length |
2900 | + */ |
2901 | + GenericValue& SetString(const Ch* s, Allocator& allocator) { return SetString(s, internal::StrLen(s), allocator); } |
2902 | + |
2903 | +#if RAPIDJSON_HAS_STDSTRING |
2904 | + //! Set this value as a string by copying from source string. |
2905 | + /*! \param s source string. |
2906 | + \param allocator Allocator for allocating copied buffer. Commonly use GenericDocument::GetAllocator(). |
2907 | + \return The value itself for fluent API. |
2908 | + \post IsString() == true && GetString() != s.data() && strcmp(GetString(),s.data() == 0 && GetStringLength() == s.size() |
2909 | + \note Requires the definition of the preprocessor symbol \ref RAPIDJSON_HAS_STDSTRING. |
2910 | + */ |
2911 | + GenericValue& SetString(const std::basic_string<Ch>& s, Allocator& allocator) { return SetString(s.data(), s.size(), allocator); } |
2912 | +#endif |
2913 | + |
2914 | + //@} |
2915 | + |
2916 | + //! Generate events of this value to a Handler. |
2917 | + /*! This function adopts the GoF visitor pattern. |
2918 | + Typical usage is to output this JSON value as JSON text via Writer, which is a Handler. |
2919 | + It can also be used to deep clone this value via GenericDocument, which is also a Handler. |
2920 | + \tparam Handler type of handler. |
2921 | + \param handler An object implementing concept Handler. |
2922 | + */ |
2923 | + template <typename Handler> |
2924 | + bool Accept(Handler& handler) const { |
2925 | + switch(GetType()) { |
2926 | + case kNullType: return handler.Null(); |
2927 | + case kFalseType: return handler.Bool(false); |
2928 | + case kTrueType: return handler.Bool(true); |
2929 | + |
2930 | + case kObjectType: |
2931 | + if (!handler.StartObject()) |
2932 | + return false; |
2933 | + for (ConstMemberIterator m = MemberBegin(); m != MemberEnd(); ++m) { |
2934 | + RAPIDJSON_ASSERT(m->name.IsString()); // User may change the type of name by MemberIterator. |
2935 | + if (!handler.Key(m->name.GetString(), m->name.GetStringLength(), (m->name.flags_ & kCopyFlag) != 0)) |
2936 | + return false; |
2937 | + if (!m->value.Accept(handler)) |
2938 | + return false; |
2939 | + } |
2940 | + return handler.EndObject(data_.o.size); |
2941 | + |
2942 | + case kArrayType: |
2943 | + if (!handler.StartArray()) |
2944 | + return false; |
2945 | + for (GenericValue* v = data_.a.elements; v != data_.a.elements + data_.a.size; ++v) |
2946 | + if (!v->Accept(handler)) |
2947 | + return false; |
2948 | + return handler.EndArray(data_.a.size); |
2949 | + |
2950 | + case kStringType: |
2951 | + return handler.String(GetString(), GetStringLength(), (flags_ & kCopyFlag) != 0); |
2952 | + |
2953 | + case kNumberType: |
2954 | + if (IsInt()) return handler.Int(data_.n.i.i); |
2955 | + else if (IsUint()) return handler.Uint(data_.n.u.u); |
2956 | + else if (IsInt64()) return handler.Int64(data_.n.i64); |
2957 | + else if (IsUint64()) return handler.Uint64(data_.n.u64); |
2958 | + else return handler.Double(data_.n.d); |
2959 | + |
2960 | + default: |
2961 | + RAPIDJSON_ASSERT(false); |
2962 | + } |
2963 | + return false; |
2964 | + } |
2965 | + |
2966 | +private: |
2967 | + template <typename, typename> friend class GenericValue; |
2968 | + template <typename, typename, typename> friend class GenericDocument; |
2969 | + |
2970 | + enum { |
2971 | + kBoolFlag = 0x100, |
2972 | + kNumberFlag = 0x200, |
2973 | + kIntFlag = 0x400, |
2974 | + kUintFlag = 0x800, |
2975 | + kInt64Flag = 0x1000, |
2976 | + kUint64Flag = 0x2000, |
2977 | + kDoubleFlag = 0x4000, |
2978 | + kStringFlag = 0x100000, |
2979 | + kCopyFlag = 0x200000, |
2980 | + kInlineStrFlag = 0x400000, |
2981 | + |
2982 | + // Initial flags of different types. |
2983 | + kNullFlag = kNullType, |
2984 | + kTrueFlag = kTrueType | kBoolFlag, |
2985 | + kFalseFlag = kFalseType | kBoolFlag, |
2986 | + kNumberIntFlag = kNumberType | kNumberFlag | kIntFlag | kInt64Flag, |
2987 | + kNumberUintFlag = kNumberType | kNumberFlag | kUintFlag | kUint64Flag | kInt64Flag, |
2988 | + kNumberInt64Flag = kNumberType | kNumberFlag | kInt64Flag, |
2989 | + kNumberUint64Flag = kNumberType | kNumberFlag | kUint64Flag, |
2990 | + kNumberDoubleFlag = kNumberType | kNumberFlag | kDoubleFlag, |
2991 | + kNumberAnyFlag = kNumberType | kNumberFlag | kIntFlag | kInt64Flag | kUintFlag | kUint64Flag | kDoubleFlag, |
2992 | + kConstStringFlag = kStringType | kStringFlag, |
2993 | + kCopyStringFlag = kStringType | kStringFlag | kCopyFlag, |
2994 | + kShortStringFlag = kStringType | kStringFlag | kCopyFlag | kInlineStrFlag, |
2995 | + kObjectFlag = kObjectType, |
2996 | + kArrayFlag = kArrayType, |
2997 | + |
2998 | + kTypeMask = 0xFF // bitwise-and with mask of 0xFF can be optimized by compiler |
2999 | + }; |
3000 | + |
3001 | + static const SizeType kDefaultArrayCapacity = 16; |
3002 | + static const SizeType kDefaultObjectCapacity = 16; |
3003 | + |
3004 | + struct String { |
3005 | + const Ch* str; |
3006 | + SizeType length; |
3007 | + unsigned hashcode; //!< reserved |
3008 | + }; // 12 bytes in 32-bit mode, 16 bytes in 64-bit mode |
3009 | + |
3010 | + // implementation detail: ShortString can represent zero-terminated strings up to MaxSize chars |
3011 | + // (excluding the terminating zero) and store a value to determine the length of the contained |
3012 | + // string in the last character str[LenPos] by storing "MaxSize - length" there. If the string |
3013 | + // to store has the maximal length of MaxSize then str[LenPos] will be 0 and therefore act as |
3014 | + // the string terminator as well. For getting the string length back from that value just use |
3015 | + // "MaxSize - str[LenPos]". |
3016 | + // This allows to store 11-chars strings in 32-bit mode and 15-chars strings in 64-bit mode |
3017 | + // inline (for `UTF8`-encoded strings). |
3018 | + struct ShortString { |
3019 | + enum { MaxChars = sizeof(String) / sizeof(Ch), MaxSize = MaxChars - 1, LenPos = MaxSize }; |
3020 | + Ch str[MaxChars]; |
3021 | + |
3022 | + inline static bool Usable(SizeType len) { return (MaxSize >= len); } |
3023 | + inline void SetLength(SizeType len) { str[LenPos] = (Ch)(MaxSize - len); } |
3024 | + inline SizeType GetLength() const { return (SizeType)(MaxSize - str[LenPos]); } |
3025 | + }; // at most as many bytes as "String" above => 12 bytes in 32-bit mode, 16 bytes in 64-bit mode |
3026 | + |
3027 | + // By using proper binary layout, retrieval of different integer types do not need conversions. |
3028 | + union Number { |
3029 | +#if RAPIDJSON_ENDIAN == RAPIDJSON_LITTLEENDIAN |
3030 | + struct I { |
3031 | + int i; |
3032 | + char padding[4]; |
3033 | + }i; |
3034 | + struct U { |
3035 | + unsigned u; |
3036 | + char padding2[4]; |
3037 | + }u; |
3038 | +#else |
3039 | + struct I { |
3040 | + char padding[4]; |
3041 | + int i; |
3042 | + }i; |
3043 | + struct U { |
3044 | + char padding2[4]; |
3045 | + unsigned u; |
3046 | + }u; |
3047 | +#endif |
3048 | + int64_t i64; |
3049 | + uint64_t u64; |
3050 | + double d; |
3051 | + }; // 8 bytes |
3052 | + |
3053 | + struct Object { |
3054 | + Member* members; |
3055 | + SizeType size; |
3056 | + SizeType capacity; |
3057 | + }; // 12 bytes in 32-bit mode, 16 bytes in 64-bit mode |
3058 | + |
3059 | + struct Array { |
3060 | + GenericValue* elements; |
3061 | + SizeType size; |
3062 | + SizeType capacity; |
3063 | + }; // 12 bytes in 32-bit mode, 16 bytes in 64-bit mode |
3064 | + |
3065 | + union Data { |
3066 | + String s; |
3067 | + ShortString ss; |
3068 | + Number n; |
3069 | + Object o; |
3070 | + Array a; |
3071 | + }; // 12 bytes in 32-bit mode, 16 bytes in 64-bit mode |
3072 | + |
3073 | + // Initialize this value as array with initial data, without calling destructor. |
3074 | + void SetArrayRaw(GenericValue* values, SizeType count, Allocator& allocator) { |
3075 | + flags_ = kArrayFlag; |
3076 | + data_.a.elements = (GenericValue*)allocator.Malloc(count * sizeof(GenericValue)); |
3077 | + std::memcpy(data_.a.elements, values, count * sizeof(GenericValue)); |
3078 | + data_.a.size = data_.a.capacity = count; |
3079 | + } |
3080 | + |
3081 | + //! Initialize this value as object with initial data, without calling destructor. |
3082 | + void SetObjectRaw(Member* members, SizeType count, Allocator& allocator) { |
3083 | + flags_ = kObjectFlag; |
3084 | + data_.o.members = (Member*)allocator.Malloc(count * sizeof(Member)); |
3085 | + std::memcpy(data_.o.members, members, count * sizeof(Member)); |
3086 | + data_.o.size = data_.o.capacity = count; |
3087 | + } |
3088 | + |
3089 | + //! Initialize this value as constant string, without calling destructor. |
3090 | + void SetStringRaw(StringRefType s) RAPIDJSON_NOEXCEPT { |
3091 | + flags_ = kConstStringFlag; |
3092 | + data_.s.str = s; |
3093 | + data_.s.length = s.length; |
3094 | + } |
3095 | + |
3096 | + //! Initialize this value as copy string with initial data, without calling destructor. |
3097 | + void SetStringRaw(StringRefType s, Allocator& allocator) { |
3098 | + Ch* str = NULL; |
3099 | + if(ShortString::Usable(s.length)) { |
3100 | + flags_ = kShortStringFlag; |
3101 | + data_.ss.SetLength(s.length); |
3102 | + str = data_.ss.str; |
3103 | + } else { |
3104 | + flags_ = kCopyStringFlag; |
3105 | + data_.s.length = s.length; |
3106 | + str = (Ch *)allocator.Malloc((s.length + 1) * sizeof(Ch)); |
3107 | + data_.s.str = str; |
3108 | + } |
3109 | + std::memcpy(str, s, s.length * sizeof(Ch)); |
3110 | + str[s.length] = '\0'; |
3111 | + } |
3112 | + |
3113 | + //! Assignment without calling destructor |
3114 | + void RawAssign(GenericValue& rhs) RAPIDJSON_NOEXCEPT { |
3115 | + data_ = rhs.data_; |
3116 | + flags_ = rhs.flags_; |
3117 | + rhs.flags_ = kNullFlag; |
3118 | + } |
3119 | + |
3120 | + template <typename SourceAllocator> |
3121 | + bool StringEqual(const GenericValue<Encoding, SourceAllocator>& rhs) const { |
3122 | + RAPIDJSON_ASSERT(IsString()); |
3123 | + RAPIDJSON_ASSERT(rhs.IsString()); |
3124 | + |
3125 | + const SizeType len1 = GetStringLength(); |
3126 | + const SizeType len2 = rhs.GetStringLength(); |
3127 | + if(len1 != len2) { return false; } |
3128 | + |
3129 | + const Ch* const str1 = GetString(); |
3130 | + const Ch* const str2 = rhs.GetString(); |
3131 | + if(str1 == str2) { return true; } // fast path for constant string |
3132 | + |
3133 | + return (std::memcmp(str1, str2, sizeof(Ch) * len1) == 0); |
3134 | + } |
3135 | + |
3136 | + Data data_; |
3137 | + unsigned flags_; |
3138 | +}; |
3139 | + |
3140 | +//! GenericValue with UTF8 encoding |
3141 | +typedef GenericValue<UTF8<> > Value; |
3142 | + |
3143 | +/////////////////////////////////////////////////////////////////////////////// |
3144 | +// GenericDocument |
3145 | + |
3146 | +//! A document for parsing JSON text as DOM. |
3147 | +/*! |
3148 | + \note implements Handler concept |
3149 | + \tparam Encoding Encoding for both parsing and string storage. |
3150 | + \tparam Allocator Allocator for allocating memory for the DOM |
3151 | + \tparam StackAllocator Allocator for allocating memory for stack during parsing. |
3152 | + \warning Although GenericDocument inherits from GenericValue, the API does \b not provide any virtual functions, especially no virtual destructor. To avoid memory leaks, do not \c delete a GenericDocument object via a pointer to a GenericValue. |
3153 | +*/ |
3154 | +template <typename Encoding, typename Allocator = MemoryPoolAllocator<>, typename StackAllocator = CrtAllocator> |
3155 | +class GenericDocument : public GenericValue<Encoding, Allocator> { |
3156 | +public: |
3157 | + typedef typename Encoding::Ch Ch; //!< Character type derived from Encoding. |
3158 | + typedef GenericValue<Encoding, Allocator> ValueType; //!< Value type of the document. |
3159 | + typedef Allocator AllocatorType; //!< Allocator type from template parameter. |
3160 | + |
3161 | + //! Constructor |
3162 | + /*! \param allocator Optional allocator for allocating memory. |
3163 | + \param stackCapacity Optional initial capacity of stack in bytes. |
3164 | + \param stackAllocator Optional allocator for allocating memory for stack. |
3165 | + */ |
3166 | + GenericDocument(Allocator* allocator = 0, size_t stackCapacity = kDefaultStackCapacity, StackAllocator* stackAllocator = 0) : |
3167 | + allocator_(allocator), ownAllocator_(0), stack_(stackAllocator, stackCapacity), parseResult_() |
3168 | + { |
3169 | + if (!allocator_) |
3170 | + ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator()); |
3171 | + } |
3172 | + |
3173 | +#if RAPIDJSON_HAS_CXX11_RVALUE_REFS |
3174 | + //! Move constructor in C++11 |
3175 | + GenericDocument(GenericDocument&& rhs) RAPIDJSON_NOEXCEPT |
3176 | + : ValueType(std::move(rhs)), |
3177 | + allocator_(rhs.allocator_), |
3178 | + ownAllocator_(rhs.ownAllocator_), |
3179 | + stack_(std::move(rhs.stack_)), |
3180 | + parseResult_(rhs.parseResult_) |
3181 | + { |
3182 | + rhs.allocator_ = 0; |
3183 | + rhs.ownAllocator_ = 0; |
3184 | + rhs.parseResult_ = ParseResult(); |
3185 | + } |
3186 | +#endif |
3187 | + |
3188 | + ~GenericDocument() { |
3189 | + Destroy(); |
3190 | + } |
3191 | + |
3192 | +#if RAPIDJSON_HAS_CXX11_RVALUE_REFS |
3193 | + //! Move assignment in C++11 |
3194 | + GenericDocument& operator=(GenericDocument&& rhs) RAPIDJSON_NOEXCEPT |
3195 | + { |
3196 | + // The cast to ValueType is necessary here, because otherwise it would |
3197 | + // attempt to call GenericValue's templated assignment operator. |
3198 | + ValueType::operator=(std::forward<ValueType>(rhs)); |
3199 | + |
3200 | + // Calling the destructor here would prematurely call stack_'s destructor |
3201 | + Destroy(); |
3202 | + |
3203 | + allocator_ = rhs.allocator_; |
3204 | + ownAllocator_ = rhs.ownAllocator_; |
3205 | + stack_ = std::move(rhs.stack_); |
3206 | + parseResult_ = rhs.parseResult_; |
3207 | + |
3208 | + rhs.allocator_ = 0; |
3209 | + rhs.ownAllocator_ = 0; |
3210 | + rhs.parseResult_ = ParseResult(); |
3211 | + |
3212 | + return *this; |
3213 | + } |
3214 | +#endif |
3215 | + |
3216 | + //!@name Parse from stream |
3217 | + //!@{ |
3218 | + |
3219 | + //! Parse JSON text from an input stream (with Encoding conversion) |
3220 | + /*! \tparam parseFlags Combination of \ref ParseFlag. |
3221 | + \tparam SourceEncoding Encoding of input stream |
3222 | + \tparam InputStream Type of input stream, implementing Stream concept |
3223 | + \param is Input stream to be parsed. |
3224 | + \return The document itself for fluent API. |
3225 | + */ |
3226 | + template <unsigned parseFlags, typename SourceEncoding, typename InputStream> |
3227 | + GenericDocument& ParseStream(InputStream& is) { |
3228 | + ValueType::SetNull(); // Remove existing root if exist |
3229 | + GenericReader<SourceEncoding, Encoding, Allocator> reader(&GetAllocator()); |
3230 | + ClearStackOnExit scope(*this); |
3231 | + parseResult_ = reader.template Parse<parseFlags>(is, *this); |
3232 | + if (parseResult_) { |
3233 | + RAPIDJSON_ASSERT(stack_.GetSize() == sizeof(ValueType)); // Got one and only one root object |
3234 | + this->RawAssign(*stack_.template Pop<ValueType>(1)); // Add this-> to prevent issue 13. |
3235 | + } |
3236 | + return *this; |
3237 | + } |
3238 | + |
3239 | + //! Parse JSON text from an input stream |
3240 | + /*! \tparam parseFlags Combination of \ref ParseFlag. |
3241 | + \tparam InputStream Type of input stream, implementing Stream concept |
3242 | + \param is Input stream to be parsed. |
3243 | + \return The document itself for fluent API. |
3244 | + */ |
3245 | + template <unsigned parseFlags, typename InputStream> |
3246 | + GenericDocument& ParseStream(InputStream& is) { |
3247 | + return ParseStream<parseFlags,Encoding,InputStream>(is); |
3248 | + } |
3249 | + |
3250 | + //! Parse JSON text from an input stream (with \ref kParseDefaultFlags) |
3251 | + /*! \tparam InputStream Type of input stream, implementing Stream concept |
3252 | + \param is Input stream to be parsed. |
3253 | + \return The document itself for fluent API. |
3254 | + */ |
3255 | + template <typename InputStream> |
3256 | + GenericDocument& ParseStream(InputStream& is) { |
3257 | + return ParseStream<kParseDefaultFlags, Encoding, InputStream>(is); |
3258 | + } |
3259 | + //!@} |
3260 | + |
3261 | + //!@name Parse in-place from mutable string |
3262 | + //!@{ |
3263 | + |
3264 | + //! Parse JSON text from a mutable string (with Encoding conversion) |
3265 | + /*! \tparam parseFlags Combination of \ref ParseFlag. |
3266 | + \tparam SourceEncoding Transcoding from input Encoding |
3267 | + \param str Mutable zero-terminated string to be parsed. |
3268 | + \return The document itself for fluent API. |
3269 | + */ |
3270 | + template <unsigned parseFlags, typename SourceEncoding> |
3271 | + GenericDocument& ParseInsitu(Ch* str) { |
3272 | + GenericInsituStringStream<Encoding> s(str); |
3273 | + return ParseStream<parseFlags | kParseInsituFlag, SourceEncoding>(s); |
3274 | + } |
3275 | + |
3276 | + //! Parse JSON text from a mutable string |
3277 | + /*! \tparam parseFlags Combination of \ref ParseFlag. |
3278 | + \param str Mutable zero-terminated string to be parsed. |
3279 | + \return The document itself for fluent API. |
3280 | + */ |
3281 | + template <unsigned parseFlags> |
3282 | + GenericDocument& ParseInsitu(Ch* str) { |
3283 | + return ParseInsitu<parseFlags, Encoding>(str); |
3284 | + } |
3285 | + |
3286 | + //! Parse JSON text from a mutable string (with \ref kParseDefaultFlags) |
3287 | + /*! \param str Mutable zero-terminated string to be parsed. |
3288 | + \return The document itself for fluent API. |
3289 | + */ |
3290 | + GenericDocument& ParseInsitu(Ch* str) { |
3291 | + return ParseInsitu<kParseDefaultFlags, Encoding>(str); |
3292 | + } |
3293 | + //!@} |
3294 | + |
3295 | + //!@name Parse from read-only string |
3296 | + //!@{ |
3297 | + |
3298 | + //! Parse JSON text from a read-only string (with Encoding conversion) |
3299 | + /*! \tparam parseFlags Combination of \ref ParseFlag (must not contain \ref kParseInsituFlag). |
3300 | + \tparam SourceEncoding Transcoding from input Encoding |
3301 | + \param str Read-only zero-terminated string to be parsed. |
3302 | + */ |
3303 | + template <unsigned parseFlags, typename SourceEncoding> |
3304 | + GenericDocument& Parse(const Ch* str) { |
3305 | + RAPIDJSON_ASSERT(!(parseFlags & kParseInsituFlag)); |
3306 | + GenericStringStream<SourceEncoding> s(str); |
3307 | + return ParseStream<parseFlags, SourceEncoding>(s); |
3308 | + } |
3309 | + |
3310 | + //! Parse JSON text from a read-only string |
3311 | + /*! \tparam parseFlags Combination of \ref ParseFlag (must not contain \ref kParseInsituFlag). |
3312 | + \param str Read-only zero-terminated string to be parsed. |
3313 | + */ |
3314 | + template <unsigned parseFlags> |
3315 | + GenericDocument& Parse(const Ch* str) { |
3316 | + return Parse<parseFlags, Encoding>(str); |
3317 | + } |
3318 | + |
3319 | + //! Parse JSON text from a read-only string (with \ref kParseDefaultFlags) |
3320 | + /*! \param str Read-only zero-terminated string to be parsed. |
3321 | + */ |
3322 | + GenericDocument& Parse(const Ch* str) { |
3323 | + return Parse<kParseDefaultFlags>(str); |
3324 | + } |
3325 | + //!@} |
3326 | + |
3327 | + //!@name Handling parse errors |
3328 | + //!@{ |
3329 | + |
3330 | + //! Whether a parse error has occured in the last parsing. |
3331 | + bool HasParseError() const { return parseResult_.IsError(); } |
3332 | + |
3333 | + //! Get the \ref ParseErrorCode of last parsing. |
3334 | + ParseErrorCode GetParseError() const { return parseResult_.Code(); } |
3335 | + |
3336 | + //! Get the position of last parsing error in input, 0 otherwise. |
3337 | + size_t GetErrorOffset() const { return parseResult_.Offset(); } |
3338 | + |
3339 | + //!@} |
3340 | + |
3341 | + //! Get the allocator of this document. |
3342 | + Allocator& GetAllocator() { return *allocator_; } |
3343 | + |
3344 | + //! Get the capacity of stack in bytes. |
3345 | + size_t GetStackCapacity() const { return stack_.GetCapacity(); } |
3346 | + |
3347 | +private: |
3348 | + // clear stack on any exit from ParseStream, e.g. due to exception |
3349 | + struct ClearStackOnExit { |
3350 | + explicit ClearStackOnExit(GenericDocument& d) : d_(d) {} |
3351 | + ~ClearStackOnExit() { d_.ClearStack(); } |
3352 | + private: |
3353 | + ClearStackOnExit(const ClearStackOnExit&); |
3354 | + ClearStackOnExit& operator=(const ClearStackOnExit&); |
3355 | + GenericDocument& d_; |
3356 | + }; |
3357 | + |
3358 | + // callers of the following private Handler functions |
3359 | + template <typename,typename,typename> friend class GenericReader; // for parsing |
3360 | + template <typename, typename> friend class GenericValue; // for deep copying |
3361 | + |
3362 | + // Implementation of Handler |
3363 | + bool Null() { new (stack_.template Push<ValueType>()) ValueType(); return true; } |
3364 | + bool Bool(bool b) { new (stack_.template Push<ValueType>()) ValueType(b); return true; } |
3365 | + bool Int(int i) { new (stack_.template Push<ValueType>()) ValueType(i); return true; } |
3366 | + bool Uint(unsigned i) { new (stack_.template Push<ValueType>()) ValueType(i); return true; } |
3367 | + bool Int64(int64_t i) { new (stack_.template Push<ValueType>()) ValueType(i); return true; } |
3368 | + bool Uint64(uint64_t i) { new (stack_.template Push<ValueType>()) ValueType(i); return true; } |
3369 | + bool Double(double d) { new (stack_.template Push<ValueType>()) ValueType(d); return true; } |
3370 | + |
3371 | + bool String(const Ch* str, SizeType length, bool copy) { |
3372 | + if (copy) |
3373 | + new (stack_.template Push<ValueType>()) ValueType(str, length, GetAllocator()); |
3374 | + else |
3375 | + new (stack_.template Push<ValueType>()) ValueType(str, length); |
3376 | + return true; |
3377 | + } |
3378 | + |
3379 | + bool StartObject() { new (stack_.template Push<ValueType>()) ValueType(kObjectType); return true; } |
3380 | + |
3381 | + bool Key(const Ch* str, SizeType length, bool copy) { return String(str, length, copy); } |
3382 | + |
3383 | + bool EndObject(SizeType memberCount) { |
3384 | + typename ValueType::Member* members = stack_.template Pop<typename ValueType::Member>(memberCount); |
3385 | + stack_.template Top<ValueType>()->SetObjectRaw(members, (SizeType)memberCount, GetAllocator()); |
3386 | + return true; |
3387 | + } |
3388 | + |
3389 | + bool StartArray() { new (stack_.template Push<ValueType>()) ValueType(kArrayType); return true; } |
3390 | + |
3391 | + bool EndArray(SizeType elementCount) { |
3392 | + ValueType* elements = stack_.template Pop<ValueType>(elementCount); |
3393 | + stack_.template Top<ValueType>()->SetArrayRaw(elements, elementCount, GetAllocator()); |
3394 | + return true; |
3395 | + } |
3396 | + |
3397 | +private: |
3398 | + //! Prohibit copying |
3399 | + GenericDocument(const GenericDocument&); |
3400 | + //! Prohibit assignment |
3401 | + GenericDocument& operator=(const GenericDocument&); |
3402 | + |
3403 | + void ClearStack() { |
3404 | + if (Allocator::kNeedFree) |
3405 | + while (stack_.GetSize() > 0) // Here assumes all elements in stack array are GenericValue (Member is actually 2 GenericValue objects) |
3406 | + (stack_.template Pop<ValueType>(1))->~ValueType(); |
3407 | + else |
3408 | + stack_.Clear(); |
3409 | + stack_.ShrinkToFit(); |
3410 | + } |
3411 | + |
3412 | + void Destroy() { |
3413 | + RAPIDJSON_DELETE(ownAllocator_); |
3414 | + } |
3415 | + |
3416 | + static const size_t kDefaultStackCapacity = 1024; |
3417 | + Allocator* allocator_; |
3418 | + Allocator* ownAllocator_; |
3419 | + internal::Stack<StackAllocator> stack_; |
3420 | + ParseResult parseResult_; |
3421 | +}; |
3422 | + |
3423 | +//! GenericDocument with UTF8 encoding |
3424 | +typedef GenericDocument<UTF8<> > Document; |
3425 | + |
3426 | +// defined here due to the dependency on GenericDocument |
3427 | +template <typename Encoding, typename Allocator> |
3428 | +template <typename SourceAllocator> |
3429 | +inline |
3430 | +GenericValue<Encoding,Allocator>::GenericValue(const GenericValue<Encoding,SourceAllocator>& rhs, Allocator& allocator) |
3431 | +{ |
3432 | + switch (rhs.GetType()) { |
3433 | + case kObjectType: |
3434 | + case kArrayType: { // perform deep copy via SAX Handler |
3435 | + GenericDocument<Encoding,Allocator> d(&allocator); |
3436 | + rhs.Accept(d); |
3437 | + RawAssign(*d.stack_.template Pop<GenericValue>(1)); |
3438 | + } |
3439 | + break; |
3440 | + case kStringType: |
3441 | + if (rhs.flags_ == kConstStringFlag) { |
3442 | + flags_ = rhs.flags_; |
3443 | + data_ = *reinterpret_cast<const Data*>(&rhs.data_); |
3444 | + } else { |
3445 | + SetStringRaw(StringRef(rhs.GetString(), rhs.GetStringLength()), allocator); |
3446 | + } |
3447 | + break; |
3448 | + default: // kNumberType, kTrueType, kFalseType, kNullType |
3449 | + flags_ = rhs.flags_; |
3450 | + data_ = *reinterpret_cast<const Data*>(&rhs.data_); |
3451 | + } |
3452 | +} |
3453 | + |
3454 | +RAPIDJSON_NAMESPACE_END |
3455 | + |
3456 | +#if defined(_MSC_VER) || defined(__GNUC__) |
3457 | +RAPIDJSON_DIAG_POP |
3458 | +#endif |
3459 | + |
3460 | +#endif // RAPIDJSON_DOCUMENT_H_ |
3461 | |
3462 | === added file 'shorts/xml2json/rapidjson/encodedstream.h' |
3463 | --- shorts/xml2json/rapidjson/encodedstream.h 1970-01-01 00:00:00 +0000 |
3464 | +++ shorts/xml2json/rapidjson/encodedstream.h 2015-12-15 16:05:21 +0000 |
3465 | @@ -0,0 +1,290 @@ |
3466 | +// Copyright (C) 2011 Milo Yip |
3467 | +// |
3468 | +// Permission is hereby granted, free of charge, to any person obtaining a copy |
3469 | +// of this software and associated documentation files (the "Software"), to deal |
3470 | +// in the Software without restriction, including without limitation the rights |
3471 | +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
3472 | +// copies of the Software, and to permit persons to whom the Software is |
3473 | +// furnished to do so, subject to the following conditions: |
3474 | +// |
3475 | +// The above copyright notice and this permission notice shall be included in |
3476 | +// all copies or substantial portions of the Software. |
3477 | +// |
3478 | +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
3479 | +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
3480 | +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
3481 | +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
3482 | +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
3483 | +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
3484 | +// THE SOFTWARE. |
3485 | + |
3486 | +#ifndef RAPIDJSON_ENCODEDSTREAM_H_ |
3487 | +#define RAPIDJSON_ENCODEDSTREAM_H_ |
3488 | + |
3489 | +#include "rapidjson.h" |
3490 | + |
3491 | +#ifdef __GNUC__ |
3492 | +RAPIDJSON_DIAG_PUSH |
3493 | +RAPIDJSON_DIAG_OFF(effc++) |
3494 | +#endif |
3495 | + |
3496 | +RAPIDJSON_NAMESPACE_BEGIN |
3497 | + |
3498 | +//! Input byte stream wrapper with a statically bound encoding. |
3499 | +/*! |
3500 | + \tparam Encoding The interpretation of encoding of the stream. Either UTF8, UTF16LE, UTF16BE, UTF32LE, UTF32BE. |
3501 | + \tparam InputByteStream Type of input byte stream. For example, FileReadStream. |
3502 | +*/ |
3503 | +template <typename Encoding, typename InputByteStream> |
3504 | +class EncodedInputStream { |
3505 | + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); |
3506 | +public: |
3507 | + typedef typename Encoding::Ch Ch; |
3508 | + |
3509 | + EncodedInputStream(InputByteStream& is) : is_(is) { |
3510 | + current_ = Encoding::TakeBOM(is_); |
3511 | + } |
3512 | + |
3513 | + Ch Peek() const { return current_; } |
3514 | + Ch Take() { Ch c = current_; current_ = Encoding::Take(is_); return c; } |
3515 | + size_t Tell() const { return is_.Tell(); } |
3516 | + |
3517 | + // Not implemented |
3518 | + void Put(Ch) { RAPIDJSON_ASSERT(false); } |
3519 | + void Flush() { RAPIDJSON_ASSERT(false); } |
3520 | + Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } |
3521 | + size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } |
3522 | + |
3523 | +private: |
3524 | + EncodedInputStream(const EncodedInputStream&); |
3525 | + EncodedInputStream& operator=(const EncodedInputStream&); |
3526 | + |
3527 | + InputByteStream& is_; |
3528 | + Ch current_; |
3529 | +}; |
3530 | + |
3531 | +//! Output byte stream wrapper with statically bound encoding. |
3532 | +/*! |
3533 | + \tparam Encoding The interpretation of encoding of the stream. Either UTF8, UTF16LE, UTF16BE, UTF32LE, UTF32BE. |
3534 | + \tparam InputByteStream Type of input byte stream. For example, FileWriteStream. |
3535 | +*/ |
3536 | +template <typename Encoding, typename OutputByteStream> |
3537 | +class EncodedOutputStream { |
3538 | + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); |
3539 | +public: |
3540 | + typedef typename Encoding::Ch Ch; |
3541 | + |
3542 | + EncodedOutputStream(OutputByteStream& os, bool putBOM = true) : os_(os) { |
3543 | + if (putBOM) |
3544 | + Encoding::PutBOM(os_); |
3545 | + } |
3546 | + |
3547 | + void Put(Ch c) { Encoding::Put(os_, c); } |
3548 | + void Flush() { os_.Flush(); } |
3549 | + |
3550 | + // Not implemented |
3551 | + Ch Peek() const { RAPIDJSON_ASSERT(false); } |
3552 | + Ch Take() { RAPIDJSON_ASSERT(false); } |
3553 | + size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; } |
3554 | + Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } |
3555 | + size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } |
3556 | + |
3557 | +private: |
3558 | + EncodedOutputStream(const EncodedOutputStream&); |
3559 | + EncodedOutputStream& operator=(const EncodedOutputStream&); |
3560 | + |
3561 | + OutputByteStream& os_; |
3562 | +}; |
3563 | + |
3564 | +#define RAPIDJSON_ENCODINGS_FUNC(x) UTF8<Ch>::x, UTF16LE<Ch>::x, UTF16BE<Ch>::x, UTF32LE<Ch>::x, UTF32BE<Ch>::x |
3565 | + |
3566 | +//! Input stream wrapper with dynamically bound encoding and automatic encoding detection. |
3567 | +/*! |
3568 | + \tparam CharType Type of character for reading. |
3569 | + \tparam InputByteStream type of input byte stream to be wrapped. |
3570 | +*/ |
3571 | +template <typename CharType, typename InputByteStream> |
3572 | +class AutoUTFInputStream { |
3573 | + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); |
3574 | +public: |
3575 | + typedef CharType Ch; |
3576 | + |
3577 | + //! Constructor. |
3578 | + /*! |
3579 | + \param is input stream to be wrapped. |
3580 | + \param type UTF encoding type if it is not detected from the stream. |
3581 | + */ |
3582 | + AutoUTFInputStream(InputByteStream& is, UTFType type = kUTF8) : is_(&is), type_(type), hasBOM_(false) { |
3583 | + DetectType(); |
3584 | + static const TakeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Take) }; |
3585 | + takeFunc_ = f[type_]; |
3586 | + current_ = takeFunc_(*is_); |
3587 | + } |
3588 | + |
3589 | + UTFType GetType() const { return type_; } |
3590 | + bool HasBOM() const { return hasBOM_; } |
3591 | + |
3592 | + Ch Peek() const { return current_; } |
3593 | + Ch Take() { Ch c = current_; current_ = takeFunc_(*is_); return c; } |
3594 | + size_t Tell() const { return is_->Tell(); } |
3595 | + |
3596 | + // Not implemented |
3597 | + void Put(Ch) { RAPIDJSON_ASSERT(false); } |
3598 | + void Flush() { RAPIDJSON_ASSERT(false); } |
3599 | + Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } |
3600 | + size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } |
3601 | + |
3602 | +private: |
3603 | + AutoUTFInputStream(const AutoUTFInputStream&); |
3604 | + AutoUTFInputStream& operator=(const AutoUTFInputStream&); |
3605 | + |
3606 | + // Detect encoding type with BOM or RFC 4627 |
3607 | + void DetectType() { |
3608 | + // BOM (Byte Order Mark): |
3609 | + // 00 00 FE FF UTF-32BE |
3610 | + // FF FE 00 00 UTF-32LE |
3611 | + // FE FF UTF-16BE |
3612 | + // FF FE UTF-16LE |
3613 | + // EF BB BF UTF-8 |
3614 | + |
3615 | + const unsigned char* c = (const unsigned char *)is_->Peek4(); |
3616 | + if (!c) |
3617 | + return; |
3618 | + |
3619 | + unsigned bom = c[0] | (c[1] << 8) | (c[2] << 16) | (c[3] << 24); |
3620 | + hasBOM_ = false; |
3621 | + if (bom == 0xFFFE0000) { type_ = kUTF32BE; hasBOM_ = true; is_->Take(); is_->Take(); is_->Take(); is_->Take(); } |
3622 | + else if (bom == 0x0000FEFF) { type_ = kUTF32LE; hasBOM_ = true; is_->Take(); is_->Take(); is_->Take(); is_->Take(); } |
3623 | + else if ((bom & 0xFFFF) == 0xFFFE) { type_ = kUTF16BE; hasBOM_ = true; is_->Take(); is_->Take(); } |
3624 | + else if ((bom & 0xFFFF) == 0xFEFF) { type_ = kUTF16LE; hasBOM_ = true; is_->Take(); is_->Take(); } |
3625 | + else if ((bom & 0xFFFFFF) == 0xBFBBEF) { type_ = kUTF8; hasBOM_ = true; is_->Take(); is_->Take(); is_->Take(); } |
3626 | + |
3627 | + // RFC 4627: Section 3 |
3628 | + // "Since the first two characters of a JSON text will always be ASCII |
3629 | + // characters [RFC0020], it is possible to determine whether an octet |
3630 | + // stream is UTF-8, UTF-16 (BE or LE), or UTF-32 (BE or LE) by looking |
3631 | + // at the pattern of nulls in the first four octets." |
3632 | + // 00 00 00 xx UTF-32BE |
3633 | + // 00 xx 00 xx UTF-16BE |
3634 | + // xx 00 00 00 UTF-32LE |
3635 | + // xx 00 xx 00 UTF-16LE |
3636 | + // xx xx xx xx UTF-8 |
3637 | + |
3638 | + if (!hasBOM_) { |
3639 | + unsigned pattern = (c[0] ? 1 : 0) | (c[1] ? 2 : 0) | (c[2] ? 4 : 0) | (c[3] ? 8 : 0); |
3640 | + switch (pattern) { |
3641 | + case 0x08: type_ = kUTF32BE; break; |
3642 | + case 0x0A: type_ = kUTF16BE; break; |
3643 | + case 0x01: type_ = kUTF32LE; break; |
3644 | + case 0x05: type_ = kUTF16LE; break; |
3645 | + case 0x0F: type_ = kUTF8; break; |
3646 | + default: break; // Use type defined by user. |
3647 | + } |
3648 | + } |
3649 | + |
3650 | + // Runtime check whether the size of character type is sufficient. It only perform checks with assertion. |
3651 | + switch (type_) { |
3652 | + case kUTF8: |
3653 | + // Do nothing |
3654 | + break; |
3655 | + case kUTF16LE: |
3656 | + case kUTF16BE: |
3657 | + RAPIDJSON_ASSERT(sizeof(Ch) >= 2); |
3658 | + break; |
3659 | + case kUTF32LE: |
3660 | + case kUTF32BE: |
3661 | + RAPIDJSON_ASSERT(sizeof(Ch) >= 4); |
3662 | + break; |
3663 | + default: |
3664 | + RAPIDJSON_ASSERT(false); // Invalid type |
3665 | + } |
3666 | + } |
3667 | + |
3668 | + typedef Ch (*TakeFunc)(InputByteStream& is); |
3669 | + InputByteStream* is_; |
3670 | + UTFType type_; |
3671 | + Ch current_; |
3672 | + TakeFunc takeFunc_; |
3673 | + bool hasBOM_; |
3674 | +}; |
3675 | + |
3676 | +//! Output stream wrapper with dynamically bound encoding and automatic encoding detection. |
3677 | +/*! |
3678 | + \tparam CharType Type of character for writing. |
3679 | + \tparam InputByteStream type of output byte stream to be wrapped. |
3680 | +*/ |
3681 | +template <typename CharType, typename OutputByteStream> |
3682 | +class AutoUTFOutputStream { |
3683 | + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); |
3684 | +public: |
3685 | + typedef CharType Ch; |
3686 | + |
3687 | + //! Constructor. |
3688 | + /*! |
3689 | + \param os output stream to be wrapped. |
3690 | + \param type UTF encoding type. |
3691 | + \param putBOM Whether to write BOM at the beginning of the stream. |
3692 | + */ |
3693 | + AutoUTFOutputStream(OutputByteStream& os, UTFType type, bool putBOM) : os_(&os), type_(type) { |
3694 | + // RUntime check whether the size of character type is sufficient. It only perform checks with assertion. |
3695 | + switch (type_) { |
3696 | + case kUTF16LE: |
3697 | + case kUTF16BE: |
3698 | + RAPIDJSON_ASSERT(sizeof(Ch) >= 2); |
3699 | + break; |
3700 | + case kUTF32LE: |
3701 | + case kUTF32BE: |
3702 | + RAPIDJSON_ASSERT(sizeof(Ch) >= 4); |
3703 | + break; |
3704 | + case kUTF8: |
3705 | + // Do nothing |
3706 | + break; |
3707 | + default: |
3708 | + RAPIDJSON_ASSERT(false); // Invalid UTFType |
3709 | + } |
3710 | + |
3711 | + static const PutFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Put) }; |
3712 | + putFunc_ = f[type_]; |
3713 | + |
3714 | + if (putBOM) |
3715 | + PutBOM(); |
3716 | + } |
3717 | + |
3718 | + UTFType GetType() const { return type_; } |
3719 | + |
3720 | + void Put(Ch c) { putFunc_(*os_, c); } |
3721 | + void Flush() { os_->Flush(); } |
3722 | + |
3723 | + // Not implemented |
3724 | + Ch Peek() const { RAPIDJSON_ASSERT(false); } |
3725 | + Ch Take() { RAPIDJSON_ASSERT(false); } |
3726 | + size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; } |
3727 | + Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } |
3728 | + size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } |
3729 | + |
3730 | +private: |
3731 | + AutoUTFOutputStream(const AutoUTFOutputStream&); |
3732 | + AutoUTFOutputStream& operator=(const AutoUTFOutputStream&); |
3733 | + |
3734 | + void PutBOM() { |
3735 | + typedef void (*PutBOMFunc)(OutputByteStream&); |
3736 | + static const PutBOMFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(PutBOM) }; |
3737 | + f[type_](*os_); |
3738 | + } |
3739 | + |
3740 | + typedef void (*PutFunc)(OutputByteStream&, Ch); |
3741 | + |
3742 | + OutputByteStream* os_; |
3743 | + UTFType type_; |
3744 | + PutFunc putFunc_; |
3745 | +}; |
3746 | + |
3747 | +#undef RAPIDJSON_ENCODINGS_FUNC |
3748 | + |
3749 | +RAPIDJSON_NAMESPACE_END |
3750 | + |
3751 | +#ifdef __GNUC__ |
3752 | +RAPIDJSON_DIAG_POP |
3753 | +#endif |
3754 | + |
3755 | +#endif // RAPIDJSON_FILESTREAM_H_ |
3756 | |
3757 | === added file 'shorts/xml2json/rapidjson/encodings.h' |
3758 | --- shorts/xml2json/rapidjson/encodings.h 1970-01-01 00:00:00 +0000 |
3759 | +++ shorts/xml2json/rapidjson/encodings.h 2015-12-15 16:05:21 +0000 |
3760 | @@ -0,0 +1,630 @@ |
3761 | +// Copyright (C) 2011 Milo Yip |
3762 | +// |
3763 | +// Permission is hereby granted, free of charge, to any person obtaining a copy |
3764 | +// of this software and associated documentation files (the "Software"), to deal |
3765 | +// in the Software without restriction, including without limitation the rights |
3766 | +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
3767 | +// copies of the Software, and to permit persons to whom the Software is |
3768 | +// furnished to do so, subject to the following conditions: |
3769 | +// |
3770 | +// The above copyright notice and this permission notice shall be included in |
3771 | +// all copies or substantial portions of the Software. |
3772 | +// |
3773 | +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
3774 | +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
3775 | +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
3776 | +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
3777 | +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
3778 | +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
3779 | +// THE SOFTWARE. |
3780 | + |
3781 | +#ifndef RAPIDJSON_ENCODINGS_H_ |
3782 | +#define RAPIDJSON_ENCODINGS_H_ |
3783 | + |
3784 | +#include "rapidjson.h" |
3785 | + |
3786 | +#ifdef _MSC_VER |
3787 | +RAPIDJSON_DIAG_PUSH |
3788 | +RAPIDJSON_DIAG_OFF(4244) // conversion from 'type1' to 'type2', possible loss of data |
3789 | +RAPIDJSON_DIAG_OFF(4702) // unreachable code |
3790 | +#elif defined(__GNUC__) |
3791 | +RAPIDJSON_DIAG_PUSH |
3792 | +RAPIDJSON_DIAG_OFF(effc++) |
3793 | +#endif |
3794 | + |
3795 | +RAPIDJSON_NAMESPACE_BEGIN |
3796 | + |
3797 | +/////////////////////////////////////////////////////////////////////////////// |
3798 | +// Encoding |
3799 | + |
3800 | +/*! \class rapidjson::Encoding |
3801 | + \brief Concept for encoding of Unicode characters. |
3802 | + |
3803 | +\code |
3804 | +concept Encoding { |
3805 | + typename Ch; //! Type of character. A "character" is actually a code unit in unicode's definition. |
3806 | + |
3807 | + enum { supportUnicode = 1 }; // or 0 if not supporting unicode |
3808 | + |
3809 | + //! \brief Encode a Unicode codepoint to an output stream. |
3810 | + //! \param os Output stream. |
3811 | + //! \param codepoint An unicode codepoint, ranging from 0x0 to 0x10FFFF inclusively. |
3812 | + template<typename OutputStream> |
3813 | + static void Encode(OutputStream& os, unsigned codepoint); |
3814 | + |
3815 | + //! \brief Decode a Unicode codepoint from an input stream. |
3816 | + //! \param is Input stream. |
3817 | + //! \param codepoint Output of the unicode codepoint. |
3818 | + //! \return true if a valid codepoint can be decoded from the stream. |
3819 | + template <typename InputStream> |
3820 | + static bool Decode(InputStream& is, unsigned* codepoint); |
3821 | + |
3822 | + //! \brief Validate one Unicode codepoint from an encoded stream. |
3823 | + //! \param is Input stream to obtain codepoint. |
3824 | + //! \param os Output for copying one codepoint. |
3825 | + //! \return true if it is valid. |
3826 | + //! \note This function just validating and copying the codepoint without actually decode it. |
3827 | + template <typename InputStream, typename OutputStream> |
3828 | + static bool Validate(InputStream& is, OutputStream& os); |
3829 | + |
3830 | + // The following functions are deal with byte streams. |
3831 | + |
3832 | + //! Take a character from input byte stream, skip BOM if exist. |
3833 | + template <typename InputByteStream> |
3834 | + static CharType TakeBOM(InputByteStream& is); |
3835 | + |
3836 | + //! Take a character from input byte stream. |
3837 | + template <typename InputByteStream> |
3838 | + static Ch Take(InputByteStream& is); |
3839 | + |
3840 | + //! Put BOM to output byte stream. |
3841 | + template <typename OutputByteStream> |
3842 | + static void PutBOM(OutputByteStream& os); |
3843 | + |
3844 | + //! Put a character to output byte stream. |
3845 | + template <typename OutputByteStream> |
3846 | + static void Put(OutputByteStream& os, Ch c); |
3847 | +}; |
3848 | +\endcode |
3849 | +*/ |
3850 | + |
3851 | +/////////////////////////////////////////////////////////////////////////////// |
3852 | +// UTF8 |
3853 | + |
3854 | +//! UTF-8 encoding. |
3855 | +/*! http://en.wikipedia.org/wiki/UTF-8 |
3856 | + http://tools.ietf.org/html/rfc3629 |
3857 | + \tparam CharType Code unit for storing 8-bit UTF-8 data. Default is char. |
3858 | + \note implements Encoding concept |
3859 | +*/ |
3860 | +template<typename CharType = char> |
3861 | +struct UTF8 { |
3862 | + typedef CharType Ch; |
3863 | + |
3864 | + enum { supportUnicode = 1 }; |
3865 | + |
3866 | + template<typename OutputStream> |
3867 | + static void Encode(OutputStream& os, unsigned codepoint) { |
3868 | + if (codepoint <= 0x7F) |
3869 | + os.Put(static_cast<Ch>(codepoint & 0xFF)); |
3870 | + else if (codepoint <= 0x7FF) { |
3871 | + os.Put(static_cast<Ch>(0xC0 | ((codepoint >> 6) & 0xFF))); |
3872 | + os.Put(static_cast<Ch>(0x80 | ((codepoint & 0x3F)))); |
3873 | + } |
3874 | + else if (codepoint <= 0xFFFF) { |
3875 | + os.Put(static_cast<Ch>(0xE0 | ((codepoint >> 12) & 0xFF))); |
3876 | + os.Put(static_cast<Ch>(0x80 | ((codepoint >> 6) & 0x3F))); |
3877 | + os.Put(static_cast<Ch>(0x80 | (codepoint & 0x3F))); |
3878 | + } |
3879 | + else { |
3880 | + RAPIDJSON_ASSERT(codepoint <= 0x10FFFF); |
3881 | + os.Put(static_cast<Ch>(0xF0 | ((codepoint >> 18) & 0xFF))); |
3882 | + os.Put(static_cast<Ch>(0x80 | ((codepoint >> 12) & 0x3F))); |
3883 | + os.Put(static_cast<Ch>(0x80 | ((codepoint >> 6) & 0x3F))); |
3884 | + os.Put(static_cast<Ch>(0x80 | (codepoint & 0x3F))); |
3885 | + } |
3886 | + } |
3887 | + |
3888 | + template <typename InputStream> |
3889 | + static bool Decode(InputStream& is, unsigned* codepoint) { |
3890 | +#define COPY() c = is.Take(); *codepoint = (*codepoint << 6) | ((unsigned char)c & 0x3Fu) |
3891 | +#define TRANS(mask) result &= ((GetRange((unsigned char)c) & mask) != 0) |
3892 | +#define TAIL() COPY(); TRANS(0x70) |
3893 | + Ch c = is.Take(); |
3894 | + if (!(c & 0x80)) { |
3895 | + *codepoint = (unsigned char)c; |
3896 | + return true; |
3897 | + } |
3898 | + |
3899 | + unsigned char type = GetRange((unsigned char)c); |
3900 | + *codepoint = (0xFF >> type) & (unsigned char)c; |
3901 | + bool result = true; |
3902 | + switch (type) { |
3903 | + case 2: TAIL(); return result; |
3904 | + case 3: TAIL(); TAIL(); return result; |
3905 | + case 4: COPY(); TRANS(0x50); TAIL(); return result; |
3906 | + case 5: COPY(); TRANS(0x10); TAIL(); TAIL(); return result; |
3907 | + case 6: TAIL(); TAIL(); TAIL(); return result; |
3908 | + case 10: COPY(); TRANS(0x20); TAIL(); return result; |
3909 | + case 11: COPY(); TRANS(0x60); TAIL(); TAIL(); return result; |
3910 | + default: return false; |
3911 | + } |
3912 | +#undef COPY |
3913 | +#undef TRANS |
3914 | +#undef TAIL |
3915 | + } |
3916 | + |
3917 | + template <typename InputStream, typename OutputStream> |
3918 | + static bool Validate(InputStream& is, OutputStream& os) { |
3919 | +#define COPY() os.Put(c = is.Take()) |
3920 | +#define TRANS(mask) result &= ((GetRange((unsigned char)c) & mask) != 0) |
3921 | +#define TAIL() COPY(); TRANS(0x70) |
3922 | + Ch c; |
3923 | + COPY(); |
3924 | + if (!(c & 0x80)) |
3925 | + return true; |
3926 | + |
3927 | + bool result = true; |
3928 | + switch (GetRange((unsigned char)c)) { |
3929 | + case 2: TAIL(); return result; |
3930 | + case 3: TAIL(); TAIL(); return result; |
3931 | + case 4: COPY(); TRANS(0x50); TAIL(); return result; |
3932 | + case 5: COPY(); TRANS(0x10); TAIL(); TAIL(); return result; |
3933 | + case 6: TAIL(); TAIL(); TAIL(); return result; |
3934 | + case 10: COPY(); TRANS(0x20); TAIL(); return result; |
3935 | + case 11: COPY(); TRANS(0x60); TAIL(); TAIL(); return result; |
3936 | + default: return false; |
3937 | + } |
3938 | +#undef COPY |
3939 | +#undef TRANS |
3940 | +#undef TAIL |
3941 | + } |
3942 | + |
3943 | + static unsigned char GetRange(unsigned char c) { |
3944 | + // Referring to DFA of http://bjoern.hoehrmann.de/utf-8/decoder/dfa/ |
3945 | + // With new mapping 1 -> 0x10, 7 -> 0x20, 9 -> 0x40, such that AND operation can test multiple types. |
3946 | + static const unsigned char type[] = { |
3947 | + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, |
3948 | + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, |
3949 | + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, |
3950 | + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, |
3951 | + 0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10, |
3952 | + 0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40, |
3953 | + 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, |
3954 | + 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, |
3955 | + 8,8,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, |
3956 | + 10,3,3,3,3,3,3,3,3,3,3,3,3,4,3,3, 11,6,6,6,5,8,8,8,8,8,8,8,8,8,8,8, |
3957 | + }; |
3958 | + return type[c]; |
3959 | + } |
3960 | + |
3961 | + template <typename InputByteStream> |
3962 | + static CharType TakeBOM(InputByteStream& is) { |
3963 | + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); |
3964 | + Ch c = Take(is); |
3965 | + if ((unsigned char)c != 0xEFu) return c; |
3966 | + c = is.Take(); |
3967 | + if ((unsigned char)c != 0xBBu) return c; |
3968 | + c = is.Take(); |
3969 | + if ((unsigned char)c != 0xBFu) return c; |
3970 | + c = is.Take(); |
3971 | + return c; |
3972 | + } |
3973 | + |
3974 | + template <typename InputByteStream> |
3975 | + static Ch Take(InputByteStream& is) { |
3976 | + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); |
3977 | + return is.Take(); |
3978 | + } |
3979 | + |
3980 | + template <typename OutputByteStream> |
3981 | + static void PutBOM(OutputByteStream& os) { |
3982 | + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); |
3983 | + os.Put(0xEFu); os.Put(0xBBu); os.Put(0xBFu); |
3984 | + } |
3985 | + |
3986 | + template <typename OutputByteStream> |
3987 | + static void Put(OutputByteStream& os, Ch c) { |
3988 | + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); |
3989 | + os.Put(static_cast<typename OutputByteStream::Ch>(c)); |
3990 | + } |
3991 | +}; |
3992 | + |
3993 | +/////////////////////////////////////////////////////////////////////////////// |
3994 | +// UTF16 |
3995 | + |
3996 | +//! UTF-16 encoding. |
3997 | +/*! http://en.wikipedia.org/wiki/UTF-16 |
3998 | + http://tools.ietf.org/html/rfc2781 |
3999 | + \tparam CharType Type for storing 16-bit UTF-16 data. Default is wchar_t. C++11 may use char16_t instead. |
4000 | + \note implements Encoding concept |
4001 | + |
4002 | + \note For in-memory access, no need to concern endianness. The code units and code points are represented by CPU's endianness. |
4003 | + For streaming, use UTF16LE and UTF16BE, which handle endianness. |
4004 | +*/ |
4005 | +template<typename CharType = wchar_t> |
4006 | +struct UTF16 { |
4007 | + typedef CharType Ch; |
4008 | + RAPIDJSON_STATIC_ASSERT(sizeof(Ch) >= 2); |
4009 | + |
4010 | + enum { supportUnicode = 1 }; |
4011 | + |
4012 | + template<typename OutputStream> |
4013 | + static void Encode(OutputStream& os, unsigned codepoint) { |
4014 | + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 2); |
4015 | + if (codepoint <= 0xFFFF) { |
4016 | + RAPIDJSON_ASSERT(codepoint < 0xD800 || codepoint > 0xDFFF); // Code point itself cannot be surrogate pair |
4017 | + os.Put(static_cast<typename OutputStream::Ch>(codepoint)); |
4018 | + } |
4019 | + else { |
4020 | + RAPIDJSON_ASSERT(codepoint <= 0x10FFFF); |
4021 | + unsigned v = codepoint - 0x10000; |
4022 | + os.Put(static_cast<typename OutputStream::Ch>((v >> 10) | 0xD800)); |
4023 | + os.Put((v & 0x3FF) | 0xDC00); |
4024 | + } |
4025 | + } |
4026 | + |
4027 | + template <typename InputStream> |
4028 | + static bool Decode(InputStream& is, unsigned* codepoint) { |
4029 | + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 2); |
4030 | + Ch c = is.Take(); |
4031 | + if (c < 0xD800 || c > 0xDFFF) { |
4032 | + *codepoint = c; |
4033 | + return true; |
4034 | + } |
4035 | + else if (c <= 0xDBFF) { |
4036 | + *codepoint = (c & 0x3FF) << 10; |
4037 | + c = is.Take(); |
4038 | + *codepoint |= (c & 0x3FF); |
4039 | + *codepoint += 0x10000; |
4040 | + return c >= 0xDC00 && c <= 0xDFFF; |
4041 | + } |
4042 | + return false; |
4043 | + } |
4044 | + |
4045 | + template <typename InputStream, typename OutputStream> |
4046 | + static bool Validate(InputStream& is, OutputStream& os) { |
4047 | + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 2); |
4048 | + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 2); |
4049 | + Ch c; |
4050 | + os.Put(c = is.Take()); |
4051 | + if (c < 0xD800 || c > 0xDFFF) |
4052 | + return true; |
4053 | + else if (c <= 0xDBFF) { |
4054 | + os.Put(c = is.Take()); |
4055 | + return c >= 0xDC00 && c <= 0xDFFF; |
4056 | + } |
4057 | + return false; |
4058 | + } |
4059 | +}; |
4060 | + |
4061 | +//! UTF-16 little endian encoding. |
4062 | +template<typename CharType = wchar_t> |
4063 | +struct UTF16LE : UTF16<CharType> { |
4064 | + template <typename InputByteStream> |
4065 | + static CharType TakeBOM(InputByteStream& is) { |
4066 | + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); |
4067 | + CharType c = Take(is); |
4068 | + return (unsigned short)c == 0xFEFFu ? Take(is) : c; |
4069 | + } |
4070 | + |
4071 | + template <typename InputByteStream> |
4072 | + static CharType Take(InputByteStream& is) { |
4073 | + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); |
4074 | + CharType c = (unsigned char)is.Take(); |
4075 | + c |= (unsigned char)is.Take() << 8; |
4076 | + return c; |
4077 | + } |
4078 | + |
4079 | + template <typename OutputByteStream> |
4080 | + static void PutBOM(OutputByteStream& os) { |
4081 | + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); |
4082 | + os.Put(0xFFu); os.Put(0xFEu); |
4083 | + } |
4084 | + |
4085 | + template <typename OutputByteStream> |
4086 | + static void Put(OutputByteStream& os, CharType c) { |
4087 | + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); |
4088 | + os.Put(c & 0xFFu); |
4089 | + os.Put((c >> 8) & 0xFFu); |
4090 | + } |
4091 | +}; |
4092 | + |
4093 | +//! UTF-16 big endian encoding. |
4094 | +template<typename CharType = wchar_t> |
4095 | +struct UTF16BE : UTF16<CharType> { |
4096 | + template <typename InputByteStream> |
4097 | + static CharType TakeBOM(InputByteStream& is) { |
4098 | + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); |
4099 | + CharType c = Take(is); |
4100 | + return (unsigned short)c == 0xFEFFu ? Take(is) : c; |
4101 | + } |
4102 | + |
4103 | + template <typename InputByteStream> |
4104 | + static CharType Take(InputByteStream& is) { |
4105 | + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); |
4106 | + CharType c = (unsigned char)is.Take() << 8; |
4107 | + c |= (unsigned char)is.Take(); |
4108 | + return c; |
4109 | + } |
4110 | + |
4111 | + template <typename OutputByteStream> |
4112 | + static void PutBOM(OutputByteStream& os) { |
4113 | + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); |
4114 | + os.Put(0xFEu); os.Put(0xFFu); |
4115 | + } |
4116 | + |
4117 | + template <typename OutputByteStream> |
4118 | + static void Put(OutputByteStream& os, CharType c) { |
4119 | + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); |
4120 | + os.Put((c >> 8) & 0xFFu); |
4121 | + os.Put(c & 0xFFu); |
4122 | + } |
4123 | +}; |
4124 | + |
4125 | +/////////////////////////////////////////////////////////////////////////////// |
4126 | +// UTF32 |
4127 | + |
4128 | +//! UTF-32 encoding. |
4129 | +/*! http://en.wikipedia.org/wiki/UTF-32 |
4130 | + \tparam CharType Type for storing 32-bit UTF-32 data. Default is unsigned. C++11 may use char32_t instead. |
4131 | + \note implements Encoding concept |
4132 | + |
4133 | + \note For in-memory access, no need to concern endianness. The code units and code points are represented by CPU's endianness. |
4134 | + For streaming, use UTF32LE and UTF32BE, which handle endianness. |
4135 | +*/ |
4136 | +template<typename CharType = unsigned> |
4137 | +struct UTF32 { |
4138 | + typedef CharType Ch; |
4139 | + RAPIDJSON_STATIC_ASSERT(sizeof(Ch) >= 4); |
4140 | + |
4141 | + enum { supportUnicode = 1 }; |
4142 | + |
4143 | + template<typename OutputStream> |
4144 | + static void Encode(OutputStream& os, unsigned codepoint) { |
4145 | + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 4); |
4146 | + RAPIDJSON_ASSERT(codepoint <= 0x10FFFF); |
4147 | + os.Put(codepoint); |
4148 | + } |
4149 | + |
4150 | + template <typename InputStream> |
4151 | + static bool Decode(InputStream& is, unsigned* codepoint) { |
4152 | + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 4); |
4153 | + Ch c = is.Take(); |
4154 | + *codepoint = c; |
4155 | + return c <= 0x10FFFF; |
4156 | + } |
4157 | + |
4158 | + template <typename InputStream, typename OutputStream> |
4159 | + static bool Validate(InputStream& is, OutputStream& os) { |
4160 | + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 4); |
4161 | + Ch c; |
4162 | + os.Put(c = is.Take()); |
4163 | + return c <= 0x10FFFF; |
4164 | + } |
4165 | +}; |
4166 | + |
4167 | +//! UTF-32 little endian enocoding. |
4168 | +template<typename CharType = unsigned> |
4169 | +struct UTF32LE : UTF32<CharType> { |
4170 | + template <typename InputByteStream> |
4171 | + static CharType TakeBOM(InputByteStream& is) { |
4172 | + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); |
4173 | + CharType c = Take(is); |
4174 | + return (unsigned)c == 0x0000FEFFu ? Take(is) : c; |
4175 | + } |
4176 | + |
4177 | + template <typename InputByteStream> |
4178 | + static CharType Take(InputByteStream& is) { |
4179 | + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); |
4180 | + CharType c = (unsigned char)is.Take(); |
4181 | + c |= (unsigned char)is.Take() << 8; |
4182 | + c |= (unsigned char)is.Take() << 16; |
4183 | + c |= (unsigned char)is.Take() << 24; |
4184 | + return c; |
4185 | + } |
4186 | + |
4187 | + template <typename OutputByteStream> |
4188 | + static void PutBOM(OutputByteStream& os) { |
4189 | + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); |
4190 | + os.Put(0xFFu); os.Put(0xFEu); os.Put(0x00u); os.Put(0x00u); |
4191 | + } |
4192 | + |
4193 | + template <typename OutputByteStream> |
4194 | + static void Put(OutputByteStream& os, CharType c) { |
4195 | + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); |
4196 | + os.Put(c & 0xFFu); |
4197 | + os.Put((c >> 8) & 0xFFu); |
4198 | + os.Put((c >> 16) & 0xFFu); |
4199 | + os.Put((c >> 24) & 0xFFu); |
4200 | + } |
4201 | +}; |
4202 | + |
4203 | +//! UTF-32 big endian encoding. |
4204 | +template<typename CharType = unsigned> |
4205 | +struct UTF32BE : UTF32<CharType> { |
4206 | + template <typename InputByteStream> |
4207 | + static CharType TakeBOM(InputByteStream& is) { |
4208 | + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); |
4209 | + CharType c = Take(is); |
4210 | + return (unsigned)c == 0x0000FEFFu ? Take(is) : c; |
4211 | + } |
4212 | + |
4213 | + template <typename InputByteStream> |
4214 | + static CharType Take(InputByteStream& is) { |
4215 | + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); |
4216 | + CharType c = (unsigned char)is.Take() << 24; |
4217 | + c |= (unsigned char)is.Take() << 16; |
4218 | + c |= (unsigned char)is.Take() << 8; |
4219 | + c |= (unsigned char)is.Take(); |
4220 | + return c; |
4221 | + } |
4222 | + |
4223 | + template <typename OutputByteStream> |
4224 | + static void PutBOM(OutputByteStream& os) { |
4225 | + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); |
4226 | + os.Put(0x00u); os.Put(0x00u); os.Put(0xFEu); os.Put(0xFFu); |
4227 | + } |
4228 | + |
4229 | + template <typename OutputByteStream> |
4230 | + static void Put(OutputByteStream& os, CharType c) { |
4231 | + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); |
4232 | + os.Put((c >> 24) & 0xFFu); |
4233 | + os.Put((c >> 16) & 0xFFu); |
4234 | + os.Put((c >> 8) & 0xFFu); |
4235 | + os.Put(c & 0xFFu); |
4236 | + } |
4237 | +}; |
4238 | + |
4239 | +/////////////////////////////////////////////////////////////////////////////// |
4240 | +// ASCII |
4241 | + |
4242 | +//! ASCII encoding. |
4243 | +/*! http://en.wikipedia.org/wiki/ASCII |
4244 | + \tparam CharType Code unit for storing 7-bit ASCII data. Default is char. |
4245 | + \note implements Encoding concept |
4246 | +*/ |
4247 | +template<typename CharType = char> |
4248 | +struct ASCII { |
4249 | + typedef CharType Ch; |
4250 | + |
4251 | + enum { supportUnicode = 0 }; |
4252 | + |
4253 | + template<typename OutputStream> |
4254 | + static void Encode(OutputStream& os, unsigned codepoint) { |
4255 | + RAPIDJSON_ASSERT(codepoint <= 0x7F); |
4256 | + os.Put(static_cast<Ch>(codepoint & 0xFF)); |
4257 | + } |
4258 | + |
4259 | + template <typename InputStream> |
4260 | + static bool Decode(InputStream& is, unsigned* codepoint) { |
4261 | + unsigned char c = static_cast<unsigned char>(is.Take()); |
4262 | + *codepoint = c; |
4263 | + return c <= 0X7F; |
4264 | + } |
4265 | + |
4266 | + template <typename InputStream, typename OutputStream> |
4267 | + static bool Validate(InputStream& is, OutputStream& os) { |
4268 | + unsigned char c = is.Take(); |
4269 | + os.Put(c); |
4270 | + return c <= 0x7F; |
4271 | + } |
4272 | + |
4273 | + template <typename InputByteStream> |
4274 | + static CharType TakeBOM(InputByteStream& is) { |
4275 | + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); |
4276 | + Ch c = Take(is); |
4277 | + return c; |
4278 | + } |
4279 | + |
4280 | + template <typename InputByteStream> |
4281 | + static Ch Take(InputByteStream& is) { |
4282 | + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); |
4283 | + return is.Take(); |
4284 | + } |
4285 | + |
4286 | + template <typename OutputByteStream> |
4287 | + static void PutBOM(OutputByteStream& os) { |
4288 | + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); |
4289 | + (void)os; |
4290 | + } |
4291 | + |
4292 | + template <typename OutputByteStream> |
4293 | + static void Put(OutputByteStream& os, Ch c) { |
4294 | + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); |
4295 | + os.Put(static_cast<typename OutputByteStream::Ch>(c)); |
4296 | + } |
4297 | +}; |
4298 | + |
4299 | +/////////////////////////////////////////////////////////////////////////////// |
4300 | +// AutoUTF |
4301 | + |
4302 | +//! Runtime-specified UTF encoding type of a stream. |
4303 | +enum UTFType { |
4304 | + kUTF8 = 0, //!< UTF-8. |
4305 | + kUTF16LE = 1, //!< UTF-16 little endian. |
4306 | + kUTF16BE = 2, //!< UTF-16 big endian. |
4307 | + kUTF32LE = 3, //!< UTF-32 little endian. |
4308 | + kUTF32BE = 4 //!< UTF-32 big endian. |
4309 | +}; |
4310 | + |
4311 | +//! Dynamically select encoding according to stream's runtime-specified UTF encoding type. |
4312 | +/*! \note This class can be used with AutoUTFInputtStream and AutoUTFOutputStream, which provides GetType(). |
4313 | +*/ |
4314 | +template<typename CharType> |
4315 | +struct AutoUTF { |
4316 | + typedef CharType Ch; |
4317 | + |
4318 | + enum { supportUnicode = 1 }; |
4319 | + |
4320 | +#define RAPIDJSON_ENCODINGS_FUNC(x) UTF8<Ch>::x, UTF16LE<Ch>::x, UTF16BE<Ch>::x, UTF32LE<Ch>::x, UTF32BE<Ch>::x |
4321 | + |
4322 | + template<typename OutputStream> |
4323 | + RAPIDJSON_FORCEINLINE static void Encode(OutputStream& os, unsigned codepoint) { |
4324 | + typedef void (*EncodeFunc)(OutputStream&, unsigned); |
4325 | + static const EncodeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Encode) }; |
4326 | + (*f[os.GetType()])(os, codepoint); |
4327 | + } |
4328 | + |
4329 | + template <typename InputStream> |
4330 | + RAPIDJSON_FORCEINLINE static bool Decode(InputStream& is, unsigned* codepoint) { |
4331 | + typedef bool (*DecodeFunc)(InputStream&, unsigned*); |
4332 | + static const DecodeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Decode) }; |
4333 | + return (*f[is.GetType()])(is, codepoint); |
4334 | + } |
4335 | + |
4336 | + template <typename InputStream, typename OutputStream> |
4337 | + RAPIDJSON_FORCEINLINE static bool Validate(InputStream& is, OutputStream& os) { |
4338 | + typedef bool (*ValidateFunc)(InputStream&, OutputStream&); |
4339 | + static const ValidateFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Validate) }; |
4340 | + return (*f[is.GetType()])(is, os); |
4341 | + } |
4342 | + |
4343 | +#undef RAPIDJSON_ENCODINGS_FUNC |
4344 | +}; |
4345 | + |
4346 | +/////////////////////////////////////////////////////////////////////////////// |
4347 | +// Transcoder |
4348 | + |
4349 | +//! Encoding conversion. |
4350 | +template<typename SourceEncoding, typename TargetEncoding> |
4351 | +struct Transcoder { |
4352 | + //! Take one Unicode codepoint from source encoding, convert it to target encoding and put it to the output stream. |
4353 | + template<typename InputStream, typename OutputStream> |
4354 | + RAPIDJSON_FORCEINLINE static bool Transcode(InputStream& is, OutputStream& os) { |
4355 | + unsigned codepoint; |
4356 | + if (!SourceEncoding::Decode(is, &codepoint)) |
4357 | + return false; |
4358 | + TargetEncoding::Encode(os, codepoint); |
4359 | + return true; |
4360 | + } |
4361 | + |
4362 | + //! Validate one Unicode codepoint from an encoded stream. |
4363 | + template<typename InputStream, typename OutputStream> |
4364 | + RAPIDJSON_FORCEINLINE static bool Validate(InputStream& is, OutputStream& os) { |
4365 | + return Transcode(is, os); // Since source/target encoding is different, must transcode. |
4366 | + } |
4367 | +}; |
4368 | + |
4369 | +//! Specialization of Transcoder with same source and target encoding. |
4370 | +template<typename Encoding> |
4371 | +struct Transcoder<Encoding, Encoding> { |
4372 | + template<typename InputStream, typename OutputStream> |
4373 | + RAPIDJSON_FORCEINLINE static bool Transcode(InputStream& is, OutputStream& os) { |
4374 | + os.Put(is.Take()); // Just copy one code unit. This semantic is different from primary template class. |
4375 | + return true; |
4376 | + } |
4377 | + |
4378 | + template<typename InputStream, typename OutputStream> |
4379 | + RAPIDJSON_FORCEINLINE static bool Validate(InputStream& is, OutputStream& os) { |
4380 | + return Encoding::Validate(is, os); // source/target encoding are the same |
4381 | + } |
4382 | +}; |
4383 | + |
4384 | +RAPIDJSON_NAMESPACE_END |
4385 | + |
4386 | +#if defined(__GNUC__) || defined(_MSV_VER) |
4387 | +RAPIDJSON_DIAG_POP |
4388 | +#endif |
4389 | + |
4390 | +#endif // RAPIDJSON_ENCODINGS_H_ |
4391 | |
4392 | === added directory 'shorts/xml2json/rapidjson/error' |
4393 | === added file 'shorts/xml2json/rapidjson/error/en.h' |
4394 | --- shorts/xml2json/rapidjson/error/en.h 1970-01-01 00:00:00 +0000 |
4395 | +++ shorts/xml2json/rapidjson/error/en.h 2015-12-15 16:05:21 +0000 |
4396 | @@ -0,0 +1,71 @@ |
4397 | +// Copyright (C) 2011 Milo Yip |
4398 | +// |
4399 | +// Permission is hereby granted, free of charge, to any person obtaining a copy |
4400 | +// of this software and associated documentation files (the "Software"), to deal |
4401 | +// in the Software without restriction, including without limitation the rights |
4402 | +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
4403 | +// copies of the Software, and to permit persons to whom the Software is |
4404 | +// furnished to do so, subject to the following conditions: |
4405 | +// |
4406 | +// The above copyright notice and this permission notice shall be included in |
4407 | +// all copies or substantial portions of the Software. |
4408 | +// |
4409 | +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
4410 | +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
4411 | +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
4412 | +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
4413 | +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
4414 | +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
4415 | +// THE SOFTWARE. |
4416 | + |
4417 | +#ifndef RAPIDJSON_ERROR_EN_H__ |
4418 | +#define RAPIDJSON_ERROR_EN_H__ |
4419 | + |
4420 | +#include "error.h" |
4421 | + |
4422 | +RAPIDJSON_NAMESPACE_BEGIN |
4423 | + |
4424 | +//! Maps error code of parsing into error message. |
4425 | +/*! |
4426 | + \ingroup RAPIDJSON_ERRORS |
4427 | + \param parseErrorCode Error code obtained in parsing. |
4428 | + \return the error message. |
4429 | + \note User can make a copy of this function for localization. |
4430 | + Using switch-case is safer for future modification of error codes. |
4431 | +*/ |
4432 | +inline const RAPIDJSON_ERROR_CHARTYPE* GetParseError_En(ParseErrorCode parseErrorCode) { |
4433 | + switch (parseErrorCode) { |
4434 | + case kParseErrorNone: return RAPIDJSON_ERROR_STRING("No error."); |
4435 | + |
4436 | + case kParseErrorDocumentEmpty: return RAPIDJSON_ERROR_STRING("The document is empty."); |
4437 | + case kParseErrorDocumentRootNotSingular: return RAPIDJSON_ERROR_STRING("The document root must not follow by other values."); |
4438 | + |
4439 | + case kParseErrorValueInvalid: return RAPIDJSON_ERROR_STRING("Invalid value."); |
4440 | + |
4441 | + case kParseErrorObjectMissName: return RAPIDJSON_ERROR_STRING("Missing a name for object member."); |
4442 | + case kParseErrorObjectMissColon: return RAPIDJSON_ERROR_STRING("Missing a colon after a name of object member."); |
4443 | + case kParseErrorObjectMissCommaOrCurlyBracket: return RAPIDJSON_ERROR_STRING("Missing a comma or '}' after an object member."); |
4444 | + |
4445 | + case kParseErrorArrayMissCommaOrSquareBracket: return RAPIDJSON_ERROR_STRING("Missing a comma or ']' after an array element."); |
4446 | + |
4447 | + case kParseErrorStringUnicodeEscapeInvalidHex: return RAPIDJSON_ERROR_STRING("Incorrect hex digit after \\u escape in string."); |
4448 | + case kParseErrorStringUnicodeSurrogateInvalid: return RAPIDJSON_ERROR_STRING("The surrogate pair in string is invalid."); |
4449 | + case kParseErrorStringEscapeInvalid: return RAPIDJSON_ERROR_STRING("Invalid escape character in string."); |
4450 | + case kParseErrorStringMissQuotationMark: return RAPIDJSON_ERROR_STRING("Missing a closing quotation mark in string."); |
4451 | + case kParseErrorStringInvalidEncoding: return RAPIDJSON_ERROR_STRING("Invalid encoding in string."); |
4452 | + |
4453 | + case kParseErrorNumberTooBig: return RAPIDJSON_ERROR_STRING("Number too big to be stored in double."); |
4454 | + case kParseErrorNumberMissFraction: return RAPIDJSON_ERROR_STRING("Miss fraction part in number."); |
4455 | + case kParseErrorNumberMissExponent: return RAPIDJSON_ERROR_STRING("Miss exponent in number."); |
4456 | + |
4457 | + case kParseErrorTermination: return RAPIDJSON_ERROR_STRING("Terminate parsing due to Handler error."); |
4458 | + case kParseErrorUnspecificSyntaxError: return RAPIDJSON_ERROR_STRING("Unspecific syntax error."); |
4459 | + |
4460 | + default: |
4461 | + return RAPIDJSON_ERROR_STRING("Unknown error."); |
4462 | + } |
4463 | +} |
4464 | + |
4465 | +RAPIDJSON_NAMESPACE_END |
4466 | + |
4467 | +#endif // RAPIDJSON_ERROR_EN_H__ |
4468 | |
4469 | === added file 'shorts/xml2json/rapidjson/error/error.h' |
4470 | --- shorts/xml2json/rapidjson/error/error.h 1970-01-01 00:00:00 +0000 |
4471 | +++ shorts/xml2json/rapidjson/error/error.h 2015-12-15 16:05:21 +0000 |
4472 | @@ -0,0 +1,150 @@ |
4473 | +// Copyright (C) 2011 Milo Yip |
4474 | +// |
4475 | +// Permission is hereby granted, free of charge, to any person obtaining a copy |
4476 | +// of this software and associated documentation files (the "Software"), to deal |
4477 | +// in the Software without restriction, including without limitation the rights |
4478 | +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
4479 | +// copies of the Software, and to permit persons to whom the Software is |
4480 | +// furnished to do so, subject to the following conditions: |
4481 | +// |
4482 | +// The above copyright notice and this permission notice shall be included in |
4483 | +// all copies or substantial portions of the Software. |
4484 | +// |
4485 | +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
4486 | +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
4487 | +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
4488 | +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
4489 | +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
4490 | +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
4491 | +// THE SOFTWARE. |
4492 | + |
4493 | +#ifndef RAPIDJSON_ERROR_ERROR_H__ |
4494 | +#define RAPIDJSON_ERROR_ERROR_H__ |
4495 | + |
4496 | +/*! \file error.h */ |
4497 | + |
4498 | +/*! \defgroup RAPIDJSON_ERRORS RapidJSON error handling */ |
4499 | + |
4500 | +/////////////////////////////////////////////////////////////////////////////// |
4501 | +// RAPIDJSON_ERROR_CHARTYPE |
4502 | + |
4503 | +//! Character type of error messages. |
4504 | +/*! \ingroup RAPIDJSON_ERRORS |
4505 | + The default character type is \c char. |
4506 | + On Windows, user can define this macro as \c TCHAR for supporting both |
4507 | + unicode/non-unicode settings. |
4508 | +*/ |
4509 | +#ifndef RAPIDJSON_ERROR_CHARTYPE |
4510 | +#define RAPIDJSON_ERROR_CHARTYPE char |
4511 | +#endif |
4512 | + |
4513 | +/////////////////////////////////////////////////////////////////////////////// |
4514 | +// RAPIDJSON_ERROR_STRING |
4515 | + |
4516 | +//! Macro for converting string literial to \ref RAPIDJSON_ERROR_CHARTYPE[]. |
4517 | +/*! \ingroup RAPIDJSON_ERRORS |
4518 | + By default this conversion macro does nothing. |
4519 | + On Windows, user can define this macro as \c _T(x) for supporting both |
4520 | + unicode/non-unicode settings. |
4521 | +*/ |
4522 | +#ifndef RAPIDJSON_ERROR_STRING |
4523 | +#define RAPIDJSON_ERROR_STRING(x) x |
4524 | +#endif |
4525 | + |
4526 | +RAPIDJSON_NAMESPACE_BEGIN |
4527 | + |
4528 | +/////////////////////////////////////////////////////////////////////////////// |
4529 | +// ParseErrorCode |
4530 | + |
4531 | +//! Error code of parsing. |
4532 | +/*! \ingroup RAPIDJSON_ERRORS |
4533 | + \see GenericReader::Parse, GenericReader::GetParseErrorCode |
4534 | +*/ |
4535 | +enum ParseErrorCode { |
4536 | + kParseErrorNone = 0, //!< No error. |
4537 | + |
4538 | + kParseErrorDocumentEmpty, //!< The document is empty. |
4539 | + kParseErrorDocumentRootNotSingular, //!< The document root must not follow by other values. |
4540 | + |
4541 | + kParseErrorValueInvalid, //!< Invalid value. |
4542 | + |
4543 | + kParseErrorObjectMissName, //!< Missing a name for object member. |
4544 | + kParseErrorObjectMissColon, //!< Missing a colon after a name of object member. |
4545 | + kParseErrorObjectMissCommaOrCurlyBracket, //!< Missing a comma or '}' after an object member. |
4546 | + |
4547 | + kParseErrorArrayMissCommaOrSquareBracket, //!< Missing a comma or ']' after an array element. |
4548 | + |
4549 | + kParseErrorStringUnicodeEscapeInvalidHex, //!< Incorrect hex digit after \\u escape in string. |
4550 | + kParseErrorStringUnicodeSurrogateInvalid, //!< The surrogate pair in string is invalid. |
4551 | + kParseErrorStringEscapeInvalid, //!< Invalid escape character in string. |
4552 | + kParseErrorStringMissQuotationMark, //!< Missing a closing quotation mark in string. |
4553 | + kParseErrorStringInvalidEncoding, //!< Invalid encoding in string. |
4554 | + |
4555 | + kParseErrorNumberTooBig, //!< Number too big to be stored in double. |
4556 | + kParseErrorNumberMissFraction, //!< Miss fraction part in number. |
4557 | + kParseErrorNumberMissExponent, //!< Miss exponent in number. |
4558 | + |
4559 | + kParseErrorTermination, //!< Parsing was terminated. |
4560 | + kParseErrorUnspecificSyntaxError //!< Unspecific syntax error. |
4561 | +}; |
4562 | + |
4563 | +//! Result of parsing (wraps ParseErrorCode) |
4564 | +/*! |
4565 | + \ingroup RAPIDJSON_ERRORS |
4566 | + \code |
4567 | + Document doc; |
4568 | + ParseResult ok = doc.Parse("[42]"); |
4569 | + if (!ok) { |
4570 | + fprintf(stderr, "JSON parse error: %s (%u)", |
4571 | + GetParseError_En(ok.Code()), ok.Offset()); |
4572 | + exit(EXIT_FAILURE); |
4573 | + } |
4574 | + \endcode |
4575 | + \see GenericReader::Parse, GenericDocument::Parse |
4576 | +*/ |
4577 | +struct ParseResult { |
4578 | + |
4579 | + //! Default constructor, no error. |
4580 | + ParseResult() : code_(kParseErrorNone), offset_(0) {} |
4581 | + //! Constructor to set an error. |
4582 | + ParseResult(ParseErrorCode code, size_t offset) : code_(code), offset_(offset) {} |
4583 | + |
4584 | + //! Get the error code. |
4585 | + ParseErrorCode Code() const { return code_; } |
4586 | + //! Get the error offset, if \ref IsError(), 0 otherwise. |
4587 | + size_t Offset() const { return offset_; } |
4588 | + |
4589 | + //! Conversion to \c bool, returns \c true, iff !\ref IsError(). |
4590 | + operator bool() const { return !IsError(); } |
4591 | + //! Whether the result is an error. |
4592 | + bool IsError() const { return code_ != kParseErrorNone; } |
4593 | + |
4594 | + bool operator==(const ParseResult& that) const { return code_ == that.code_; } |
4595 | + bool operator==(ParseErrorCode code) const { return code_ == code; } |
4596 | + friend bool operator==(ParseErrorCode code, const ParseResult & err) { return code == err.code_; } |
4597 | + |
4598 | + //! Reset error code. |
4599 | + void Clear() { Set(kParseErrorNone); } |
4600 | + //! Update error code and offset. |
4601 | + void Set(ParseErrorCode code, size_t offset = 0) { code_ = code; offset_ = offset; } |
4602 | + |
4603 | +private: |
4604 | + ParseErrorCode code_; |
4605 | + size_t offset_; |
4606 | +}; |
4607 | + |
4608 | +//! Function pointer type of GetParseError(). |
4609 | +/*! \ingroup RAPIDJSON_ERRORS |
4610 | + |
4611 | + This is the prototype for \c GetParseError_X(), where \c X is a locale. |
4612 | + User can dynamically change locale in runtime, e.g.: |
4613 | +\code |
4614 | + GetParseErrorFunc GetParseError = GetParseError_En; // or whatever |
4615 | + const RAPIDJSON_ERROR_CHARTYPE* s = GetParseError(document.GetParseErrorCode()); |
4616 | +\endcode |
4617 | +*/ |
4618 | +typedef const RAPIDJSON_ERROR_CHARTYPE* (*GetParseErrorFunc)(ParseErrorCode); |
4619 | + |
4620 | +RAPIDJSON_NAMESPACE_END |
4621 | + |
4622 | +#endif // RAPIDJSON_ERROR_ERROR_H__ |
4623 | |
4624 | === added file 'shorts/xml2json/rapidjson/filereadstream.h' |
4625 | --- shorts/xml2json/rapidjson/filereadstream.h 1970-01-01 00:00:00 +0000 |
4626 | +++ shorts/xml2json/rapidjson/filereadstream.h 2015-12-15 16:05:21 +0000 |
4627 | @@ -0,0 +1,94 @@ |
4628 | +// Copyright (C) 2011 Milo Yip |
4629 | +// |
4630 | +// Permission is hereby granted, free of charge, to any person obtaining a copy |
4631 | +// of this software and associated documentation files (the "Software"), to deal |
4632 | +// in the Software without restriction, including without limitation the rights |
4633 | +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
4634 | +// copies of the Software, and to permit persons to whom the Software is |
4635 | +// furnished to do so, subject to the following conditions: |
4636 | +// |
4637 | +// The above copyright notice and this permission notice shall be included in |
4638 | +// all copies or substantial portions of the Software. |
4639 | +// |
4640 | +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
4641 | +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
4642 | +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
4643 | +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
4644 | +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
4645 | +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
4646 | +// THE SOFTWARE. |
4647 | + |
4648 | +#ifndef RAPIDJSON_FILEREADSTREAM_H_ |
4649 | +#define RAPIDJSON_FILEREADSTREAM_H_ |
4650 | + |
4651 | +#include "rapidjson.h" |
4652 | +#include <cstdio> |
4653 | + |
4654 | +RAPIDJSON_NAMESPACE_BEGIN |
4655 | + |
4656 | +//! File byte stream for input using fread(). |
4657 | +/*! |
4658 | + \note implements Stream concept |
4659 | +*/ |
4660 | +class FileReadStream { |
4661 | +public: |
4662 | + typedef char Ch; //!< Character type (byte). |
4663 | + |
4664 | + //! Constructor. |
4665 | + /*! |
4666 | + \param fp File pointer opened for read. |
4667 | + \param buffer user-supplied buffer. |
4668 | + \param bufferSize size of buffer in bytes. Must >=4 bytes. |
4669 | + */ |
4670 | + FileReadStream(std::FILE* fp, char* buffer, size_t bufferSize) : fp_(fp), buffer_(buffer), bufferSize_(bufferSize), bufferLast_(0), current_(buffer_), readCount_(0), count_(0), eof_(false) { |
4671 | + RAPIDJSON_ASSERT(fp_ != 0); |
4672 | + RAPIDJSON_ASSERT(bufferSize >= 4); |
4673 | + Read(); |
4674 | + } |
4675 | + |
4676 | + Ch Peek() const { return *current_; } |
4677 | + Ch Take() { Ch c = *current_; Read(); return c; } |
4678 | + size_t Tell() const { return count_ + static_cast<size_t>(current_ - buffer_); } |
4679 | + |
4680 | + // Not implemented |
4681 | + void Put(Ch) { RAPIDJSON_ASSERT(false); } |
4682 | + void Flush() { RAPIDJSON_ASSERT(false); } |
4683 | + Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } |
4684 | + size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } |
4685 | + |
4686 | + // For encoding detection only. |
4687 | + const Ch* Peek4() const { |
4688 | + return (current_ + 4 <= bufferLast_) ? current_ : 0; |
4689 | + } |
4690 | + |
4691 | +private: |
4692 | + void Read() { |
4693 | + if (current_ < bufferLast_) |
4694 | + ++current_; |
4695 | + else if (!eof_) { |
4696 | + count_ += readCount_; |
4697 | + readCount_ = fread(buffer_, 1, bufferSize_, fp_); |
4698 | + bufferLast_ = buffer_ + readCount_ - 1; |
4699 | + current_ = buffer_; |
4700 | + |
4701 | + if (readCount_ < bufferSize_) { |
4702 | + buffer_[readCount_] = '\0'; |
4703 | + ++bufferLast_; |
4704 | + eof_ = true; |
4705 | + } |
4706 | + } |
4707 | + } |
4708 | + |
4709 | + std::FILE* fp_; |
4710 | + Ch *buffer_; |
4711 | + size_t bufferSize_; |
4712 | + Ch *bufferLast_; |
4713 | + Ch *current_; |
4714 | + size_t readCount_; |
4715 | + size_t count_; //!< Number of characters read |
4716 | + bool eof_; |
4717 | +}; |
4718 | + |
4719 | +RAPIDJSON_NAMESPACE_END |
4720 | + |
4721 | +#endif // RAPIDJSON_FILESTREAM_H_ |
4722 | |
4723 | === added file 'shorts/xml2json/rapidjson/filestream.h' |
4724 | --- shorts/xml2json/rapidjson/filestream.h 1970-01-01 00:00:00 +0000 |
4725 | +++ shorts/xml2json/rapidjson/filestream.h 2015-12-15 16:05:21 +0000 |
4726 | @@ -0,0 +1,73 @@ |
4727 | +// Copyright (C) 2011 Milo Yip |
4728 | +// |
4729 | +// Permission is hereby granted, free of charge, to any person obtaining a copy |
4730 | +// of this software and associated documentation files (the "Software"), to deal |
4731 | +// in the Software without restriction, including without limitation the rights |
4732 | +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
4733 | +// copies of the Software, and to permit persons to whom the Software is |
4734 | +// furnished to do so, subject to the following conditions: |
4735 | +// |
4736 | +// The above copyright notice and this permission notice shall be included in |
4737 | +// all copies or substantial portions of the Software. |
4738 | +// |
4739 | +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
4740 | +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
4741 | +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
4742 | +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
4743 | +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
4744 | +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
4745 | +// THE SOFTWARE. |
4746 | + |
4747 | +#ifndef RAPIDJSON_FILESTREAM_H_ |
4748 | +#define RAPIDJSON_FILESTREAM_H_ |
4749 | + |
4750 | +#include "rapidjson.h" |
4751 | +#include <cstdio> |
4752 | + |
4753 | +RAPIDJSON_NAMESPACE_BEGIN |
4754 | + |
4755 | +//! (Deprecated) Wrapper of C file stream for input or output. |
4756 | +/*! |
4757 | + This simple wrapper does not check the validity of the stream. |
4758 | + \note implements Stream concept |
4759 | + \note deprecated: This was only for basic testing in version 0.1, it is found that the performance is very low by using fgetc(). Use FileReadStream instead. |
4760 | +*/ |
4761 | +class FileStream { |
4762 | +public: |
4763 | + typedef char Ch; //!< Character type. Only support char. |
4764 | + |
4765 | + FileStream(std::FILE* fp) : fp_(fp), current_('\0'), count_(0) { Read(); } |
4766 | + char Peek() const { return current_; } |
4767 | + char Take() { char c = current_; Read(); return c; } |
4768 | + size_t Tell() const { return count_; } |
4769 | + void Put(char c) { fputc(c, fp_); } |
4770 | + void Flush() { fflush(fp_); } |
4771 | + |
4772 | + // Not implemented |
4773 | + char* PutBegin() { return 0; } |
4774 | + size_t PutEnd(char*) { return 0; } |
4775 | + |
4776 | +private: |
4777 | + // Prohibit copy constructor & assignment operator. |
4778 | + FileStream(const FileStream&); |
4779 | + FileStream& operator=(const FileStream&); |
4780 | + |
4781 | + void Read() { |
4782 | + RAPIDJSON_ASSERT(fp_ != 0); |
4783 | + int c = fgetc(fp_); |
4784 | + if (c != EOF) { |
4785 | + current_ = (char)c; |
4786 | + count_++; |
4787 | + } |
4788 | + else if (current_ != '\0') |
4789 | + current_ = '\0'; |
4790 | + } |
4791 | + |
4792 | + std::FILE* fp_; |
4793 | + char current_; |
4794 | + size_t count_; |
4795 | +}; |
4796 | + |
4797 | +RAPIDJSON_NAMESPACE_END |
4798 | + |
4799 | +#endif // RAPIDJSON_FILESTREAM_H_ |
4800 | |
4801 | === added file 'shorts/xml2json/rapidjson/filewritestream.h' |
4802 | --- shorts/xml2json/rapidjson/filewritestream.h 1970-01-01 00:00:00 +0000 |
4803 | +++ shorts/xml2json/rapidjson/filewritestream.h 2015-12-15 16:05:21 +0000 |
4804 | @@ -0,0 +1,97 @@ |
4805 | +// Copyright (C) 2011 Milo Yip |
4806 | +// |
4807 | +// Permission is hereby granted, free of charge, to any person obtaining a copy |
4808 | +// of this software and associated documentation files (the "Software"), to deal |
4809 | +// in the Software without restriction, including without limitation the rights |
4810 | +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
4811 | +// copies of the Software, and to permit persons to whom the Software is |
4812 | +// furnished to do so, subject to the following conditions: |
4813 | +// |
4814 | +// The above copyright notice and this permission notice shall be included in |
4815 | +// all copies or substantial portions of the Software. |
4816 | +// |
4817 | +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
4818 | +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
4819 | +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
4820 | +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
4821 | +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
4822 | +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
4823 | +// THE SOFTWARE. |
4824 | + |
4825 | +#ifndef RAPIDJSON_FILEWRITESTREAM_H_ |
4826 | +#define RAPIDJSON_FILEWRITESTREAM_H_ |
4827 | + |
4828 | +#include "rapidjson.h" |
4829 | +#include <cstdio> |
4830 | + |
4831 | +RAPIDJSON_NAMESPACE_BEGIN |
4832 | + |
4833 | +//! Wrapper of C file stream for input using fread(). |
4834 | +/*! |
4835 | + \note implements Stream concept |
4836 | +*/ |
4837 | +class FileWriteStream { |
4838 | +public: |
4839 | + typedef char Ch; //!< Character type. Only support char. |
4840 | + |
4841 | + FileWriteStream(std::FILE* fp, char* buffer, size_t bufferSize) : fp_(fp), buffer_(buffer), bufferEnd_(buffer + bufferSize), current_(buffer_) { |
4842 | + RAPIDJSON_ASSERT(fp_ != 0); |
4843 | + } |
4844 | + |
4845 | + void Put(char c) { |
4846 | + if (current_ >= bufferEnd_) |
4847 | + Flush(); |
4848 | + |
4849 | + *current_++ = c; |
4850 | + } |
4851 | + |
4852 | + void PutN(char c, size_t n) { |
4853 | + size_t avail = static_cast<size_t>(bufferEnd_ - current_); |
4854 | + while (n > avail) { |
4855 | + std::memset(current_, c, avail); |
4856 | + current_ += avail; |
4857 | + Flush(); |
4858 | + n -= avail; |
4859 | + avail = static_cast<size_t>(bufferEnd_ - current_); |
4860 | + } |
4861 | + |
4862 | + if (n > 0) { |
4863 | + std::memset(current_, c, n); |
4864 | + current_ += n; |
4865 | + } |
4866 | + } |
4867 | + |
4868 | + void Flush() { |
4869 | + if (current_ != buffer_) { |
4870 | + fwrite(buffer_, 1, static_cast<size_t>(current_ - buffer_), fp_); |
4871 | + current_ = buffer_; |
4872 | + } |
4873 | + } |
4874 | + |
4875 | + // Not implemented |
4876 | + char Peek() const { RAPIDJSON_ASSERT(false); return 0; } |
4877 | + char Take() { RAPIDJSON_ASSERT(false); return 0; } |
4878 | + size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; } |
4879 | + char* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } |
4880 | + size_t PutEnd(char*) { RAPIDJSON_ASSERT(false); return 0; } |
4881 | + |
4882 | +private: |
4883 | + // Prohibit copy constructor & assignment operator. |
4884 | + FileWriteStream(const FileWriteStream&); |
4885 | + FileWriteStream& operator=(const FileWriteStream&); |
4886 | + |
4887 | + std::FILE* fp_; |
4888 | + char *buffer_; |
4889 | + char *bufferEnd_; |
4890 | + char *current_; |
4891 | +}; |
4892 | + |
4893 | +//! Implement specialized version of PutN() with memset() for better performance. |
4894 | +template<> |
4895 | +inline void PutN(FileWriteStream& stream, char c, size_t n) { |
4896 | + stream.PutN(c, n); |
4897 | +} |
4898 | + |
4899 | +RAPIDJSON_NAMESPACE_END |
4900 | + |
4901 | +#endif // RAPIDJSON_FILESTREAM_H_ |
4902 | |
4903 | === added directory 'shorts/xml2json/rapidjson/internal' |
4904 | === added file 'shorts/xml2json/rapidjson/internal/biginteger.h' |
4905 | --- shorts/xml2json/rapidjson/internal/biginteger.h 1970-01-01 00:00:00 +0000 |
4906 | +++ shorts/xml2json/rapidjson/internal/biginteger.h 2015-12-15 16:05:21 +0000 |
4907 | @@ -0,0 +1,294 @@ |
4908 | +// Copyright (C) 2011 Milo Yip |
4909 | +// |
4910 | +// Permission is hereby granted, free of charge, to any person obtaining a copy |
4911 | +// of this software and associated documentation files (the "Software"), to deal |
4912 | +// in the Software without restriction, including without limitation the rights |
4913 | +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
4914 | +// copies of the Software, and to permit persons to whom the Software is |
4915 | +// furnished to do so, subject to the following conditions: |
4916 | +// |
4917 | +// The above copyright notice and this permission notice shall be included in |
4918 | +// all copies or substantial portions of the Software. |
4919 | +// |
4920 | +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
4921 | +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
4922 | +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
4923 | +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
4924 | +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
4925 | +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
4926 | +// THE SOFTWARE. |
4927 | + |
4928 | +#ifndef RAPIDJSON_BIGINTEGER_H_ |
4929 | +#define RAPIDJSON_BIGINTEGER_H_ |
4930 | + |
4931 | +#include "../rapidjson.h" |
4932 | + |
4933 | +#if defined(_MSC_VER) && defined(_M_AMD64) |
4934 | +#include <intrin.h> // for _umul128 |
4935 | +#endif |
4936 | + |
4937 | +RAPIDJSON_NAMESPACE_BEGIN |
4938 | +namespace internal { |
4939 | + |
4940 | +class BigInteger { |
4941 | +public: |
4942 | + typedef uint64_t Type; |
4943 | + |
4944 | + BigInteger(const BigInteger& rhs) : count_(rhs.count_) { |
4945 | + std::memcpy(digits_, rhs.digits_, count_ * sizeof(Type)); |
4946 | + } |
4947 | + |
4948 | + explicit BigInteger(uint64_t u) : count_(1) { |
4949 | + digits_[0] = u; |
4950 | + } |
4951 | + |
4952 | + BigInteger(const char* decimals, size_t length) : count_(1) { |
4953 | + RAPIDJSON_ASSERT(length > 0); |
4954 | + digits_[0] = 0; |
4955 | + size_t i = 0; |
4956 | + const size_t kMaxDigitPerIteration = 19; // 2^64 = 18446744073709551616 > 10^19 |
4957 | + while (length >= kMaxDigitPerIteration) { |
4958 | + AppendDecimal64(decimals + i, decimals + i + kMaxDigitPerIteration); |
4959 | + length -= kMaxDigitPerIteration; |
4960 | + i += kMaxDigitPerIteration; |
4961 | + } |
4962 | + |
4963 | + if (length > 0) |
4964 | + AppendDecimal64(decimals + i, decimals + i + length); |
4965 | + } |
4966 | + |
4967 | + BigInteger& operator=(uint64_t u) { |
4968 | + digits_[0] = u; |
4969 | + count_ = 1; |
4970 | + return *this; |
4971 | + } |
4972 | + |
4973 | + BigInteger& operator+=(uint64_t u) { |
4974 | + Type backup = digits_[0]; |
4975 | + digits_[0] += u; |
4976 | + for (size_t i = 0; i < count_ - 1; i++) { |
4977 | + if (digits_[i] >= backup) |
4978 | + return *this; // no carry |
4979 | + backup = digits_[i + 1]; |
4980 | + digits_[i + 1] += 1; |
4981 | + } |
4982 | + |
4983 | + // Last carry |
4984 | + if (digits_[count_ - 1] < backup) |
4985 | + PushBack(1); |
4986 | + |
4987 | + return *this; |
4988 | + } |
4989 | + |
4990 | + BigInteger& operator*=(uint64_t u) { |
4991 | + if (u == 0) return *this = 0; |
4992 | + if (u == 1) return *this; |
4993 | + if (*this == 1) return *this = u; |
4994 | + |
4995 | + uint64_t k = 0; |
4996 | + for (size_t i = 0; i < count_; i++) { |
4997 | + uint64_t hi; |
4998 | + digits_[i] = MulAdd64(digits_[i], u, k, &hi); |
4999 | + k = hi; |
5000 | + } |
The diff has been truncated for viewing.
PASSED: Continuous integration, rev:417 /core-apps- jenkins. ubuntu. com/job/ shorts- app-ci/ 10/ /core-apps- jenkins. ubuntu. com/job/ generic- update- mp/258/ console
https:/
Executed test runs:
None: https:/
Click here to trigger a rebuild: /core-apps- jenkins. ubuntu. com/job/ shorts- app-ci/ 10/rebuild
https:/