diff --git a/README.md b/README.md
index 3d86a676..6c5a0905 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,7 @@
#Cordova Low Latency Audio Plugin for iOS and Android
=======================
-Prerequisites: A Cordova/PhoneGap 3.0+ project for iOS or Android.
+Prerequisites: A Cordova/PhoneGap 3.0+ project for iOS, Android or BlackBerry 10.
## Index
@@ -115,7 +115,7 @@ Unloads an audio file from memory.
* ID - string unique ID for the audio file
* success - success callback function
* fail - error/fail callback function
-
+
##Example
In this example, the resources reside in a relative path under the Cordova root folder "www/".
@@ -134,27 +134,27 @@ The implementation goes as follows:
```javascript
if( window.plugins && window.plugins.LowLatencyAudio ) {
var lla = window.plugins.LowLatencyAudio;
-
+
// preload audio resource
lla.preloadAudio( 'music', media['music'], 1, 1, function(msg){
}, function(msg){
console.log( 'error: ' + msg );
});
-
+
lla.preloadFX( 'click', media['click'], function(msg){
}, function(msg){
console.log( 'error: ' + msg );
});
-
+
// now start playing
lla.play( 'click' );
lla.loop( 'music' );
- // stop after 1 min
+ // stop after 1 min
window.setTimeout( function(){
//lla.stop( 'click' );
lla.stop( 'music' );
-
+
lla.unload( 'music' );
lla.unload( 'click' );
}, 1000 * 60 );
@@ -177,4 +177,3 @@ cordova plugin add https://github.com/floatinghotpot/cordova-plugin-lowlatencyau
The first iteration of the Plugin was built by [Andrew Trice](https://github.com/triceam/LowLatencyAudio).
This plugin was ported to Plugman / Cordova 3 by [Raymond Xie](https://github.com/floatinghotpot), [SidneyS](https://github.com/sidneys) and other committers.
-
diff --git a/plugin.xml b/plugin.xml
index e998c027..c4d97e04 100644
--- a/plugin.xml
+++ b/plugin.xml
@@ -3,11 +3,11 @@
xmlns:android="http://schemas.android.com/apk/res/android"
id="com.rjfun.cordova.plugin.lowlatencyaudio"
version="1.1.4">
-
+
LowLatencyAudio
Andrew Trice, updated by Raymond Xie, etc.
Cordova/PhoneGap 3+ Plugin to support Low Latency and Polyphonic Audio Playback on Android and iOS, must have for mobile apps/games, as HTML5 audio in mobile browsers is really poor. Also implemented same interface for HTML5 audio, useful when test in PC browser.
-
+
MIT
audio,fx,music,mp3,game
https://github.com/floatinghotpot/cordova-plugin-lowlatencyaudio.git
@@ -23,7 +23,7 @@
-
+
@@ -33,28 +33,39 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/blackberry10/LICENSE b/src/blackberry10/LICENSE
new file mode 100644
index 00000000..2e41acf1
--- /dev/null
+++ b/src/blackberry10/LICENSE
@@ -0,0 +1,704 @@
+Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+-------------------------------------------------------
+*JNEXT (v1.0.8.3)
+
+ MOZILLA PUBLIC LICENSE
+ Version 1.1
+
+ ---------------
+
+1. Definitions.
+
+ 1.0.1. "Commercial Use" means distribution or otherwise making the
+ Covered Code available to a third party.
+
+ 1.1. "Contributor" means each entity that creates or contributes to
+ the creation of Modifications.
+
+ 1.2. "Contributor Version" means the combination of the Original
+ Code, prior Modifications used by a Contributor, and the Modifications
+ made by that particular Contributor.
+
+ 1.3. "Covered Code" means the Original Code or Modifications or the
+ combination of the Original Code and Modifications, in each case
+ including portions thereof.
+
+ 1.4. "Electronic Distribution Mechanism" means a mechanism generally
+ accepted in the software development community for the electronic
+ transfer of data.
+
+ 1.5. "Executable" means Covered Code in any form other than Source
+ Code.
+
+ 1.6. "Initial Developer" means the individual or entity identified
+ as the Initial Developer in the Source Code notice required by Exhibit
+ A.
+
+ 1.7. "Larger Work" means a work which combines Covered Code or
+ portions thereof with code not governed by the terms of this License.
+
+ 1.8. "License" means this document.
+
+ 1.8.1. "Licensable" means having the right to grant, to the maximum
+ extent possible, whether at the time of the initial grant or
+ subsequently acquired, any and all of the rights conveyed herein.
+
+ 1.9. "Modifications" means any addition to or deletion from the
+ substance or structure of either the Original Code or any previous
+ Modifications. When Covered Code is released as a series of files, a
+ Modification is:
+ A. Any addition to or deletion from the contents of a file
+ containing Original Code or previous Modifications.
+
+ B. Any new file that contains any part of the Original Code or
+ previous Modifications.
+
+ 1.10. "Original Code" means Source Code of computer software code
+ which is described in the Source Code notice required by Exhibit A as
+ Original Code, and which, at the time of its release under this
+ License is not already Covered Code governed by this License.
+
+ 1.10.1. "Patent Claims" means any patent claim(s), now owned or
+ hereafter acquired, including without limitation, method, process,
+ and apparatus claims, in any patent Licensable by grantor.
+
+ 1.11. "Source Code" means the preferred form of the Covered Code for
+ making modifications to it, including all modules it contains, plus
+ any associated interface definition files, scripts used to control
+ compilation and installation of an Executable, or source code
+ differential comparisons against either the Original Code or another
+ well known, available Covered Code of the Contributor's choice. The
+ Source Code can be in a compressed or archival form, provided the
+ appropriate decompression or de-archiving software is widely available
+ for no charge.
+
+ 1.12. "You" (or "Your") means an individual or a legal entity
+ exercising rights under, and complying with all of the terms of, this
+ License or a future version of this License issued under Section 6.1.
+ For legal entities, "You" includes any entity which controls, is
+ controlled by, or is under common control with You. For purposes of
+ this definition, "control" means (a) the power, direct or indirect,
+ to cause the direction or management of such entity, whether by
+ contract or otherwise, or (b) ownership of more than fifty percent
+ (50%) of the outstanding shares or beneficial ownership of such
+ entity.
+
+2. Source Code License.
+
+ 2.1. The Initial Developer Grant.
+ The Initial Developer hereby grants You a world-wide, royalty-free,
+ non-exclusive license, subject to third party intellectual property
+ claims:
+ (a) under intellectual property rights (other than patent or
+ trademark) Licensable by Initial Developer to use, reproduce,
+ modify, display, perform, sublicense and distribute the Original
+ Code (or portions thereof) with or without Modifications, and/or
+ as part of a Larger Work; and
+
+ (b) under Patents Claims infringed by the making, using or
+ selling of Original Code, to make, have made, use, practice,
+ sell, and offer for sale, and/or otherwise dispose of the
+ Original Code (or portions thereof).
+
+ (c) the licenses granted in this Section 2.1(a) and (b) are
+ effective on the date Initial Developer first distributes
+ Original Code under the terms of this License.
+
+ (d) Notwithstanding Section 2.1(b) above, no patent license is
+ granted: 1) for code that You delete from the Original Code; 2)
+ separate from the Original Code; or 3) for infringements caused
+ by: i) the modification of the Original Code or ii) the
+ combination of the Original Code with other software or devices.
+
+ 2.2. Contributor Grant.
+ Subject to third party intellectual property claims, each Contributor
+ hereby grants You a world-wide, royalty-free, non-exclusive license
+
+ (a) under intellectual property rights (other than patent or
+ trademark) Licensable by Contributor, to use, reproduce, modify,
+ display, perform, sublicense and distribute the Modifications
+ created by such Contributor (or portions thereof) either on an
+ unmodified basis, with other Modifications, as Covered Code
+ and/or as part of a Larger Work; and
+
+ (b) under Patent Claims infringed by the making, using, or
+ selling of Modifications made by that Contributor either alone
+ and/or in combination with its Contributor Version (or portions
+ of such combination), to make, use, sell, offer for sale, have
+ made, and/or otherwise dispose of: 1) Modifications made by that
+ Contributor (or portions thereof); and 2) the combination of
+ Modifications made by that Contributor with its Contributor
+ Version (or portions of such combination).
+
+ (c) the licenses granted in Sections 2.2(a) and 2.2(b) are
+ effective on the date Contributor first makes Commercial Use of
+ the Covered Code.
+
+ (d) Notwithstanding Section 2.2(b) above, no patent license is
+ granted: 1) for any code that Contributor has deleted from the
+ Contributor Version; 2) separate from the Contributor Version;
+ 3) for infringements caused by: i) third party modifications of
+ Contributor Version or ii) the combination of Modifications made
+ by that Contributor with other software (except as part of the
+ Contributor Version) or other devices; or 4) under Patent Claims
+ infringed by Covered Code in the absence of Modifications made by
+ that Contributor.
+
+3. Distribution Obligations.
+
+ 3.1. Application of License.
+ The Modifications which You create or to which You contribute are
+ governed by the terms of this License, including without limitation
+ Section 2.2. The Source Code version of Covered Code may be
+ distributed only under the terms of this License or a future version
+ of this License released under Section 6.1, and You must include a
+ copy of this License with every copy of the Source Code You
+ distribute. You may not offer or impose any terms on any Source Code
+ version that alters or restricts the applicable version of this
+ License or the recipients' rights hereunder. However, You may include
+ an additional document offering the additional rights described in
+ Section 3.5.
+
+ 3.2. Availability of Source Code.
+ Any Modification which You create or to which You contribute must be
+ made available in Source Code form under the terms of this License
+ either on the same media as an Executable version or via an accepted
+ Electronic Distribution Mechanism to anyone to whom you made an
+ Executable version available; and if made available via Electronic
+ Distribution Mechanism, must remain available for at least twelve (12)
+ months after the date it initially became available, or at least six
+ (6) months after a subsequent version of that particular Modification
+ has been made available to such recipients. You are responsible for
+ ensuring that the Source Code version remains available even if the
+ Electronic Distribution Mechanism is maintained by a third party.
+
+ 3.3. Description of Modifications.
+ You must cause all Covered Code to which You contribute to contain a
+ file documenting the changes You made to create that Covered Code and
+ the date of any change. You must include a prominent statement that
+ the Modification is derived, directly or indirectly, from Original
+ Code provided by the Initial Developer and including the name of the
+ Initial Developer in (a) the Source Code, and (b) in any notice in an
+ Executable version or related documentation in which You describe the
+ origin or ownership of the Covered Code.
+
+ 3.4. Intellectual Property Matters
+ (a) Third Party Claims.
+ If Contributor has knowledge that a license under a third party's
+ intellectual property rights is required to exercise the rights
+ granted by such Contributor under Sections 2.1 or 2.2,
+ Contributor must include a text file with the Source Code
+ distribution titled "LEGAL" which describes the claim and the
+ party making the claim in sufficient detail that a recipient will
+ know whom to contact. If Contributor obtains such knowledge after
+ the Modification is made available as described in Section 3.2,
+ Contributor shall promptly modify the LEGAL file in all copies
+ Contributor makes available thereafter and shall take other steps
+ (such as notifying appropriate mailing lists or newsgroups)
+ reasonably calculated to inform those who received the Covered
+ Code that new knowledge has been obtained.
+
+ (b) Contributor APIs.
+ If Contributor's Modifications include an application programming
+ interface and Contributor has knowledge of patent licenses which
+ are reasonably necessary to implement that API, Contributor must
+ also include this information in the LEGAL file.
+
+ (c) Representations.
+ Contributor represents that, except as disclosed pursuant to
+ Section 3.4(a) above, Contributor believes that Contributor's
+ Modifications are Contributor's original creation(s) and/or
+ Contributor has sufficient rights to grant the rights conveyed by
+ this License.
+
+ 3.5. Required Notices.
+ You must duplicate the notice in Exhibit A in each file of the Source
+ Code. If it is not possible to put such notice in a particular Source
+ Code file due to its structure, then You must include such notice in a
+ location (such as a relevant directory) where a user would be likely
+ to look for such a notice. If You created one or more Modification(s)
+ You may add your name as a Contributor to the notice described in
+ Exhibit A. You must also duplicate this License in any documentation
+ for the Source Code where You describe recipients' rights or ownership
+ rights relating to Covered Code. You may choose to offer, and to
+ charge a fee for, warranty, support, indemnity or liability
+ obligations to one or more recipients of Covered Code. However, You
+ may do so only on Your own behalf, and not on behalf of the Initial
+ Developer or any Contributor. You must make it absolutely clear than
+ any such warranty, support, indemnity or liability obligation is
+ offered by You alone, and You hereby agree to indemnify the Initial
+ Developer and every Contributor for any liability incurred by the
+ Initial Developer or such Contributor as a result of warranty,
+ support, indemnity or liability terms You offer.
+
+ 3.6. Distribution of Executable Versions.
+ You may distribute Covered Code in Executable form only if the
+ requirements of Section 3.1-3.5 have been met for that Covered Code,
+ and if You include a notice stating that the Source Code version of
+ the Covered Code is available under the terms of this License,
+ including a description of how and where You have fulfilled the
+ obligations of Section 3.2. The notice must be conspicuously included
+ in any notice in an Executable version, related documentation or
+ collateral in which You describe recipients' rights relating to the
+ Covered Code. You may distribute the Executable version of Covered
+ Code or ownership rights under a license of Your choice, which may
+ contain terms different from this License, provided that You are in
+ compliance with the terms of this License and that the license for the
+ Executable version does not attempt to limit or alter the recipient's
+ rights in the Source Code version from the rights set forth in this
+ License. If You distribute the Executable version under a different
+ license You must make it absolutely clear that any terms which differ
+ from this License are offered by You alone, not by the Initial
+ Developer or any Contributor. You hereby agree to indemnify the
+ Initial Developer and every Contributor for any liability incurred by
+ the Initial Developer or such Contributor as a result of any such
+ terms You offer.
+
+ 3.7. Larger Works.
+ You may create a Larger Work by combining Covered Code with other code
+ not governed by the terms of this License and distribute the Larger
+ Work as a single product. In such a case, You must make sure the
+ requirements of this License are fulfilled for the Covered Code.
+
+4. Inability to Comply Due to Statute or Regulation.
+
+ If it is impossible for You to comply with any of the terms of this
+ License with respect to some or all of the Covered Code due to
+ statute, judicial order, or regulation then You must: (a) comply with
+ the terms of this License to the maximum extent possible; and (b)
+ describe the limitations and the code they affect. Such description
+ must be included in the LEGAL file described in Section 3.4 and must
+ be included with all distributions of the Source Code. Except to the
+ extent prohibited by statute or regulation, such description must be
+ sufficiently detailed for a recipient of ordinary skill to be able to
+ understand it.
+
+5. Application of this License.
+
+ This License applies to code to which the Initial Developer has
+ attached the notice in Exhibit A and to related Covered Code.
+
+6. Versions of the License.
+
+ 6.1. New Versions.
+ Netscape Communications Corporation ("Netscape") may publish revised
+ and/or new versions of the License from time to time. Each version
+ will be given a distinguishing version number.
+
+ 6.2. Effect of New Versions.
+ Once Covered Code has been published under a particular version of the
+ License, You may always continue to use it under the terms of that
+ version. You may also choose to use such Covered Code under the terms
+ of any subsequent version of the License published by Netscape. No one
+ other than Netscape has the right to modify the terms applicable to
+ Covered Code created under this License.
+
+ 6.3. Derivative Works.
+ If You create or use a modified version of this License (which you may
+ only do in order to apply it to code which is not already Covered Code
+ governed by this License), You must (a) rename Your license so that
+ the phrases "Mozilla", "MOZILLAPL", "MOZPL", "Netscape",
+ "MPL", "NPL" or any confusingly similar phrase do not appear in your
+ license (except to note that your license differs from this License)
+ and (b) otherwise make it clear that Your version of the license
+ contains terms which differ from the Mozilla Public License and
+ Netscape Public License. (Filling in the name of the Initial
+ Developer, Original Code or Contributor in the notice described in
+ Exhibit A shall not of themselves be deemed to be modifications of
+ this License.)
+
+7. DISCLAIMER OF WARRANTY.
+
+ COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
+ WITHOUT LIMITATION, WARRANTIES THAT THE COVERED CODE IS FREE OF
+ DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE OR NON-INFRINGING.
+ THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED CODE
+ IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT,
+ YOU (NOT THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE
+ COST OF ANY NECESSARY SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER
+ OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. NO USE OF
+ ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER.
+
+8. TERMINATION.
+
+ 8.1. This License and the rights granted hereunder will terminate
+ automatically if You fail to comply with terms herein and fail to cure
+ such breach within 30 days of becoming aware of the breach. All
+ sublicenses to the Covered Code which are properly granted shall
+ survive any termination of this License. Provisions which, by their
+ nature, must remain in effect beyond the termination of this License
+ shall survive.
+
+ 8.2. If You initiate litigation by asserting a patent infringement
+ claim (excluding declatory judgment actions) against Initial Developer
+ or a Contributor (the Initial Developer or Contributor against whom
+ You file such action is referred to as "Participant") alleging that:
+
+ (a) such Participant's Contributor Version directly or indirectly
+ infringes any patent, then any and all rights granted by such
+ Participant to You under Sections 2.1 and/or 2.2 of this License
+ shall, upon 60 days notice from Participant terminate prospectively,
+ unless if within 60 days after receipt of notice You either: (i)
+ agree in writing to pay Participant a mutually agreeable reasonable
+ royalty for Your past and future use of Modifications made by such
+ Participant, or (ii) withdraw Your litigation claim with respect to
+ the Contributor Version against such Participant. If within 60 days
+ of notice, a reasonable royalty and payment arrangement are not
+ mutually agreed upon in writing by the parties or the litigation claim
+ is not withdrawn, the rights granted by Participant to You under
+ Sections 2.1 and/or 2.2 automatically terminate at the expiration of
+ the 60 day notice period specified above.
+
+ (b) any software, hardware, or device, other than such Participant's
+ Contributor Version, directly or indirectly infringes any patent, then
+ any rights granted to You by such Participant under Sections 2.1(b)
+ and 2.2(b) are revoked effective as of the date You first made, used,
+ sold, distributed, or had made, Modifications made by that
+ Participant.
+
+ 8.3. If You assert a patent infringement claim against Participant
+ alleging that such Participant's Contributor Version directly or
+ indirectly infringes any patent where such claim is resolved (such as
+ by license or settlement) prior to the initiation of patent
+ infringement litigation, then the reasonable value of the licenses
+ granted by such Participant under Sections 2.1 or 2.2 shall be taken
+ into account in determining the amount or value of any payment or
+ license.
+
+ 8.4. In the event of termination under Sections 8.1 or 8.2 above,
+ all end user license agreements (excluding distributors and resellers)
+ which have been validly granted by You or any distributor hereunder
+ prior to termination shall survive termination.
+
+9. LIMITATION OF LIABILITY.
+
+ UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, WHETHER TORT
+ (INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL YOU, THE INITIAL
+ DEVELOPER, ANY OTHER CONTRIBUTOR, OR ANY DISTRIBUTOR OF COVERED CODE,
+ OR ANY SUPPLIER OF ANY OF SUCH PARTIES, BE LIABLE TO ANY PERSON FOR
+ ANY INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES OF ANY
+ CHARACTER INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF GOODWILL,
+ WORK STOPPAGE, COMPUTER FAILURE OR MALFUNCTION, OR ANY AND ALL OTHER
+ COMMERCIAL DAMAGES OR LOSSES, EVEN IF SUCH PARTY SHALL HAVE BEEN
+ INFORMED OF THE POSSIBILITY OF SUCH DAMAGES. THIS LIMITATION OF
+ LIABILITY SHALL NOT APPLY TO LIABILITY FOR DEATH OR PERSONAL INJURY
+ RESULTING FROM SUCH PARTY'S NEGLIGENCE TO THE EXTENT APPLICABLE LAW
+ PROHIBITS SUCH LIMITATION. SOME JURISDICTIONS DO NOT ALLOW THE
+ EXCLUSION OR LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO
+ THIS EXCLUSION AND LIMITATION MAY NOT APPLY TO YOU.
+
+10. U.S. GOVERNMENT END USERS.
+
+ The Covered Code is a "commercial item," as that term is defined in
+ 48 C.F.R. 2.101 (Oct. 1995), consisting of "commercial computer
+ software" and "commercial computer software documentation," as such
+ terms are used in 48 C.F.R. 12.212 (Sept. 1995). Consistent with 48
+ C.F.R. 12.212 and 48 C.F.R. 227.7202-1 through 227.7202-4 (June 1995),
+ all U.S. Government End Users acquire Covered Code with only those
+ rights set forth herein.
+
+11. MISCELLANEOUS.
+
+ This License represents the complete agreement concerning subject
+ matter hereof. If any provision of this License is held to be
+ unenforceable, such provision shall be reformed only to the extent
+ necessary to make it enforceable. This License shall be governed by
+ California law provisions (except to the extent applicable law, if
+ any, provides otherwise), excluding its conflict-of-law provisions.
+ With respect to disputes in which at least one party is a citizen of,
+ or an entity chartered or registered to do business in the United
+ States of America, any litigation relating to this License shall be
+ subject to the jurisdiction of the Federal Courts of the Northern
+ District of California, with venue lying in Santa Clara County,
+ California, with the losing party responsible for costs, including
+ without limitation, court costs and reasonable attorneys' fees and
+ expenses. The application of the United Nations Convention on
+ Contracts for the International Sale of Goods is expressly excluded.
+ Any law or regulation which provides that the language of a contract
+ shall be construed against the drafter shall not apply to this
+ License.
+
+12. RESPONSIBILITY FOR CLAIMS.
+
+ As between Initial Developer and the Contributors, each party is
+ responsible for claims and damages arising, directly or indirectly,
+ out of its utilization of rights under this License and You agree to
+ work with Initial Developer and Contributors to distribute such
+ responsibility on an equitable basis. Nothing herein is intended or
+ shall be deemed to constitute any admission of liability.
+
+13. MULTIPLE-LICENSED CODE.
+
+ Initial Developer may designate portions of the Covered Code as
+ "Multiple-Licensed". "Multiple-Licensed" means that the Initial
+ Developer permits you to utilize portions of the Covered Code under
+ Your choice of the NPL or the alternative licenses, if any, specified
+ by the Initial Developer in the file described in Exhibit A.
+
+EXHIBIT A -Mozilla Public License.
+
+ ``The contents of this file are subject to the Mozilla Public License
+ Version 1.1 (the "License"); you may not use this file except in
+ compliance with the License. You may obtain a copy of the License at
+ http://www.mozilla.org/MPL/
+
+ Software distributed under the License is distributed on an "AS IS"
+ basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
+ License for the specific language governing rights and limitations
+ under the License.
+
+ The Original Code is ______________________________________.
+
+ The Initial Developer of the Original Code is ________________________.
+ Portions created by ______________________ are Copyright (C) ______
+ _______________________. All Rights Reserved.
+
+ Contributor(s): ______________________________________.
+
+ Alternatively, the contents of this file may be used under the terms
+ of the _____ license (the "[___] License"), in which case the
+ provisions of [______] License are applicable instead of those
+ above. If you wish to allow use of your version of this file only
+ under the terms of the [____] License and not to allow others to use
+ your version of this file under the MPL, indicate your decision by
+ deleting the provisions above and replace them with the notice and
+ other provisions required by the [___] License. If you do not delete
+ the provisions above, a recipient may use your version of this file
+ under either the MPL or the [___] License."
+
+ [NOTE: The text of this Exhibit A may differ slightly from the text of
+ the notices in the Source Code files of the Original Code. You should
+ use the text of this Exhibit A rather than the text found in the
+ Original Code Source Code for Your Modifications.]
+
+-------------------------------------------------------
+
+* Tokenizer
+/************************************************************************
+The zlib/libpng License
+
+Copyright (c) 2006 Joerg Wiedenmann
+
+This software is provided 'as-is', without any express or implied warranty.
+In no event will the authors be held liable for any damages arising from
+the use of this software.
+
+Permission is granted to anyone to use this software for any purpose,
+including commercial applications, and to alter it and redistribute it
+freely, subject to the following restrictions:
+
+1. The origin of this software must not be misrepresented;
+ you must not claim that you wrote the original software.
+ If you use this software in a product, an acknowledgment
+ in the product documentation would be appreciated but is
+ not required.
+
+2. Altered source versions must be plainly marked as such,
+ and must not be misrepresented as being the original software.
+
+3. This notice may not be removed or altered from any source distribution.
+
+***********************************************************************/
+
diff --git a/src/blackberry10/index.js b/src/blackberry10/index.js
new file mode 100644
index 00000000..49cfd4c4
--- /dev/null
+++ b/src/blackberry10/index.js
@@ -0,0 +1,126 @@
+/*
+* Copyright (c) 2013 BlackBerry Limited
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+var lowLatencyAudio;
+
+module.exports = {
+
+ preloadFX: function (success, fail, args, env) {
+ var result = new PluginResult(args, env),
+ id = JSON.parse(unescape(args[0])),
+ assetPath = JSON.parse(unescape(args[1])),
+ response = lowLatencyAudio.getInstance().preloadFX(id, assetPath);
+ result.ok(response, false);
+ },
+
+ preloadAudio: function (success, fail, args, env) {
+ var result = new PluginResult(args, env),
+ id = JSON.parse(unescape(args[0])),
+ assetPath = JSON.parse(unescape(args[1])),
+ volume = args[2],
+ voices = args[3],
+ response = lowLatencyAudio.getInstance().preloadAudio(id, assetPath, volume, voices);
+ result.ok(response, false);
+ },
+
+ play: function (success, fail, args, env) {
+ var result = new PluginResult(args, env),
+ id = JSON.parse(unescape(args[0])),
+ response = lowLatencyAudio.getInstance().play(id);
+ result.ok(response, false);
+ },
+
+ stop: function (success, fail, args, env) {
+ var result = new PluginResult(args, env),
+ id = JSON.parse(unescape(args[0])),
+ response = lowLatencyAudio.getInstance().stop(id);
+ result.ok(response, false);
+ },
+
+ loop: function (success, fail, args, env) {
+ var result = new PluginResult(args, env),
+ id = JSON.parse(unescape(args[0])),
+ response = lowLatencyAudio.getInstance().loop(id);
+ result.ok(response, false);
+ },
+
+ unload: function (success, fail, args, env) {
+ var result = new PluginResult(args, env),
+ id = JSON.parse(unescape(args[0])),
+ response = lowLatencyAudio.getInstance().unload(id);
+ result.ok(response, false);
+ }
+
+};
+
+///////////////////////////////////////////////////////////////////
+// JavaScript wrapper for JNEXT plugin for connection
+///////////////////////////////////////////////////////////////////
+
+JNEXT.LowLatencyAudio = function () {
+ var self = this,
+ hasInstance = false;
+
+ self.getId = function () {
+ return self.m_id;
+ };
+
+ self.init = function () {
+ if (!JNEXT.require("libLowLatencyAudio")) {
+ return false;
+ }
+
+ self.m_id = JNEXT.createObject("libLowLatencyAudio.LowLatencyAudio_JS");
+
+ if (self.m_id === "") {
+ return false;
+ }
+
+ JNEXT.registerEvents(self);
+ };
+
+ self.preloadFX = function (id, assetPath) {
+ return JNEXT.invoke(self.m_id, "preloadFX " + id + " " + assetPath);
+ };
+ self.preloadAudio = function (id, assetPath, volume, voices) {
+ return JNEXT.invoke(self.m_id, "preloadAudio " + id + " " + assetPath + " " + volume + " " + voices);
+ };
+ self.play = function (id) {
+ return JNEXT.invoke(self.m_id, "play " + id);
+ };
+ self.stop = function (id) {
+ return JNEXT.invoke(self.m_id, "stop " + id);
+ };
+ self.loop = function (id) {
+ return JNEXT.invoke(self.m_id, "loop " + id);
+ };
+ self.unload = function (id) {
+ return JNEXT.invoke(self.m_id, "unload " + id);
+ };
+
+ self.m_id = "";
+
+ self.getInstance = function () {
+ if (!hasInstance) {
+ hasInstance = true;
+ self.init();
+ }
+ return self;
+ };
+
+};
+
+lowLatencyAudio = new JNEXT.LowLatencyAudio();
diff --git a/src/blackberry10/native/.cproject b/src/blackberry10/native/.cproject
new file mode 100644
index 00000000..fef60b0b
--- /dev/null
+++ b/src/blackberry10/native/.cproject
@@ -0,0 +1,761 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/blackberry10/native/.project b/src/blackberry10/native/.project
new file mode 100644
index 00000000..fad65a0c
--- /dev/null
+++ b/src/blackberry10/native/.project
@@ -0,0 +1,76 @@
+
+
+ LowLatencyAudio
+
+
+
+
+
+ org.eclipse.cdt.managedbuilder.core.genmakebuilder
+ clean,full,incremental,
+
+
+ ?name?
+
+
+
+ org.eclipse.cdt.make.core.append_environment
+ true
+
+
+ org.eclipse.cdt.make.core.buildArguments
+
+
+
+ org.eclipse.cdt.make.core.buildCommand
+ make
+
+
+ org.eclipse.cdt.make.core.buildLocation
+ ${workspace_loc:/LowLatencyAudio/Device-Release}
+
+
+ org.eclipse.cdt.make.core.contents
+ org.eclipse.cdt.make.core.activeConfigSettings
+
+
+ org.eclipse.cdt.make.core.enableAutoBuild
+ false
+
+
+ org.eclipse.cdt.make.core.enableCleanBuild
+ true
+
+
+ org.eclipse.cdt.make.core.enableFullBuild
+ true
+
+
+ org.eclipse.cdt.make.core.stopOnError
+ true
+
+
+ org.eclipse.cdt.make.core.useDefaultBuildCmd
+ true
+
+
+
+
+ org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder
+ full,incremental,
+
+
+
+
+ com.qnx.tools.bbt.xml.core.bbtXMLValidationBuilder
+
+
+
+
+
+ org.eclipse.cdt.core.cnature
+ org.eclipse.cdt.managedbuilder.core.managedBuildNature
+ org.eclipse.cdt.managedbuilder.core.ScannerConfigNature
+ com.qnx.tools.ide.bbt.core.bbtnature
+
+
diff --git a/src/blackberry10/native/device/libLowLatencyAudio.so b/src/blackberry10/native/device/libLowLatencyAudio.so
new file mode 100755
index 00000000..6edf8b21
Binary files /dev/null and b/src/blackberry10/native/device/libLowLatencyAudio.so differ
diff --git a/src/blackberry10/native/device/public/json_reader.o b/src/blackberry10/native/device/public/json_reader.o
new file mode 100644
index 00000000..d7873ed5
Binary files /dev/null and b/src/blackberry10/native/device/public/json_reader.o differ
diff --git a/src/blackberry10/native/device/public/json_value.o b/src/blackberry10/native/device/public/json_value.o
new file mode 100644
index 00000000..42add2e2
Binary files /dev/null and b/src/blackberry10/native/device/public/json_value.o differ
diff --git a/src/blackberry10/native/device/public/json_writer.o b/src/blackberry10/native/device/public/json_writer.o
new file mode 100644
index 00000000..53a18f22
Binary files /dev/null and b/src/blackberry10/native/device/public/json_writer.o differ
diff --git a/src/blackberry10/native/device/public/plugin.o b/src/blackberry10/native/device/public/plugin.o
new file mode 100644
index 00000000..a7049e1c
Binary files /dev/null and b/src/blackberry10/native/device/public/plugin.o differ
diff --git a/src/blackberry10/native/device/public/tokenizer.o b/src/blackberry10/native/device/public/tokenizer.o
new file mode 100644
index 00000000..a233b390
Binary files /dev/null and b/src/blackberry10/native/device/public/tokenizer.o differ
diff --git a/src/blackberry10/native/device/src/lowlatencyaudio_js.o b/src/blackberry10/native/device/src/lowlatencyaudio_js.o
new file mode 100644
index 00000000..cf0d91aa
Binary files /dev/null and b/src/blackberry10/native/device/src/lowlatencyaudio_js.o differ
diff --git a/src/blackberry10/native/public/json/autolink.h b/src/blackberry10/native/public/json/autolink.h
new file mode 100644
index 00000000..37c9258e
--- /dev/null
+++ b/src/blackberry10/native/public/json/autolink.h
@@ -0,0 +1,19 @@
+#ifndef JSON_AUTOLINK_H_INCLUDED
+# define JSON_AUTOLINK_H_INCLUDED
+
+# include "config.h"
+
+# ifdef JSON_IN_CPPTL
+# include
+# endif
+
+# if !defined(JSON_NO_AUTOLINK) && !defined(JSON_DLL_BUILD) && !defined(JSON_IN_CPPTL)
+# define CPPTL_AUTOLINK_NAME "json"
+# undef CPPTL_AUTOLINK_DLL
+# ifdef JSON_DLL
+# define CPPTL_AUTOLINK_DLL
+# endif
+# include "autolink.h"
+# endif
+
+#endif // JSON_AUTOLINK_H_INCLUDED
diff --git a/src/blackberry10/native/public/json/config.h b/src/blackberry10/native/public/json/config.h
new file mode 100644
index 00000000..5d334cbc
--- /dev/null
+++ b/src/blackberry10/native/public/json/config.h
@@ -0,0 +1,43 @@
+#ifndef JSON_CONFIG_H_INCLUDED
+# define JSON_CONFIG_H_INCLUDED
+
+/// If defined, indicates that json library is embedded in CppTL library.
+//# define JSON_IN_CPPTL 1
+
+/// If defined, indicates that json may leverage CppTL library
+//# define JSON_USE_CPPTL 1
+/// If defined, indicates that cpptl vector based map should be used instead of std::map
+/// as Value container.
+//# define JSON_USE_CPPTL_SMALLMAP 1
+/// If defined, indicates that Json specific container should be used
+/// (hash table & simple deque container with customizable allocator).
+/// THIS FEATURE IS STILL EXPERIMENTAL!
+//# define JSON_VALUE_USE_INTERNAL_MAP 1
+/// Force usage of standard new/malloc based allocator instead of memory pool based allocator.
+/// The memory pools allocator used optimization (initializing Value and ValueInternalLink
+/// as if it was a POD) that may cause some validation tool to report errors.
+/// Only has effects if JSON_VALUE_USE_INTERNAL_MAP is defined.
+//# define JSON_USE_SIMPLE_INTERNAL_ALLOCATOR 1
+
+/// If defined, indicates that Json use exception to report invalid type manipulation
+/// instead of C assert macro.
+# define JSON_USE_EXCEPTION 1
+
+# ifdef JSON_IN_CPPTL
+# include
+# ifndef JSON_USE_CPPTL
+# define JSON_USE_CPPTL 1
+# endif
+# endif
+
+# ifdef JSON_IN_CPPTL
+# define JSON_API CPPTL_API
+# elif defined(JSON_DLL_BUILD)
+# define JSON_API __declspec(dllexport)
+# elif defined(JSON_DLL)
+# define JSON_API __declspec(dllimport)
+# else
+# define JSON_API
+# endif
+
+#endif // JSON_CONFIG_H_INCLUDED
diff --git a/src/blackberry10/native/public/json/features.h b/src/blackberry10/native/public/json/features.h
new file mode 100644
index 00000000..5a9adec1
--- /dev/null
+++ b/src/blackberry10/native/public/json/features.h
@@ -0,0 +1,42 @@
+#ifndef CPPTL_JSON_FEATURES_H_INCLUDED
+# define CPPTL_JSON_FEATURES_H_INCLUDED
+
+# include "forwards.h"
+
+namespace Json {
+
+ /** \brief Configuration passed to reader and writer.
+ * This configuration object can be used to force the Reader or Writer
+ * to behave in a standard conforming way.
+ */
+ class JSON_API Features
+ {
+ public:
+ /** \brief A configuration that allows all features and assumes all strings are UTF-8.
+ * - C & C++ comments are allowed
+ * - Root object can be any JSON value
+ * - Assumes Value strings are encoded in UTF-8
+ */
+ static Features all();
+
+ /** \brief A configuration that is strictly compatible with the JSON specification.
+ * - Comments are forbidden.
+ * - Root object must be either an array or an object value.
+ * - Assumes Value strings are encoded in UTF-8
+ */
+ static Features strictMode();
+
+ /** \brief Initialize the configuration like JsonConfig::allFeatures;
+ */
+ Features();
+
+ /// \c true if comments are allowed. Default: \c true.
+ bool allowComments_;
+
+ /// \c true if root must be either an array or an object value. Default: \c false.
+ bool strictRoot_;
+ };
+
+} // namespace Json
+
+#endif // CPPTL_JSON_FEATURES_H_INCLUDED
diff --git a/src/blackberry10/native/public/json/forwards.h b/src/blackberry10/native/public/json/forwards.h
new file mode 100644
index 00000000..d0ce8300
--- /dev/null
+++ b/src/blackberry10/native/public/json/forwards.h
@@ -0,0 +1,39 @@
+#ifndef JSON_FORWARDS_H_INCLUDED
+# define JSON_FORWARDS_H_INCLUDED
+
+# include "config.h"
+
+namespace Json {
+
+ // writer.h
+ class FastWriter;
+ class StyledWriter;
+
+ // reader.h
+ class Reader;
+
+ // features.h
+ class Features;
+
+ // value.h
+ typedef int Int;
+ typedef unsigned int UInt;
+ class StaticString;
+ class Path;
+ class PathArgument;
+ class Value;
+ class ValueIteratorBase;
+ class ValueIterator;
+ class ValueConstIterator;
+#ifdef JSON_VALUE_USE_INTERNAL_MAP
+ class ValueAllocator;
+ class ValueMapAllocator;
+ class ValueInternalLink;
+ class ValueInternalArray;
+ class ValueInternalMap;
+#endif // #ifdef JSON_VALUE_USE_INTERNAL_MAP
+
+} // namespace Json
+
+
+#endif // JSON_FORWARDS_H_INCLUDED
diff --git a/src/blackberry10/native/public/json/json.h b/src/blackberry10/native/public/json/json.h
new file mode 100644
index 00000000..c71ed65a
--- /dev/null
+++ b/src/blackberry10/native/public/json/json.h
@@ -0,0 +1,10 @@
+#ifndef JSON_JSON_H_INCLUDED
+# define JSON_JSON_H_INCLUDED
+
+# include "autolink.h"
+# include "value.h"
+# include "reader.h"
+# include "writer.h"
+# include "features.h"
+
+#endif // JSON_JSON_H_INCLUDED
diff --git a/src/blackberry10/native/public/json/reader.h b/src/blackberry10/native/public/json/reader.h
new file mode 100644
index 00000000..ee1d6a24
--- /dev/null
+++ b/src/blackberry10/native/public/json/reader.h
@@ -0,0 +1,196 @@
+#ifndef CPPTL_JSON_READER_H_INCLUDED
+# define CPPTL_JSON_READER_H_INCLUDED
+
+# include "features.h"
+# include "value.h"
+# include
+# include
+# include
+# include
+
+namespace Json {
+
+ /** \brief Unserialize a JSON document into a Value.
+ *
+ */
+ class JSON_API Reader
+ {
+ public:
+ typedef char Char;
+ typedef const Char *Location;
+
+ /** \brief Constructs a Reader allowing all features
+ * for parsing.
+ */
+ Reader();
+
+ /** \brief Constructs a Reader allowing the specified feature set
+ * for parsing.
+ */
+ Reader( const Features &features );
+
+ /** \brief Read a Value from a JSON document.
+ * \param document UTF-8 encoded string containing the document to read.
+ * \param root [out] Contains the root value of the document if it was
+ * successfully parsed.
+ * \param collectComments \c true to collect comment and allow writing them back during
+ * serialization, \c false to discard comments.
+ * This parameter is ignored if Features::allowComments_
+ * is \c false.
+ * \return \c true if the document was successfully parsed, \c false if an error occurred.
+ */
+ bool parse( const std::string &document,
+ Value &root,
+ bool collectComments = true );
+
+ /** \brief Read a Value from a JSON document.
+ * \param document UTF-8 encoded string containing the document to read.
+ * \param root [out] Contains the root value of the document if it was
+ * successfully parsed.
+ * \param collectComments \c true to collect comment and allow writing them back during
+ * serialization, \c false to discard comments.
+ * This parameter is ignored if Features::allowComments_
+ * is \c false.
+ * \return \c true if the document was successfully parsed, \c false if an error occurred.
+ */
+ bool parse( const char *beginDoc, const char *endDoc,
+ Value &root,
+ bool collectComments = true );
+
+ /// \brief Parse from input stream.
+ /// \see Json::operator>>(std::istream&, Json::Value&).
+ bool parse( std::istream &is,
+ Value &root,
+ bool collectComments = true );
+
+ /** \brief Returns a user friendly string that list errors in the parsed document.
+ * \return Formatted error message with the list of errors with their location in
+ * the parsed document. An empty string is returned if no error occurred
+ * during parsing.
+ */
+ std::string getFormatedErrorMessages() const;
+
+ private:
+ enum TokenType
+ {
+ tokenEndOfStream = 0,
+ tokenObjectBegin,
+ tokenObjectEnd,
+ tokenArrayBegin,
+ tokenArrayEnd,
+ tokenString,
+ tokenNumber,
+ tokenTrue,
+ tokenFalse,
+ tokenNull,
+ tokenArraySeparator,
+ tokenMemberSeparator,
+ tokenComment,
+ tokenError
+ };
+
+ class Token
+ {
+ public:
+ TokenType type_;
+ Location start_;
+ Location end_;
+ };
+
+ class ErrorInfo
+ {
+ public:
+ Token token_;
+ std::string message_;
+ Location extra_;
+ };
+
+ typedef std::deque Errors;
+
+ bool expectToken( TokenType type, Token &token, const char *message );
+ bool readToken( Token &token );
+ void skipSpaces();
+ bool match( Location pattern,
+ int patternLength );
+ bool readComment();
+ bool readCStyleComment();
+ bool readCppStyleComment();
+ bool readString();
+ void readNumber();
+ bool readValue();
+ bool readObject( Token &token );
+ bool readArray( Token &token );
+ bool decodeNumber( Token &token );
+ bool decodeString( Token &token );
+ bool decodeString( Token &token, std::string &decoded );
+ bool decodeDouble( Token &token );
+ bool decodeUnicodeCodePoint( Token &token,
+ Location ¤t,
+ Location end,
+ unsigned int &unicode );
+ bool decodeUnicodeEscapeSequence( Token &token,
+ Location ¤t,
+ Location end,
+ unsigned int &unicode );
+ bool addError( const std::string &message,
+ Token &token,
+ Location extra = 0 );
+ bool recoverFromError( TokenType skipUntilToken );
+ bool addErrorAndRecover( const std::string &message,
+ Token &token,
+ TokenType skipUntilToken );
+ void skipUntilSpace();
+ Value ¤tValue();
+ Char getNextChar();
+ void getLocationLineAndColumn( Location location,
+ int &line,
+ int &column ) const;
+ std::string getLocationLineAndColumn( Location location ) const;
+ void addComment( Location begin,
+ Location end,
+ CommentPlacement placement );
+ void skipCommentTokens( Token &token );
+
+ typedef std::stack Nodes;
+ Nodes nodes_;
+ Errors errors_;
+ std::string document_;
+ Location begin_;
+ Location end_;
+ Location current_;
+ Location lastValueEnd_;
+ Value *lastValue_;
+ std::string commentsBefore_;
+ Features features_;
+ bool collectComments_;
+ };
+
+ /** \brief Read from 'sin' into 'root'.
+
+ Always keep comments from the input JSON.
+
+ This can be used to read a file into a particular sub-object.
+ For example:
+ \code
+ Json::Value root;
+ cin >> root["dir"]["file"];
+ cout << root;
+ \endcode
+ Result:
+ \verbatim
+ {
+ "dir": {
+ "file": {
+ // The input stream JSON would be nested here.
+ }
+ }
+ }
+ \endverbatim
+ \throw std::exception on parse error.
+ \see Json::operator<<()
+ */
+ std::istream& operator>>( std::istream&, Value& );
+
+} // namespace Json
+
+#endif // CPPTL_JSON_READER_H_INCLUDED
diff --git a/src/blackberry10/native/public/json/value.h b/src/blackberry10/native/public/json/value.h
new file mode 100644
index 00000000..58bfd88e
--- /dev/null
+++ b/src/blackberry10/native/public/json/value.h
@@ -0,0 +1,1069 @@
+#ifndef CPPTL_JSON_H_INCLUDED
+# define CPPTL_JSON_H_INCLUDED
+
+# include "forwards.h"
+# include
+# include
+
+# ifndef JSON_USE_CPPTL_SMALLMAP
+# include
+# else
+# include
+# endif
+# ifdef JSON_USE_CPPTL
+# include
+# endif
+
+/** \brief JSON (JavaScript Object Notation).
+ */
+namespace Json {
+
+ /** \brief Type of the value held by a Value object.
+ */
+ enum ValueType
+ {
+ nullValue = 0, ///< 'null' value
+ intValue, ///< signed integer value
+ uintValue, ///< unsigned integer value
+ realValue, ///< double value
+ stringValue, ///< UTF-8 string value
+ booleanValue, ///< bool value
+ arrayValue, ///< array value (ordered list)
+ objectValue ///< object value (collection of name/value pairs).
+ };
+
+ enum CommentPlacement
+ {
+ commentBefore = 0, ///< a comment placed on the line before a value
+ commentAfterOnSameLine, ///< a comment just after a value on the same line
+ commentAfter, ///< a comment on the line after a value (only make sense for root value)
+ numberOfCommentPlacement
+ };
+
+//# ifdef JSON_USE_CPPTL
+// typedef CppTL::AnyEnumerator EnumMemberNames;
+// typedef CppTL::AnyEnumerator EnumValues;
+//# endif
+
+ /** \brief Lightweight wrapper to tag static string.
+ *
+ * Value constructor and objectValue member assignement takes advantage of the
+ * StaticString and avoid the cost of string duplication when storing the
+ * string or the member name.
+ *
+ * Example of usage:
+ * \code
+ * Json::Value aValue( StaticString("some text") );
+ * Json::Value object;
+ * static const StaticString code("code");
+ * object[code] = 1234;
+ * \endcode
+ */
+ class JSON_API StaticString
+ {
+ public:
+ explicit StaticString( const char *czstring )
+ : str_( czstring )
+ {
+ }
+
+ operator const char *() const
+ {
+ return str_;
+ }
+
+ const char *c_str() const
+ {
+ return str_;
+ }
+
+ private:
+ const char *str_;
+ };
+
+ /** \brief Represents a JSON value.
+ *
+ * This class is a discriminated union wrapper that can represents a:
+ * - signed integer [range: Value::minInt - Value::maxInt]
+ * - unsigned integer (range: 0 - Value::maxUInt)
+ * - double
+ * - UTF-8 string
+ * - boolean
+ * - 'null'
+ * - an ordered list of Value
+ * - collection of name/value pairs (javascript object)
+ *
+ * The type of the held value is represented by a #ValueType and
+ * can be obtained using type().
+ *
+ * values of an #objectValue or #arrayValue can be accessed using operator[]() methods.
+ * Non const methods will automatically create the a #nullValue element
+ * if it does not exist.
+ * The sequence of an #arrayValue will be automatically resize and initialized
+ * with #nullValue. resize() can be used to enlarge or truncate an #arrayValue.
+ *
+ * The get() methods can be used to obtanis default value in the case the required element
+ * does not exist.
+ *
+ * It is possible to iterate over the list of a #objectValue values using
+ * the getMemberNames() method.
+ */
+ class JSON_API Value
+ {
+ friend class ValueIteratorBase;
+# ifdef JSON_VALUE_USE_INTERNAL_MAP
+ friend class ValueInternalLink;
+ friend class ValueInternalMap;
+# endif
+ public:
+ typedef std::vector Members;
+ typedef ValueIterator iterator;
+ typedef ValueConstIterator const_iterator;
+ typedef Json::UInt UInt;
+ typedef Json::Int Int;
+ typedef UInt ArrayIndex;
+
+ static const Value null;
+ static const Int minInt;
+ static const Int maxInt;
+ static const UInt maxUInt;
+
+ private:
+#ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION
+# ifndef JSON_VALUE_USE_INTERNAL_MAP
+ class CZString
+ {
+ public:
+ enum DuplicationPolicy
+ {
+ noDuplication = 0,
+ duplicate,
+ duplicateOnCopy
+ };
+ CZString( int index );
+ CZString( const char *cstr, DuplicationPolicy allocate );
+ CZString( const CZString &other );
+ ~CZString();
+ CZString &operator =( const CZString &other );
+ bool operator<( const CZString &other ) const;
+ bool operator==( const CZString &other ) const;
+ int index() const;
+ const char *c_str() const;
+ bool isStaticString() const;
+ private:
+ void swap( CZString &other );
+ const char *cstr_;
+ int index_;
+ };
+
+ public:
+# ifndef JSON_USE_CPPTL_SMALLMAP
+ typedef std::map ObjectValues;
+# else
+ typedef CppTL::SmallMap ObjectValues;
+# endif // ifndef JSON_USE_CPPTL_SMALLMAP
+# endif // ifndef JSON_VALUE_USE_INTERNAL_MAP
+#endif // ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION
+
+ public:
+ /** \brief Create a default Value of the given type.
+
+ This is a very useful constructor.
+ To create an empty array, pass arrayValue.
+ To create an empty object, pass objectValue.
+ Another Value can then be set to this one by assignment.
+ This is useful since clear() and resize() will not alter types.
+
+ Examples:
+ \code
+ Json::Value null_value; // null
+ Json::Value arr_value(Json::arrayValue); // []
+ Json::Value obj_value(Json::objectValue); // {}
+ \endcode
+ */
+ Value( ValueType type = nullValue );
+ Value( Int value );
+ Value( UInt value );
+ Value( double value );
+ Value( const char *value );
+ Value( const char *beginValue, const char *endValue );
+ /** \brief Constructs a value from a static string.
+
+ * Like other value string constructor but do not duplicate the string for
+ * internal storage. The given string must remain alive after the call to this
+ * constructor.
+ * Example of usage:
+ * \code
+ * Json::Value aValue( StaticString("some text") );
+ * \endcode
+ */
+ Value( const StaticString &value );
+ Value( const std::string &value );
+# ifdef JSON_USE_CPPTL
+ Value( const CppTL::ConstString &value );
+# endif
+ Value( bool value );
+ Value( const Value &other );
+ ~Value();
+
+ Value &operator=( const Value &other );
+ /// Swap values.
+ /// \note Currently, comments are intentionally not swapped, for
+ /// both logic and efficiency.
+ void swap( Value &other );
+
+ ValueType type() const;
+
+ bool operator <( const Value &other ) const;
+ bool operator <=( const Value &other ) const;
+ bool operator >=( const Value &other ) const;
+ bool operator >( const Value &other ) const;
+
+ bool operator ==( const Value &other ) const;
+ bool operator !=( const Value &other ) const;
+
+ int compare( const Value &other );
+
+ const char *asCString() const;
+ std::string asString() const;
+# ifdef JSON_USE_CPPTL
+ CppTL::ConstString asConstString() const;
+# endif
+ Int asInt() const;
+ UInt asUInt() const;
+ double asDouble() const;
+ bool asBool() const;
+
+ bool isNull() const;
+ bool isBool() const;
+ bool isInt() const;
+ bool isUInt() const;
+ bool isIntegral() const;
+ bool isDouble() const;
+ bool isNumeric() const;
+ bool isString() const;
+ bool isArray() const;
+ bool isObject() const;
+
+ bool isConvertibleTo( ValueType other ) const;
+
+ /// Number of values in array or object
+ UInt size() const;
+
+ /// \brief Return true if empty array, empty object, or null;
+ /// otherwise, false.
+ bool empty() const;
+
+ /// Return isNull()
+ bool operator!() const;
+
+ /// Remove all object members and array elements.
+ /// \pre type() is arrayValue, objectValue, or nullValue
+ /// \post type() is unchanged
+ void clear();
+
+ /// Resize the array to size elements.
+ /// New elements are initialized to null.
+ /// May only be called on nullValue or arrayValue.
+ /// \pre type() is arrayValue or nullValue
+ /// \post type() is arrayValue
+ void resize( UInt size );
+
+ /// Access an array element (zero based index ).
+ /// If the array contains less than index element, then null value are inserted
+ /// in the array so that its size is index+1.
+ /// (You may need to say 'value[0u]' to get your compiler to distinguish
+ /// this from the operator[] which takes a string.)
+ Value &operator[]( UInt index );
+ /// Access an array element (zero based index )
+ /// (You may need to say 'value[0u]' to get your compiler to distinguish
+ /// this from the operator[] which takes a string.)
+ const Value &operator[]( UInt index ) const;
+ /// If the array contains at least index+1 elements, returns the element value,
+ /// otherwise returns defaultValue.
+ Value get( UInt index,
+ const Value &defaultValue ) const;
+ /// Return true if index < size().
+ bool isValidIndex( UInt index ) const;
+ /// \brief Append value to array at the end.
+ ///
+ /// Equivalent to jsonvalue[jsonvalue.size()] = value;
+ Value &append( const Value &value );
+
+ /// Access an object value by name, create a null member if it does not exist.
+ Value &operator[]( const char *key );
+ /// Access an object value by name, returns null if there is no member with that name.
+ const Value &operator[]( const char *key ) const;
+ /// Access an object value by name, create a null member if it does not exist.
+ Value &operator[]( const std::string &key );
+ /// Access an object value by name, returns null if there is no member with that name.
+ const Value &operator[]( const std::string &key ) const;
+ /** \brief Access an object value by name, create a null member if it does not exist.
+
+ * If the object as no entry for that name, then the member name used to store
+ * the new entry is not duplicated.
+ * Example of use:
+ * \code
+ * Json::Value object;
+ * static const StaticString code("code");
+ * object[code] = 1234;
+ * \endcode
+ */
+ Value &operator[]( const StaticString &key );
+# ifdef JSON_USE_CPPTL
+ /// Access an object value by name, create a null member if it does not exist.
+ Value &operator[]( const CppTL::ConstString &key );
+ /// Access an object value by name, returns null if there is no member with that name.
+ const Value &operator[]( const CppTL::ConstString &key ) const;
+# endif
+ /// Return the member named key if it exist, defaultValue otherwise.
+ Value get( const char *key,
+ const Value &defaultValue ) const;
+ /// Return the member named key if it exist, defaultValue otherwise.
+ Value get( const std::string &key,
+ const Value &defaultValue ) const;
+# ifdef JSON_USE_CPPTL
+ /// Return the member named key if it exist, defaultValue otherwise.
+ Value get( const CppTL::ConstString &key,
+ const Value &defaultValue ) const;
+# endif
+ /// \brief Remove and return the named member.
+ ///
+ /// Do nothing if it did not exist.
+ /// \return the removed Value, or null.
+ /// \pre type() is objectValue or nullValue
+ /// \post type() is unchanged
+ Value removeMember( const char* key );
+ /// Same as removeMember(const char*)
+ Value removeMember( const std::string &key );
+
+ /// Return true if the object has a member named key.
+ bool isMember( const char *key ) const;
+ /// Return true if the object has a member named key.
+ bool isMember( const std::string &key ) const;
+# ifdef JSON_USE_CPPTL
+ /// Return true if the object has a member named key.
+ bool isMember( const CppTL::ConstString &key ) const;
+# endif
+
+ /// \brief Return a list of the member names.
+ ///
+ /// If null, return an empty list.
+ /// \pre type() is objectValue or nullValue
+ /// \post if type() was nullValue, it remains nullValue
+ Members getMemberNames() const;
+
+//# ifdef JSON_USE_CPPTL
+// EnumMemberNames enumMemberNames() const;
+// EnumValues enumValues() const;
+//# endif
+
+ /// Comments must be //... or /* ... */
+ void setComment( const char *comment,
+ CommentPlacement placement );
+ /// Comments must be //... or /* ... */
+ void setComment( const std::string &comment,
+ CommentPlacement placement );
+ bool hasComment( CommentPlacement placement ) const;
+ /// Include delimiters and embedded newlines.
+ std::string getComment( CommentPlacement placement ) const;
+
+ std::string toStyledString() const;
+
+ const_iterator begin() const;
+ const_iterator end() const;
+
+ iterator begin();
+ iterator end();
+
+ private:
+ Value &resolveReference( const char *key,
+ bool isStatic );
+
+# ifdef JSON_VALUE_USE_INTERNAL_MAP
+ inline bool isItemAvailable() const
+ {
+ return itemIsUsed_ == 0;
+ }
+
+ inline void setItemUsed( bool isUsed = true )
+ {
+ itemIsUsed_ = isUsed ? 1 : 0;
+ }
+
+ inline bool isMemberNameStatic() const
+ {
+ return memberNameIsStatic_ == 0;
+ }
+
+ inline void setMemberNameIsStatic( bool isStatic )
+ {
+ memberNameIsStatic_ = isStatic ? 1 : 0;
+ }
+# endif // # ifdef JSON_VALUE_USE_INTERNAL_MAP
+
+ private:
+ struct CommentInfo
+ {
+ CommentInfo();
+ ~CommentInfo();
+
+ void setComment( const char *text );
+
+ char *comment_;
+ };
+
+ //struct MemberNamesTransform
+ //{
+ // typedef const char *result_type;
+ // const char *operator()( const CZString &name ) const
+ // {
+ // return name.c_str();
+ // }
+ //};
+
+ union ValueHolder
+ {
+ Int int_;
+ UInt uint_;
+ double real_;
+ bool bool_;
+ char *string_;
+# ifdef JSON_VALUE_USE_INTERNAL_MAP
+ ValueInternalArray *array_;
+ ValueInternalMap *map_;
+#else
+ ObjectValues *map_;
+# endif
+ } value_;
+ ValueType type_ : 8;
+ int allocated_ : 1; // Notes: if declared as bool, bitfield is useless.
+# ifdef JSON_VALUE_USE_INTERNAL_MAP
+ unsigned int itemIsUsed_ : 1; // used by the ValueInternalMap container.
+ int memberNameIsStatic_ : 1; // used by the ValueInternalMap container.
+# endif
+ CommentInfo *comments_;
+ };
+
+
+ /** \brief Experimental and untested: represents an element of the "path" to access a node.
+ */
+ class PathArgument
+ {
+ public:
+ friend class Path;
+
+ PathArgument();
+ PathArgument( UInt index );
+ PathArgument( const char *key );
+ PathArgument( const std::string &key );
+
+ private:
+ enum Kind
+ {
+ kindNone = 0,
+ kindIndex,
+ kindKey
+ };
+ std::string key_;
+ UInt index_;
+ Kind kind_;
+ };
+
+ /** \brief Experimental and untested: represents a "path" to access a node.
+ *
+ * Syntax:
+ * - "." => root node
+ * - ".[n]" => elements at index 'n' of root node (an array value)
+ * - ".name" => member named 'name' of root node (an object value)
+ * - ".name1.name2.name3"
+ * - ".[0][1][2].name1[3]"
+ * - ".%" => member name is provided as parameter
+ * - ".[%]" => index is provied as parameter
+ */
+ class Path
+ {
+ public:
+ Path( const std::string &path,
+ const PathArgument &a1 = PathArgument(),
+ const PathArgument &a2 = PathArgument(),
+ const PathArgument &a3 = PathArgument(),
+ const PathArgument &a4 = PathArgument(),
+ const PathArgument &a5 = PathArgument() );
+
+ const Value &resolve( const Value &root ) const;
+ Value resolve( const Value &root,
+ const Value &defaultValue ) const;
+ /// Creates the "path" to access the specified node and returns a reference on the node.
+ Value &make( Value &root ) const;
+
+ private:
+ typedef std::vector InArgs;
+ typedef std::vector Args;
+
+ void makePath( const std::string &path,
+ const InArgs &in );
+ void addPathInArg( const std::string &path,
+ const InArgs &in,
+ InArgs::const_iterator &itInArg,
+ PathArgument::Kind kind );
+ void invalidPath( const std::string &path,
+ int location );
+
+ Args args_;
+ };
+
+ /** \brief Experimental do not use: Allocator to customize member name and string value memory management done by Value.
+ *
+ * - makeMemberName() and releaseMemberName() are called to respectively duplicate and
+ * free an Json::objectValue member name.
+ * - duplicateStringValue() and releaseStringValue() are called similarly to
+ * duplicate and free a Json::stringValue value.
+ */
+ class ValueAllocator
+ {
+ public:
+ enum { unknown = (unsigned)-1 };
+
+ virtual ~ValueAllocator();
+
+ virtual char *makeMemberName( const char *memberName ) = 0;
+ virtual void releaseMemberName( char *memberName ) = 0;
+ virtual char *duplicateStringValue( const char *value,
+ unsigned int length = unknown ) = 0;
+ virtual void releaseStringValue( char *value ) = 0;
+ };
+
+#ifdef JSON_VALUE_USE_INTERNAL_MAP
+ /** \brief Allocator to customize Value internal map.
+ * Below is an example of a simple implementation (default implementation actually
+ * use memory pool for speed).
+ * \code
+ class DefaultValueMapAllocator : public ValueMapAllocator
+ {
+ public: // overridden from ValueMapAllocator
+ virtual ValueInternalMap *newMap()
+ {
+ return new ValueInternalMap();
+ }
+
+ virtual ValueInternalMap *newMapCopy( const ValueInternalMap &other )
+ {
+ return new ValueInternalMap( other );
+ }
+
+ virtual void destructMap( ValueInternalMap *map )
+ {
+ delete map;
+ }
+
+ virtual ValueInternalLink *allocateMapBuckets( unsigned int size )
+ {
+ return new ValueInternalLink[size];
+ }
+
+ virtual void releaseMapBuckets( ValueInternalLink *links )
+ {
+ delete [] links;
+ }
+
+ virtual ValueInternalLink *allocateMapLink()
+ {
+ return new ValueInternalLink();
+ }
+
+ virtual void releaseMapLink( ValueInternalLink *link )
+ {
+ delete link;
+ }
+ };
+ * \endcode
+ */
+ class JSON_API ValueMapAllocator
+ {
+ public:
+ virtual ~ValueMapAllocator();
+ virtual ValueInternalMap *newMap() = 0;
+ virtual ValueInternalMap *newMapCopy( const ValueInternalMap &other ) = 0;
+ virtual void destructMap( ValueInternalMap *map ) = 0;
+ virtual ValueInternalLink *allocateMapBuckets( unsigned int size ) = 0;
+ virtual void releaseMapBuckets( ValueInternalLink *links ) = 0;
+ virtual ValueInternalLink *allocateMapLink() = 0;
+ virtual void releaseMapLink( ValueInternalLink *link ) = 0;
+ };
+
+ /** \brief ValueInternalMap hash-map bucket chain link (for internal use only).
+ * \internal previous_ & next_ allows for bidirectional traversal.
+ */
+ class JSON_API ValueInternalLink
+ {
+ public:
+ enum { itemPerLink = 6 }; // sizeof(ValueInternalLink) = 128 on 32 bits architecture.
+ enum InternalFlags {
+ flagAvailable = 0,
+ flagUsed = 1
+ };
+
+ ValueInternalLink();
+
+ ~ValueInternalLink();
+
+ Value items_[itemPerLink];
+ char *keys_[itemPerLink];
+ ValueInternalLink *previous_;
+ ValueInternalLink *next_;
+ };
+
+
+ /** \brief A linked page based hash-table implementation used internally by Value.
+ * \internal ValueInternalMap is a tradional bucket based hash-table, with a linked
+ * list in each bucket to handle collision. There is an addional twist in that
+ * each node of the collision linked list is a page containing a fixed amount of
+ * value. This provides a better compromise between memory usage and speed.
+ *
+ * Each bucket is made up of a chained list of ValueInternalLink. The last
+ * link of a given bucket can be found in the 'previous_' field of the following bucket.
+ * The last link of the last bucket is stored in tailLink_ as it has no following bucket.
+ * Only the last link of a bucket may contains 'available' item. The last link always
+ * contains at least one element unless is it the bucket one very first link.
+ */
+ class JSON_API ValueInternalMap
+ {
+ friend class ValueIteratorBase;
+ friend class Value;
+ public:
+ typedef unsigned int HashKey;
+ typedef unsigned int BucketIndex;
+
+# ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION
+ struct IteratorState
+ {
+ IteratorState()
+ : map_(0)
+ , link_(0)
+ , itemIndex_(0)
+ , bucketIndex_(0)
+ {
+ }
+ ValueInternalMap *map_;
+ ValueInternalLink *link_;
+ BucketIndex itemIndex_;
+ BucketIndex bucketIndex_;
+ };
+# endif // ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION
+
+ ValueInternalMap();
+ ValueInternalMap( const ValueInternalMap &other );
+ ValueInternalMap &operator =( const ValueInternalMap &other );
+ ~ValueInternalMap();
+
+ void swap( ValueInternalMap &other );
+
+ BucketIndex size() const;
+
+ void clear();
+
+ bool reserveDelta( BucketIndex growth );
+
+ bool reserve( BucketIndex newItemCount );
+
+ const Value *find( const char *key ) const;
+
+ Value *find( const char *key );
+
+ Value &resolveReference( const char *key,
+ bool isStatic );
+
+ void remove( const char *key );
+
+ void doActualRemove( ValueInternalLink *link,
+ BucketIndex index,
+ BucketIndex bucketIndex );
+
+ ValueInternalLink *&getLastLinkInBucket( BucketIndex bucketIndex );
+
+ Value &setNewItem( const char *key,
+ bool isStatic,
+ ValueInternalLink *link,
+ BucketIndex index );
+
+ Value &unsafeAdd( const char *key,
+ bool isStatic,
+ HashKey hashedKey );
+
+ HashKey hash( const char *key ) const;
+
+ int compare( const ValueInternalMap &other ) const;
+
+ private:
+ void makeBeginIterator( IteratorState &it ) const;
+ void makeEndIterator( IteratorState &it ) const;
+ static bool equals( const IteratorState &x, const IteratorState &other );
+ static void increment( IteratorState &iterator );
+ static void incrementBucket( IteratorState &iterator );
+ static void decrement( IteratorState &iterator );
+ static const char *key( const IteratorState &iterator );
+ static const char *key( const IteratorState &iterator, bool &isStatic );
+ static Value &value( const IteratorState &iterator );
+ static int distance( const IteratorState &x, const IteratorState &y );
+
+ private:
+ ValueInternalLink *buckets_;
+ ValueInternalLink *tailLink_;
+ BucketIndex bucketsSize_;
+ BucketIndex itemCount_;
+ };
+
+ /** \brief A simplified deque implementation used internally by Value.
+ * \internal
+ * It is based on a list of fixed "page", each page contains a fixed number of items.
+ * Instead of using a linked-list, a array of pointer is used for fast item look-up.
+ * Look-up for an element is as follow:
+ * - compute page index: pageIndex = itemIndex / itemsPerPage
+ * - look-up item in page: pages_[pageIndex][itemIndex % itemsPerPage]
+ *
+ * Insertion is amortized constant time (only the array containing the index of pointers
+ * need to be reallocated when items are appended).
+ */
+ class JSON_API ValueInternalArray
+ {
+ friend class Value;
+ friend class ValueIteratorBase;
+ public:
+ enum { itemsPerPage = 8 }; // should be a power of 2 for fast divide and modulo.
+ typedef Value::ArrayIndex ArrayIndex;
+ typedef unsigned int PageIndex;
+
+# ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION
+ struct IteratorState // Must be a POD
+ {
+ IteratorState()
+ : array_(0)
+ , currentPageIndex_(0)
+ , currentItemIndex_(0)
+ {
+ }
+ ValueInternalArray *array_;
+ Value **currentPageIndex_;
+ unsigned int currentItemIndex_;
+ };
+# endif // ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION
+
+ ValueInternalArray();
+ ValueInternalArray( const ValueInternalArray &other );
+ ValueInternalArray &operator =( const ValueInternalArray &other );
+ ~ValueInternalArray();
+ void swap( ValueInternalArray &other );
+
+ void clear();
+ void resize( ArrayIndex newSize );
+
+ Value &resolveReference( ArrayIndex index );
+
+ Value *find( ArrayIndex index ) const;
+
+ ArrayIndex size() const;
+
+ int compare( const ValueInternalArray &other ) const;
+
+ private:
+ static bool equals( const IteratorState &x, const IteratorState &other );
+ static void increment( IteratorState &iterator );
+ static void decrement( IteratorState &iterator );
+ static Value &dereference( const IteratorState &iterator );
+ static Value &unsafeDereference( const IteratorState &iterator );
+ static int distance( const IteratorState &x, const IteratorState &y );
+ static ArrayIndex indexOf( const IteratorState &iterator );
+ void makeBeginIterator( IteratorState &it ) const;
+ void makeEndIterator( IteratorState &it ) const;
+ void makeIterator( IteratorState &it, ArrayIndex index ) const;
+
+ void makeIndexValid( ArrayIndex index );
+
+ Value **pages_;
+ ArrayIndex size_;
+ PageIndex pageCount_;
+ };
+
+ /** \brief Experimental: do not use. Allocator to customize Value internal array.
+ * Below is an example of a simple implementation (actual implementation use
+ * memory pool).
+ \code
+class DefaultValueArrayAllocator : public ValueArrayAllocator
+{
+public: // overridden from ValueArrayAllocator
+ virtual ~DefaultValueArrayAllocator()
+ {
+ }
+
+ virtual ValueInternalArray *newArray()
+ {
+ return new ValueInternalArray();
+ }
+
+ virtual ValueInternalArray *newArrayCopy( const ValueInternalArray &other )
+ {
+ return new ValueInternalArray( other );
+ }
+
+ virtual void destruct( ValueInternalArray *array )
+ {
+ delete array;
+ }
+
+ virtual void reallocateArrayPageIndex( Value **&indexes,
+ ValueInternalArray::PageIndex &indexCount,
+ ValueInternalArray::PageIndex minNewIndexCount )
+ {
+ ValueInternalArray::PageIndex newIndexCount = (indexCount*3)/2 + 1;
+ if ( minNewIndexCount > newIndexCount )
+ newIndexCount = minNewIndexCount;
+ void *newIndexes = realloc( indexes, sizeof(Value*) * newIndexCount );
+ if ( !newIndexes )
+ throw std::bad_alloc();
+ indexCount = newIndexCount;
+ indexes = static_cast( newIndexes );
+ }
+ virtual void releaseArrayPageIndex( Value **indexes,
+ ValueInternalArray::PageIndex indexCount )
+ {
+ if ( indexes )
+ free( indexes );
+ }
+
+ virtual Value *allocateArrayPage()
+ {
+ return static_cast( malloc( sizeof(Value) * ValueInternalArray::itemsPerPage ) );
+ }
+
+ virtual void releaseArrayPage( Value *value )
+ {
+ if ( value )
+ free( value );
+ }
+};
+ \endcode
+ */
+ class JSON_API ValueArrayAllocator
+ {
+ public:
+ virtual ~ValueArrayAllocator();
+ virtual ValueInternalArray *newArray() = 0;
+ virtual ValueInternalArray *newArrayCopy( const ValueInternalArray &other ) = 0;
+ virtual void destructArray( ValueInternalArray *array ) = 0;
+ /** \brief Reallocate array page index.
+ * Reallocates an array of pointer on each page.
+ * \param indexes [input] pointer on the current index. May be \c NULL.
+ * [output] pointer on the new index of at least
+ * \a minNewIndexCount pages.
+ * \param indexCount [input] current number of pages in the index.
+ * [output] number of page the reallocated index can handle.
+ * \b MUST be >= \a minNewIndexCount.
+ * \param minNewIndexCount Minimum number of page the new index must be able to
+ * handle.
+ */
+ virtual void reallocateArrayPageIndex( Value **&indexes,
+ ValueInternalArray::PageIndex &indexCount,
+ ValueInternalArray::PageIndex minNewIndexCount ) = 0;
+ virtual void releaseArrayPageIndex( Value **indexes,
+ ValueInternalArray::PageIndex indexCount ) = 0;
+ virtual Value *allocateArrayPage() = 0;
+ virtual void releaseArrayPage( Value *value ) = 0;
+ };
+#endif // #ifdef JSON_VALUE_USE_INTERNAL_MAP
+
+
+ /** \brief base class for Value iterators.
+ *
+ */
+ class ValueIteratorBase
+ {
+ public:
+ typedef unsigned int size_t;
+ typedef int difference_type;
+ typedef ValueIteratorBase SelfType;
+
+ ValueIteratorBase();
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+ explicit ValueIteratorBase( const Value::ObjectValues::iterator ¤t );
+#else
+ ValueIteratorBase( const ValueInternalArray::IteratorState &state );
+ ValueIteratorBase( const ValueInternalMap::IteratorState &state );
+#endif
+
+ bool operator ==( const SelfType &other ) const
+ {
+ return isEqual( other );
+ }
+
+ bool operator !=( const SelfType &other ) const
+ {
+ return !isEqual( other );
+ }
+
+ difference_type operator -( const SelfType &other ) const
+ {
+ return computeDistance( other );
+ }
+
+ /// Return either the index or the member name of the referenced value as a Value.
+ Value key() const;
+
+ /// Return the index of the referenced Value. -1 if it is not an arrayValue.
+ UInt index() const;
+
+ /// Return the member name of the referenced Value. "" if it is not an objectValue.
+ const char *memberName() const;
+
+ protected:
+ Value &deref() const;
+
+ void increment();
+
+ void decrement();
+
+ difference_type computeDistance( const SelfType &other ) const;
+
+ bool isEqual( const SelfType &other ) const;
+
+ void copy( const SelfType &other );
+
+ private:
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+ Value::ObjectValues::iterator current_;
+ // Indicates that iterator is for a null value.
+ bool isNull_;
+#else
+ union
+ {
+ ValueInternalArray::IteratorState array_;
+ ValueInternalMap::IteratorState map_;
+ } iterator_;
+ bool isArray_;
+#endif
+ };
+
+ /** \brief const iterator for object and array value.
+ *
+ */
+ class ValueConstIterator : public ValueIteratorBase
+ {
+ friend class Value;
+ public:
+ typedef unsigned int size_t;
+ typedef int difference_type;
+ typedef const Value &reference;
+ typedef const Value *pointer;
+ typedef ValueConstIterator SelfType;
+
+ ValueConstIterator();
+ private:
+ /*! \internal Use by Value to create an iterator.
+ */
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+ explicit ValueConstIterator( const Value::ObjectValues::iterator ¤t );
+#else
+ ValueConstIterator( const ValueInternalArray::IteratorState &state );
+ ValueConstIterator( const ValueInternalMap::IteratorState &state );
+#endif
+ public:
+ SelfType &operator =( const ValueIteratorBase &other );
+
+ SelfType operator++( int )
+ {
+ SelfType temp( *this );
+ ++*this;
+ return temp;
+ }
+
+ SelfType operator--( int )
+ {
+ SelfType temp( *this );
+ --*this;
+ return temp;
+ }
+
+ SelfType &operator--()
+ {
+ decrement();
+ return *this;
+ }
+
+ SelfType &operator++()
+ {
+ increment();
+ return *this;
+ }
+
+ reference operator *() const
+ {
+ return deref();
+ }
+ };
+
+
+ /** \brief Iterator for object and array value.
+ */
+ class ValueIterator : public ValueIteratorBase
+ {
+ friend class Value;
+ public:
+ typedef unsigned int size_t;
+ typedef int difference_type;
+ typedef Value &reference;
+ typedef Value *pointer;
+ typedef ValueIterator SelfType;
+
+ ValueIterator();
+ ValueIterator( const ValueConstIterator &other );
+ ValueIterator( const ValueIterator &other );
+ private:
+ /*! \internal Use by Value to create an iterator.
+ */
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+ explicit ValueIterator( const Value::ObjectValues::iterator ¤t );
+#else
+ ValueIterator( const ValueInternalArray::IteratorState &state );
+ ValueIterator( const ValueInternalMap::IteratorState &state );
+#endif
+ public:
+
+ SelfType &operator =( const SelfType &other );
+
+ SelfType operator++( int )
+ {
+ SelfType temp( *this );
+ ++*this;
+ return temp;
+ }
+
+ SelfType operator--( int )
+ {
+ SelfType temp( *this );
+ --*this;
+ return temp;
+ }
+
+ SelfType &operator--()
+ {
+ decrement();
+ return *this;
+ }
+
+ SelfType &operator++()
+ {
+ increment();
+ return *this;
+ }
+
+ reference operator *() const
+ {
+ return deref();
+ }
+ };
+
+
+} // namespace Json
+
+
+#endif // CPPTL_JSON_H_INCLUDED
diff --git a/src/blackberry10/native/public/json/writer.h b/src/blackberry10/native/public/json/writer.h
new file mode 100644
index 00000000..5f4b83be
--- /dev/null
+++ b/src/blackberry10/native/public/json/writer.h
@@ -0,0 +1,174 @@
+#ifndef JSON_WRITER_H_INCLUDED
+# define JSON_WRITER_H_INCLUDED
+
+# include "value.h"
+# include
+# include
+# include
+
+namespace Json {
+
+ class Value;
+
+ /** \brief Abstract class for writers.
+ */
+ class JSON_API Writer
+ {
+ public:
+ virtual ~Writer();
+
+ virtual std::string write( const Value &root ) = 0;
+ };
+
+ /** \brief Outputs a Value in JSON format without formatting (not human friendly).
+ *
+ * The JSON document is written in a single line. It is not intended for 'human' consumption,
+ * but may be usefull to support feature such as RPC where bandwith is limited.
+ * \sa Reader, Value
+ */
+ class JSON_API FastWriter : public Writer
+ {
+ public:
+ FastWriter();
+ virtual ~FastWriter(){}
+
+ void enableYAMLCompatibility();
+
+ public: // overridden from Writer
+ virtual std::string write( const Value &root );
+
+ private:
+ void writeValue( const Value &value );
+
+ std::string document_;
+ bool yamlCompatiblityEnabled_;
+ };
+
+ /** \brief Writes a Value in JSON format in a human friendly way.
+ *
+ * The rules for line break and indent are as follow:
+ * - Object value:
+ * - if empty then print {} without indent and line break
+ * - if not empty the print '{', line break & indent, print one value per line
+ * and then unindent and line break and print '}'.
+ * - Array value:
+ * - if empty then print [] without indent and line break
+ * - if the array contains no object value, empty array or some other value types,
+ * and all the values fit on one lines, then print the array on a single line.
+ * - otherwise, it the values do not fit on one line, or the array contains
+ * object or non empty array, then print one value per line.
+ *
+ * If the Value have comments then they are outputed according to their #CommentPlacement.
+ *
+ * \sa Reader, Value, Value::setComment()
+ */
+ class JSON_API StyledWriter: public Writer
+ {
+ public:
+ StyledWriter();
+ virtual ~StyledWriter(){}
+
+ public: // overridden from Writer
+ /** \brief Serialize a Value in JSON format.
+ * \param root Value to serialize.
+ * \return String containing the JSON document that represents the root value.
+ */
+ virtual std::string write( const Value &root );
+
+ private:
+ void writeValue( const Value &value );
+ void writeArrayValue( const Value &value );
+ bool isMultineArray( const Value &value );
+ void pushValue( const std::string &value );
+ void writeIndent();
+ void writeWithIndent( const std::string &value );
+ void indent();
+ void unindent();
+ void writeCommentBeforeValue( const Value &root );
+ void writeCommentAfterValueOnSameLine( const Value &root );
+ bool hasCommentForValue( const Value &value );
+ static std::string normalizeEOL( const std::string &text );
+
+ typedef std::vector ChildValues;
+
+ ChildValues childValues_;
+ std::string document_;
+ std::string indentString_;
+ int rightMargin_;
+ int indentSize_;
+ bool addChildValues_;
+ };
+
+ /** \brief Writes a Value in JSON format in a human friendly way,
+ to a stream rather than to a string.
+ *
+ * The rules for line break and indent are as follow:
+ * - Object value:
+ * - if empty then print {} without indent and line break
+ * - if not empty the print '{', line break & indent, print one value per line
+ * and then unindent and line break and print '}'.
+ * - Array value:
+ * - if empty then print [] without indent and line break
+ * - if the array contains no object value, empty array or some other value types,
+ * and all the values fit on one lines, then print the array on a single line.
+ * - otherwise, it the values do not fit on one line, or the array contains
+ * object or non empty array, then print one value per line.
+ *
+ * If the Value have comments then they are outputed according to their #CommentPlacement.
+ *
+ * \param indentation Each level will be indented by this amount extra.
+ * \sa Reader, Value, Value::setComment()
+ */
+ class JSON_API StyledStreamWriter
+ {
+ public:
+ StyledStreamWriter( std::string indentation="\t" );
+ ~StyledStreamWriter(){}
+
+ public:
+ /** \brief Serialize a Value in JSON format.
+ * \param out Stream to write to. (Can be ostringstream, e.g.)
+ * \param root Value to serialize.
+ * \note There is no point in deriving from Writer, since write() should not return a value.
+ */
+ void write( std::ostream &out, const Value &root );
+
+ private:
+ void writeValue( const Value &value );
+ void writeArrayValue( const Value &value );
+ bool isMultineArray( const Value &value );
+ void pushValue( const std::string &value );
+ void writeIndent();
+ void writeWithIndent( const std::string &value );
+ void indent();
+ void unindent();
+ void writeCommentBeforeValue( const Value &root );
+ void writeCommentAfterValueOnSameLine( const Value &root );
+ bool hasCommentForValue( const Value &value );
+ static std::string normalizeEOL( const std::string &text );
+
+ typedef std::vector ChildValues;
+
+ ChildValues childValues_;
+ std::ostream* document_;
+ std::string indentString_;
+ int rightMargin_;
+ std::string indentation_;
+ bool addChildValues_;
+ };
+
+ std::string JSON_API valueToString( Int value );
+ std::string JSON_API valueToString( UInt value );
+ std::string JSON_API valueToString( double value );
+ std::string JSON_API valueToString( bool value );
+ std::string JSON_API valueToQuotedString( const char *value );
+
+ /// \brief Output using the StyledStreamWriter.
+ /// \see Json::operator>>()
+ std::ostream& operator<<( std::ostream&, const Value &root );
+
+} // namespace Json
+
+
+
+#endif // JSON_WRITER_H_INCLUDED
diff --git a/src/blackberry10/native/public/json_batchallocator.h b/src/blackberry10/native/public/json_batchallocator.h
new file mode 100644
index 00000000..87ea5ed8
--- /dev/null
+++ b/src/blackberry10/native/public/json_batchallocator.h
@@ -0,0 +1,125 @@
+#ifndef JSONCPP_BATCHALLOCATOR_H_INCLUDED
+# define JSONCPP_BATCHALLOCATOR_H_INCLUDED
+
+# include
+# include
+
+# ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION
+
+namespace Json {
+
+/* Fast memory allocator.
+ *
+ * This memory allocator allocates memory for a batch of object (specified by
+ * the page size, the number of object in each page).
+ *
+ * It does not allow the destruction of a single object. All the allocated objects
+ * can be destroyed at once. The memory can be either released or reused for future
+ * allocation.
+ *
+ * The in-place new operator must be used to construct the object using the pointer
+ * returned by allocate.
+ */
+template
+class BatchAllocator
+{
+public:
+ typedef AllocatedType Type;
+
+ BatchAllocator( unsigned int objectsPerPage = 255 )
+ : freeHead_( 0 )
+ , objectsPerPage_( objectsPerPage )
+ {
+// printf( "Size: %d => %s\n", sizeof(AllocatedType), typeid(AllocatedType).name() );
+ assert( sizeof(AllocatedType) * objectPerAllocation >= sizeof(AllocatedType *) ); // We must be able to store a slist in the object free space.
+ assert( objectsPerPage >= 16 );
+ batches_ = allocateBatch( 0 ); // allocated a dummy page
+ currentBatch_ = batches_;
+ }
+
+ ~BatchAllocator()
+ {
+ for ( BatchInfo *batch = batches_; batch; )
+ {
+ BatchInfo *nextBatch = batch->next_;
+ free( batch );
+ batch = nextBatch;
+ }
+ }
+
+ /// allocate space for an array of objectPerAllocation object.
+ /// @warning it is the responsability of the caller to call objects constructors.
+ AllocatedType *allocate()
+ {
+ if ( freeHead_ ) // returns node from free list.
+ {
+ AllocatedType *object = freeHead_;
+ freeHead_ = *(AllocatedType **)object;
+ return object;
+ }
+ if ( currentBatch_->used_ == currentBatch_->end_ )
+ {
+ currentBatch_ = currentBatch_->next_;
+ while ( currentBatch_ && currentBatch_->used_ == currentBatch_->end_ )
+ currentBatch_ = currentBatch_->next_;
+
+ if ( !currentBatch_ ) // no free batch found, allocate a new one
+ {
+ currentBatch_ = allocateBatch( objectsPerPage_ );
+ currentBatch_->next_ = batches_; // insert at the head of the list
+ batches_ = currentBatch_;
+ }
+ }
+ AllocatedType *allocated = currentBatch_->used_;
+ currentBatch_->used_ += objectPerAllocation;
+ return allocated;
+ }
+
+ /// Release the object.
+ /// @warning it is the responsability of the caller to actually destruct the object.
+ void release( AllocatedType *object )
+ {
+ assert( object != 0 );
+ *(AllocatedType **)object = freeHead_;
+ freeHead_ = object;
+ }
+
+private:
+ struct BatchInfo
+ {
+ BatchInfo *next_;
+ AllocatedType *used_;
+ AllocatedType *end_;
+ AllocatedType buffer_[objectPerAllocation];
+ };
+
+ // disabled copy constructor and assignement operator.
+ BatchAllocator( const BatchAllocator & );
+ void operator =( const BatchAllocator &);
+
+ static BatchInfo *allocateBatch( unsigned int objectsPerPage )
+ {
+ const unsigned int mallocSize = sizeof(BatchInfo) - sizeof(AllocatedType)* objectPerAllocation
+ + sizeof(AllocatedType) * objectPerAllocation * objectsPerPage;
+ BatchInfo *batch = static_cast( malloc( mallocSize ) );
+ batch->next_ = 0;
+ batch->used_ = batch->buffer_;
+ batch->end_ = batch->buffer_ + objectsPerPage;
+ return batch;
+ }
+
+ BatchInfo *batches_;
+ BatchInfo *currentBatch_;
+ /// Head of a single linked list within the allocated space of freeed object
+ AllocatedType *freeHead_;
+ unsigned int objectsPerPage_;
+};
+
+
+} // namespace Json
+
+# endif // ifndef JSONCPP_DOC_INCLUDE_IMPLEMENTATION
+
+#endif // JSONCPP_BATCHALLOCATOR_H_INCLUDED
+
diff --git a/src/blackberry10/native/public/json_internalarray.inl b/src/blackberry10/native/public/json_internalarray.inl
new file mode 100644
index 00000000..9b985d25
--- /dev/null
+++ b/src/blackberry10/native/public/json_internalarray.inl
@@ -0,0 +1,448 @@
+// included by json_value.cpp
+// everything is within Json namespace
+
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// class ValueInternalArray
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+
+ValueArrayAllocator::~ValueArrayAllocator()
+{
+}
+
+// //////////////////////////////////////////////////////////////////
+// class DefaultValueArrayAllocator
+// //////////////////////////////////////////////////////////////////
+#ifdef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR
+class DefaultValueArrayAllocator : public ValueArrayAllocator
+{
+public: // overridden from ValueArrayAllocator
+ virtual ~DefaultValueArrayAllocator()
+ {
+ }
+
+ virtual ValueInternalArray *newArray()
+ {
+ return new ValueInternalArray();
+ }
+
+ virtual ValueInternalArray *newArrayCopy( const ValueInternalArray &other )
+ {
+ return new ValueInternalArray( other );
+ }
+
+ virtual void destructArray( ValueInternalArray *array )
+ {
+ delete array;
+ }
+
+ virtual void reallocateArrayPageIndex( Value **&indexes,
+ ValueInternalArray::PageIndex &indexCount,
+ ValueInternalArray::PageIndex minNewIndexCount )
+ {
+ ValueInternalArray::PageIndex newIndexCount = (indexCount*3)/2 + 1;
+ if ( minNewIndexCount > newIndexCount )
+ newIndexCount = minNewIndexCount;
+ void *newIndexes = realloc( indexes, sizeof(Value*) * newIndexCount );
+ if ( !newIndexes )
+ throw std::bad_alloc();
+ indexCount = newIndexCount;
+ indexes = static_cast( newIndexes );
+ }
+ virtual void releaseArrayPageIndex( Value **indexes,
+ ValueInternalArray::PageIndex indexCount )
+ {
+ if ( indexes )
+ free( indexes );
+ }
+
+ virtual Value *allocateArrayPage()
+ {
+ return static_cast( malloc( sizeof(Value) * ValueInternalArray::itemsPerPage ) );
+ }
+
+ virtual void releaseArrayPage( Value *value )
+ {
+ if ( value )
+ free( value );
+ }
+};
+
+#else // #ifdef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR
+/// @todo make this thread-safe (lock when accessign batch allocator)
+class DefaultValueArrayAllocator : public ValueArrayAllocator
+{
+public: // overridden from ValueArrayAllocator
+ virtual ~DefaultValueArrayAllocator()
+ {
+ }
+
+ virtual ValueInternalArray *newArray()
+ {
+ ValueInternalArray *array = arraysAllocator_.allocate();
+ new (array) ValueInternalArray(); // placement new
+ return array;
+ }
+
+ virtual ValueInternalArray *newArrayCopy( const ValueInternalArray &other )
+ {
+ ValueInternalArray *array = arraysAllocator_.allocate();
+ new (array) ValueInternalArray( other ); // placement new
+ return array;
+ }
+
+ virtual void destructArray( ValueInternalArray *array )
+ {
+ if ( array )
+ {
+ array->~ValueInternalArray();
+ arraysAllocator_.release( array );
+ }
+ }
+
+ virtual void reallocateArrayPageIndex( Value **&indexes,
+ ValueInternalArray::PageIndex &indexCount,
+ ValueInternalArray::PageIndex minNewIndexCount )
+ {
+ ValueInternalArray::PageIndex newIndexCount = (indexCount*3)/2 + 1;
+ if ( minNewIndexCount > newIndexCount )
+ newIndexCount = minNewIndexCount;
+ void *newIndexes = realloc( indexes, sizeof(Value*) * newIndexCount );
+ if ( !newIndexes )
+ throw std::bad_alloc();
+ indexCount = newIndexCount;
+ indexes = static_cast( newIndexes );
+ }
+ virtual void releaseArrayPageIndex( Value **indexes,
+ ValueInternalArray::PageIndex indexCount )
+ {
+ if ( indexes )
+ free( indexes );
+ }
+
+ virtual Value *allocateArrayPage()
+ {
+ return static_cast( pagesAllocator_.allocate() );
+ }
+
+ virtual void releaseArrayPage( Value *value )
+ {
+ if ( value )
+ pagesAllocator_.release( value );
+ }
+private:
+ BatchAllocator arraysAllocator_;
+ BatchAllocator pagesAllocator_;
+};
+#endif // #ifdef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR
+
+static ValueArrayAllocator *&arrayAllocator()
+{
+ static DefaultValueArrayAllocator defaultAllocator;
+ static ValueArrayAllocator *arrayAllocator = &defaultAllocator;
+ return arrayAllocator;
+}
+
+static struct DummyArrayAllocatorInitializer {
+ DummyArrayAllocatorInitializer()
+ {
+ arrayAllocator(); // ensure arrayAllocator() statics are initialized before main().
+ }
+} dummyArrayAllocatorInitializer;
+
+// //////////////////////////////////////////////////////////////////
+// class ValueInternalArray
+// //////////////////////////////////////////////////////////////////
+bool
+ValueInternalArray::equals( const IteratorState &x,
+ const IteratorState &other )
+{
+ return x.array_ == other.array_
+ && x.currentItemIndex_ == other.currentItemIndex_
+ && x.currentPageIndex_ == other.currentPageIndex_;
+}
+
+
+void
+ValueInternalArray::increment( IteratorState &it )
+{
+ JSON_ASSERT_MESSAGE( it.array_ &&
+ (it.currentPageIndex_ - it.array_->pages_)*itemsPerPage + it.currentItemIndex_
+ != it.array_->size_,
+ "ValueInternalArray::increment(): moving iterator beyond end" );
+ ++(it.currentItemIndex_);
+ if ( it.currentItemIndex_ == itemsPerPage )
+ {
+ it.currentItemIndex_ = 0;
+ ++(it.currentPageIndex_);
+ }
+}
+
+
+void
+ValueInternalArray::decrement( IteratorState &it )
+{
+ JSON_ASSERT_MESSAGE( it.array_ && it.currentPageIndex_ == it.array_->pages_
+ && it.currentItemIndex_ == 0,
+ "ValueInternalArray::decrement(): moving iterator beyond end" );
+ if ( it.currentItemIndex_ == 0 )
+ {
+ it.currentItemIndex_ = itemsPerPage-1;
+ --(it.currentPageIndex_);
+ }
+ else
+ {
+ --(it.currentItemIndex_);
+ }
+}
+
+
+Value &
+ValueInternalArray::unsafeDereference( const IteratorState &it )
+{
+ return (*(it.currentPageIndex_))[it.currentItemIndex_];
+}
+
+
+Value &
+ValueInternalArray::dereference( const IteratorState &it )
+{
+ JSON_ASSERT_MESSAGE( it.array_ &&
+ (it.currentPageIndex_ - it.array_->pages_)*itemsPerPage + it.currentItemIndex_
+ < it.array_->size_,
+ "ValueInternalArray::dereference(): dereferencing invalid iterator" );
+ return unsafeDereference( it );
+}
+
+void
+ValueInternalArray::makeBeginIterator( IteratorState &it ) const
+{
+ it.array_ = const_cast( this );
+ it.currentItemIndex_ = 0;
+ it.currentPageIndex_ = pages_;
+}
+
+
+void
+ValueInternalArray::makeIterator( IteratorState &it, ArrayIndex index ) const
+{
+ it.array_ = const_cast( this );
+ it.currentItemIndex_ = index % itemsPerPage;
+ it.currentPageIndex_ = pages_ + index / itemsPerPage;
+}
+
+
+void
+ValueInternalArray::makeEndIterator( IteratorState &it ) const
+{
+ makeIterator( it, size_ );
+}
+
+
+ValueInternalArray::ValueInternalArray()
+ : pages_( 0 )
+ , size_( 0 )
+ , pageCount_( 0 )
+{
+}
+
+
+ValueInternalArray::ValueInternalArray( const ValueInternalArray &other )
+ : pages_( 0 )
+ , pageCount_( 0 )
+ , size_( other.size_ )
+{
+ PageIndex minNewPages = other.size_ / itemsPerPage;
+ arrayAllocator()->reallocateArrayPageIndex( pages_, pageCount_, minNewPages );
+ JSON_ASSERT_MESSAGE( pageCount_ >= minNewPages,
+ "ValueInternalArray::reserve(): bad reallocation" );
+ IteratorState itOther;
+ other.makeBeginIterator( itOther );
+ Value *value;
+ for ( ArrayIndex index = 0; index < size_; ++index, increment(itOther) )
+ {
+ if ( index % itemsPerPage == 0 )
+ {
+ PageIndex pageIndex = index / itemsPerPage;
+ value = arrayAllocator()->allocateArrayPage();
+ pages_[pageIndex] = value;
+ }
+ new (value) Value( dereference( itOther ) );
+ }
+}
+
+
+ValueInternalArray &
+ValueInternalArray::operator =( const ValueInternalArray &other )
+{
+ ValueInternalArray temp( other );
+ swap( temp );
+ return *this;
+}
+
+
+ValueInternalArray::~ValueInternalArray()
+{
+ // destroy all constructed items
+ IteratorState it;
+ IteratorState itEnd;
+ makeBeginIterator( it);
+ makeEndIterator( itEnd );
+ for ( ; !equals(it,itEnd); increment(it) )
+ {
+ Value *value = &dereference(it);
+ value->~Value();
+ }
+ // release all pages
+ PageIndex lastPageIndex = size_ / itemsPerPage;
+ for ( PageIndex pageIndex = 0; pageIndex < lastPageIndex; ++pageIndex )
+ arrayAllocator()->releaseArrayPage( pages_[pageIndex] );
+ // release pages index
+ arrayAllocator()->releaseArrayPageIndex( pages_, pageCount_ );
+}
+
+
+void
+ValueInternalArray::swap( ValueInternalArray &other )
+{
+ Value **tempPages = pages_;
+ pages_ = other.pages_;
+ other.pages_ = tempPages;
+ ArrayIndex tempSize = size_;
+ size_ = other.size_;
+ other.size_ = tempSize;
+ PageIndex tempPageCount = pageCount_;
+ pageCount_ = other.pageCount_;
+ other.pageCount_ = tempPageCount;
+}
+
+void
+ValueInternalArray::clear()
+{
+ ValueInternalArray dummy;
+ swap( dummy );
+}
+
+
+void
+ValueInternalArray::resize( ArrayIndex newSize )
+{
+ if ( newSize == 0 )
+ clear();
+ else if ( newSize < size_ )
+ {
+ IteratorState it;
+ IteratorState itEnd;
+ makeIterator( it, newSize );
+ makeIterator( itEnd, size_ );
+ for ( ; !equals(it,itEnd); increment(it) )
+ {
+ Value *value = &dereference(it);
+ value->~Value();
+ }
+ PageIndex pageIndex = (newSize + itemsPerPage - 1) / itemsPerPage;
+ PageIndex lastPageIndex = size_ / itemsPerPage;
+ for ( ; pageIndex < lastPageIndex; ++pageIndex )
+ arrayAllocator()->releaseArrayPage( pages_[pageIndex] );
+ size_ = newSize;
+ }
+ else if ( newSize > size_ )
+ resolveReference( newSize );
+}
+
+
+void
+ValueInternalArray::makeIndexValid( ArrayIndex index )
+{
+ // Need to enlarge page index ?
+ if ( index >= pageCount_ * itemsPerPage )
+ {
+ PageIndex minNewPages = (index + 1) / itemsPerPage;
+ arrayAllocator()->reallocateArrayPageIndex( pages_, pageCount_, minNewPages );
+ JSON_ASSERT_MESSAGE( pageCount_ >= minNewPages, "ValueInternalArray::reserve(): bad reallocation" );
+ }
+
+ // Need to allocate new pages ?
+ ArrayIndex nextPageIndex =
+ (size_ % itemsPerPage) != 0 ? size_ - (size_%itemsPerPage) + itemsPerPage
+ : size_;
+ if ( nextPageIndex <= index )
+ {
+ PageIndex pageIndex = nextPageIndex / itemsPerPage;
+ PageIndex pageToAllocate = (index - nextPageIndex) / itemsPerPage + 1;
+ for ( ; pageToAllocate-- > 0; ++pageIndex )
+ pages_[pageIndex] = arrayAllocator()->allocateArrayPage();
+ }
+
+ // Initialize all new entries
+ IteratorState it;
+ IteratorState itEnd;
+ makeIterator( it, size_ );
+ size_ = index + 1;
+ makeIterator( itEnd, size_ );
+ for ( ; !equals(it,itEnd); increment(it) )
+ {
+ Value *value = &dereference(it);
+ new (value) Value(); // Construct a default value using placement new
+ }
+}
+
+Value &
+ValueInternalArray::resolveReference( ArrayIndex index )
+{
+ if ( index >= size_ )
+ makeIndexValid( index );
+ return pages_[index/itemsPerPage][index%itemsPerPage];
+}
+
+Value *
+ValueInternalArray::find( ArrayIndex index ) const
+{
+ if ( index >= size_ )
+ return 0;
+ return &(pages_[index/itemsPerPage][index%itemsPerPage]);
+}
+
+ValueInternalArray::ArrayIndex
+ValueInternalArray::size() const
+{
+ return size_;
+}
+
+int
+ValueInternalArray::distance( const IteratorState &x, const IteratorState &y )
+{
+ return indexOf(y) - indexOf(x);
+}
+
+
+ValueInternalArray::ArrayIndex
+ValueInternalArray::indexOf( const IteratorState &iterator )
+{
+ if ( !iterator.array_ )
+ return ArrayIndex(-1);
+ return ArrayIndex(
+ (iterator.currentPageIndex_ - iterator.array_->pages_) * itemsPerPage
+ + iterator.currentItemIndex_ );
+}
+
+
+int
+ValueInternalArray::compare( const ValueInternalArray &other ) const
+{
+ int sizeDiff( size_ - other.size_ );
+ if ( sizeDiff != 0 )
+ return sizeDiff;
+
+ for ( ArrayIndex index =0; index < size_; ++index )
+ {
+ int diff = pages_[index/itemsPerPage][index%itemsPerPage].compare(
+ other.pages_[index/itemsPerPage][index%itemsPerPage] );
+ if ( diff != 0 )
+ return diff;
+ }
+ return 0;
+}
diff --git a/src/blackberry10/native/public/json_internalmap.inl b/src/blackberry10/native/public/json_internalmap.inl
new file mode 100644
index 00000000..19771488
--- /dev/null
+++ b/src/blackberry10/native/public/json_internalmap.inl
@@ -0,0 +1,607 @@
+// included by json_value.cpp
+// everything is within Json namespace
+
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// class ValueInternalMap
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+
+/** \internal MUST be safely initialized using memset( this, 0, sizeof(ValueInternalLink) );
+ * This optimization is used by the fast allocator.
+ */
+ValueInternalLink::ValueInternalLink()
+ : previous_( 0 )
+ , next_( 0 )
+{
+}
+
+ValueInternalLink::~ValueInternalLink()
+{
+ for ( int index =0; index < itemPerLink; ++index )
+ {
+ if ( !items_[index].isItemAvailable() )
+ {
+ if ( !items_[index].isMemberNameStatic() )
+ free( keys_[index] );
+ }
+ else
+ break;
+ }
+}
+
+
+
+ValueMapAllocator::~ValueMapAllocator()
+{
+}
+
+#ifdef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR
+class DefaultValueMapAllocator : public ValueMapAllocator
+{
+public: // overridden from ValueMapAllocator
+ virtual ValueInternalMap *newMap()
+ {
+ return new ValueInternalMap();
+ }
+
+ virtual ValueInternalMap *newMapCopy( const ValueInternalMap &other )
+ {
+ return new ValueInternalMap( other );
+ }
+
+ virtual void destructMap( ValueInternalMap *map )
+ {
+ delete map;
+ }
+
+ virtual ValueInternalLink *allocateMapBuckets( unsigned int size )
+ {
+ return new ValueInternalLink[size];
+ }
+
+ virtual void releaseMapBuckets( ValueInternalLink *links )
+ {
+ delete [] links;
+ }
+
+ virtual ValueInternalLink *allocateMapLink()
+ {
+ return new ValueInternalLink();
+ }
+
+ virtual void releaseMapLink( ValueInternalLink *link )
+ {
+ delete link;
+ }
+};
+#else
+/// @todo make this thread-safe (lock when accessign batch allocator)
+class DefaultValueMapAllocator : public ValueMapAllocator
+{
+public: // overridden from ValueMapAllocator
+ virtual ValueInternalMap *newMap()
+ {
+ ValueInternalMap *map = mapsAllocator_.allocate();
+ new (map) ValueInternalMap(); // placement new
+ return map;
+ }
+
+ virtual ValueInternalMap *newMapCopy( const ValueInternalMap &other )
+ {
+ ValueInternalMap *map = mapsAllocator_.allocate();
+ new (map) ValueInternalMap( other ); // placement new
+ return map;
+ }
+
+ virtual void destructMap( ValueInternalMap *map )
+ {
+ if ( map )
+ {
+ map->~ValueInternalMap();
+ mapsAllocator_.release( map );
+ }
+ }
+
+ virtual ValueInternalLink *allocateMapBuckets( unsigned int size )
+ {
+ return new ValueInternalLink[size];
+ }
+
+ virtual void releaseMapBuckets( ValueInternalLink *links )
+ {
+ delete [] links;
+ }
+
+ virtual ValueInternalLink *allocateMapLink()
+ {
+ ValueInternalLink *link = linksAllocator_.allocate();
+ memset( link, 0, sizeof(ValueInternalLink) );
+ return link;
+ }
+
+ virtual void releaseMapLink( ValueInternalLink *link )
+ {
+ link->~ValueInternalLink();
+ linksAllocator_.release( link );
+ }
+private:
+ BatchAllocator mapsAllocator_;
+ BatchAllocator linksAllocator_;
+};
+#endif
+
+static ValueMapAllocator *&mapAllocator()
+{
+ static DefaultValueMapAllocator defaultAllocator;
+ static ValueMapAllocator *mapAllocator = &defaultAllocator;
+ return mapAllocator;
+}
+
+static struct DummyMapAllocatorInitializer {
+ DummyMapAllocatorInitializer()
+ {
+ mapAllocator(); // ensure mapAllocator() statics are initialized before main().
+ }
+} dummyMapAllocatorInitializer;
+
+
+
+// h(K) = value * K >> w ; with w = 32 & K prime w.r.t. 2^32.
+
+/*
+use linked list hash map.
+buckets array is a container.
+linked list element contains 6 key/values. (memory = (16+4) * 6 + 4 = 124)
+value have extra state: valid, available, deleted
+*/
+
+
+ValueInternalMap::ValueInternalMap()
+ : buckets_( 0 )
+ , tailLink_( 0 )
+ , bucketsSize_( 0 )
+ , itemCount_( 0 )
+{
+}
+
+
+ValueInternalMap::ValueInternalMap( const ValueInternalMap &other )
+ : buckets_( 0 )
+ , tailLink_( 0 )
+ , bucketsSize_( 0 )
+ , itemCount_( 0 )
+{
+ reserve( other.itemCount_ );
+ IteratorState it;
+ IteratorState itEnd;
+ other.makeBeginIterator( it );
+ other.makeEndIterator( itEnd );
+ for ( ; !equals(it,itEnd); increment(it) )
+ {
+ bool isStatic;
+ const char *memberName = key( it, isStatic );
+ const Value &aValue = value( it );
+ resolveReference(memberName, isStatic) = aValue;
+ }
+}
+
+
+ValueInternalMap &
+ValueInternalMap::operator =( const ValueInternalMap &other )
+{
+ ValueInternalMap dummy( other );
+ swap( dummy );
+ return *this;
+}
+
+
+ValueInternalMap::~ValueInternalMap()
+{
+ if ( buckets_ )
+ {
+ for ( BucketIndex bucketIndex =0; bucketIndex < bucketsSize_; ++bucketIndex )
+ {
+ ValueInternalLink *link = buckets_[bucketIndex].next_;
+ while ( link )
+ {
+ ValueInternalLink *linkToRelease = link;
+ link = link->next_;
+ mapAllocator()->releaseMapLink( linkToRelease );
+ }
+ }
+ mapAllocator()->releaseMapBuckets( buckets_ );
+ }
+}
+
+
+void
+ValueInternalMap::swap( ValueInternalMap &other )
+{
+ ValueInternalLink *tempBuckets = buckets_;
+ buckets_ = other.buckets_;
+ other.buckets_ = tempBuckets;
+ ValueInternalLink *tempTailLink = tailLink_;
+ tailLink_ = other.tailLink_;
+ other.tailLink_ = tempTailLink;
+ BucketIndex tempBucketsSize = bucketsSize_;
+ bucketsSize_ = other.bucketsSize_;
+ other.bucketsSize_ = tempBucketsSize;
+ BucketIndex tempItemCount = itemCount_;
+ itemCount_ = other.itemCount_;
+ other.itemCount_ = tempItemCount;
+}
+
+
+void
+ValueInternalMap::clear()
+{
+ ValueInternalMap dummy;
+ swap( dummy );
+}
+
+
+ValueInternalMap::BucketIndex
+ValueInternalMap::size() const
+{
+ return itemCount_;
+}
+
+bool
+ValueInternalMap::reserveDelta( BucketIndex growth )
+{
+ return reserve( itemCount_ + growth );
+}
+
+bool
+ValueInternalMap::reserve( BucketIndex newItemCount )
+{
+ if ( !buckets_ && newItemCount > 0 )
+ {
+ buckets_ = mapAllocator()->allocateMapBuckets( 1 );
+ bucketsSize_ = 1;
+ tailLink_ = &buckets_[0];
+ }
+// BucketIndex idealBucketCount = (newItemCount + ValueInternalLink::itemPerLink) / ValueInternalLink::itemPerLink;
+ return true;
+}
+
+
+const Value *
+ValueInternalMap::find( const char *key ) const
+{
+ if ( !bucketsSize_ )
+ return 0;
+ HashKey hashedKey = hash( key );
+ BucketIndex bucketIndex = hashedKey % bucketsSize_;
+ for ( const ValueInternalLink *current = &buckets_[bucketIndex];
+ current != 0;
+ current = current->next_ )
+ {
+ for ( BucketIndex index=0; index < ValueInternalLink::itemPerLink; ++index )
+ {
+ if ( current->items_[index].isItemAvailable() )
+ return 0;
+ if ( strcmp( key, current->keys_[index] ) == 0 )
+ return ¤t->items_[index];
+ }
+ }
+ return 0;
+}
+
+
+Value *
+ValueInternalMap::find( const char *key )
+{
+ const ValueInternalMap *constThis = this;
+ return const_cast( constThis->find( key ) );
+}
+
+
+Value &
+ValueInternalMap::resolveReference( const char *key,
+ bool isStatic )
+{
+ HashKey hashedKey = hash( key );
+ if ( bucketsSize_ )
+ {
+ BucketIndex bucketIndex = hashedKey % bucketsSize_;
+ ValueInternalLink **previous = 0;
+ BucketIndex index;
+ for ( ValueInternalLink *current = &buckets_[bucketIndex];
+ current != 0;
+ previous = ¤t->next_, current = current->next_ )
+ {
+ for ( index=0; index < ValueInternalLink::itemPerLink; ++index )
+ {
+ if ( current->items_[index].isItemAvailable() )
+ return setNewItem( key, isStatic, current, index );
+ if ( strcmp( key, current->keys_[index] ) == 0 )
+ return current->items_[index];
+ }
+ }
+ }
+
+ reserveDelta( 1 );
+ return unsafeAdd( key, isStatic, hashedKey );
+}
+
+
+void
+ValueInternalMap::remove( const char *key )
+{
+ HashKey hashedKey = hash( key );
+ if ( !bucketsSize_ )
+ return;
+ BucketIndex bucketIndex = hashedKey % bucketsSize_;
+ for ( ValueInternalLink *link = &buckets_[bucketIndex];
+ link != 0;
+ link = link->next_ )
+ {
+ BucketIndex index;
+ for ( index =0; index < ValueInternalLink::itemPerLink; ++index )
+ {
+ if ( link->items_[index].isItemAvailable() )
+ return;
+ if ( strcmp( key, link->keys_[index] ) == 0 )
+ {
+ doActualRemove( link, index, bucketIndex );
+ return;
+ }
+ }
+ }
+}
+
+void
+ValueInternalMap::doActualRemove( ValueInternalLink *link,
+ BucketIndex index,
+ BucketIndex bucketIndex )
+{
+ // find last item of the bucket and swap it with the 'removed' one.
+ // set removed items flags to 'available'.
+ // if last page only contains 'available' items, then desallocate it (it's empty)
+ ValueInternalLink *&lastLink = getLastLinkInBucket( index );
+ BucketIndex lastItemIndex = 1; // a link can never be empty, so start at 1
+ for ( ;
+ lastItemIndex < ValueInternalLink::itemPerLink;
+ ++lastItemIndex ) // may be optimized with dicotomic search
+ {
+ if ( lastLink->items_[lastItemIndex].isItemAvailable() )
+ break;
+ }
+
+ BucketIndex lastUsedIndex = lastItemIndex - 1;
+ Value *valueToDelete = &link->items_[index];
+ Value *valueToPreserve = &lastLink->items_[lastUsedIndex];
+ if ( valueToDelete != valueToPreserve )
+ valueToDelete->swap( *valueToPreserve );
+ if ( lastUsedIndex == 0 ) // page is now empty
+ { // remove it from bucket linked list and delete it.
+ ValueInternalLink *linkPreviousToLast = lastLink->previous_;
+ if ( linkPreviousToLast != 0 ) // can not deleted bucket link.
+ {
+ mapAllocator()->releaseMapLink( lastLink );
+ linkPreviousToLast->next_ = 0;
+ lastLink = linkPreviousToLast;
+ }
+ }
+ else
+ {
+ Value dummy;
+ valueToPreserve->swap( dummy ); // restore deleted to default Value.
+ valueToPreserve->setItemUsed( false );
+ }
+ --itemCount_;
+}
+
+
+ValueInternalLink *&
+ValueInternalMap::getLastLinkInBucket( BucketIndex bucketIndex )
+{
+ if ( bucketIndex == bucketsSize_ - 1 )
+ return tailLink_;
+ ValueInternalLink *&previous = buckets_[bucketIndex+1].previous_;
+ if ( !previous )
+ previous = &buckets_[bucketIndex];
+ return previous;
+}
+
+
+Value &
+ValueInternalMap::setNewItem( const char *key,
+ bool isStatic,
+ ValueInternalLink *link,
+ BucketIndex index )
+{
+ char *duplicatedKey = valueAllocator()->makeMemberName( key );
+ ++itemCount_;
+ link->keys_[index] = duplicatedKey;
+ link->items_[index].setItemUsed();
+ link->items_[index].setMemberNameIsStatic( isStatic );
+ return link->items_[index]; // items already default constructed.
+}
+
+
+Value &
+ValueInternalMap::unsafeAdd( const char *key,
+ bool isStatic,
+ HashKey hashedKey )
+{
+ JSON_ASSERT_MESSAGE( bucketsSize_ > 0, "ValueInternalMap::unsafeAdd(): internal logic error." );
+ BucketIndex bucketIndex = hashedKey % bucketsSize_;
+ ValueInternalLink *&previousLink = getLastLinkInBucket( bucketIndex );
+ ValueInternalLink *link = previousLink;
+ BucketIndex index;
+ for ( index =0; index < ValueInternalLink::itemPerLink; ++index )
+ {
+ if ( link->items_[index].isItemAvailable() )
+ break;
+ }
+ if ( index == ValueInternalLink::itemPerLink ) // need to add a new page
+ {
+ ValueInternalLink *newLink = mapAllocator()->allocateMapLink();
+ index = 0;
+ link->next_ = newLink;
+ previousLink = newLink;
+ link = newLink;
+ }
+ return setNewItem( key, isStatic, link, index );
+}
+
+
+ValueInternalMap::HashKey
+ValueInternalMap::hash( const char *key ) const
+{
+ HashKey hash = 0;
+ while ( *key )
+ hash += *key++ * 37;
+ return hash;
+}
+
+
+int
+ValueInternalMap::compare( const ValueInternalMap &other ) const
+{
+ int sizeDiff( itemCount_ - other.itemCount_ );
+ if ( sizeDiff != 0 )
+ return sizeDiff;
+ // Strict order guaranty is required. Compare all keys FIRST, then compare values.
+ IteratorState it;
+ IteratorState itEnd;
+ makeBeginIterator( it );
+ makeEndIterator( itEnd );
+ for ( ; !equals(it,itEnd); increment(it) )
+ {
+ if ( !other.find( key( it ) ) )
+ return 1;
+ }
+
+ // All keys are equals, let's compare values
+ makeBeginIterator( it );
+ for ( ; !equals(it,itEnd); increment(it) )
+ {
+ const Value *otherValue = other.find( key( it ) );
+ int valueDiff = value(it).compare( *otherValue );
+ if ( valueDiff != 0 )
+ return valueDiff;
+ }
+ return 0;
+}
+
+
+void
+ValueInternalMap::makeBeginIterator( IteratorState &it ) const
+{
+ it.map_ = const_cast( this );
+ it.bucketIndex_ = 0;
+ it.itemIndex_ = 0;
+ it.link_ = buckets_;
+}
+
+
+void
+ValueInternalMap::makeEndIterator( IteratorState &it ) const
+{
+ it.map_ = const_cast( this );
+ it.bucketIndex_ = bucketsSize_;
+ it.itemIndex_ = 0;
+ it.link_ = 0;
+}
+
+
+bool
+ValueInternalMap::equals( const IteratorState &x, const IteratorState &other )
+{
+ return x.map_ == other.map_
+ && x.bucketIndex_ == other.bucketIndex_
+ && x.link_ == other.link_
+ && x.itemIndex_ == other.itemIndex_;
+}
+
+
+void
+ValueInternalMap::incrementBucket( IteratorState &iterator )
+{
+ ++iterator.bucketIndex_;
+ JSON_ASSERT_MESSAGE( iterator.bucketIndex_ <= iterator.map_->bucketsSize_,
+ "ValueInternalMap::increment(): attempting to iterate beyond end." );
+ if ( iterator.bucketIndex_ == iterator.map_->bucketsSize_ )
+ iterator.link_ = 0;
+ else
+ iterator.link_ = &(iterator.map_->buckets_[iterator.bucketIndex_]);
+ iterator.itemIndex_ = 0;
+}
+
+
+void
+ValueInternalMap::increment( IteratorState &iterator )
+{
+ JSON_ASSERT_MESSAGE( iterator.map_, "Attempting to iterator using invalid iterator." );
+ ++iterator.itemIndex_;
+ if ( iterator.itemIndex_ == ValueInternalLink::itemPerLink )
+ {
+ JSON_ASSERT_MESSAGE( iterator.link_ != 0,
+ "ValueInternalMap::increment(): attempting to iterate beyond end." );
+ iterator.link_ = iterator.link_->next_;
+ if ( iterator.link_ == 0 )
+ incrementBucket( iterator );
+ }
+ else if ( iterator.link_->items_[iterator.itemIndex_].isItemAvailable() )
+ {
+ incrementBucket( iterator );
+ }
+}
+
+
+void
+ValueInternalMap::decrement( IteratorState &iterator )
+{
+ if ( iterator.itemIndex_ == 0 )
+ {
+ JSON_ASSERT_MESSAGE( iterator.map_, "Attempting to iterate using invalid iterator." );
+ if ( iterator.link_ == &iterator.map_->buckets_[iterator.bucketIndex_] )
+ {
+ JSON_ASSERT_MESSAGE( iterator.bucketIndex_ > 0, "Attempting to iterate beyond beginning." );
+ --(iterator.bucketIndex_);
+ }
+ iterator.link_ = iterator.link_->previous_;
+ iterator.itemIndex_ = ValueInternalLink::itemPerLink - 1;
+ }
+}
+
+
+const char *
+ValueInternalMap::key( const IteratorState &iterator )
+{
+ JSON_ASSERT_MESSAGE( iterator.link_, "Attempting to iterate using invalid iterator." );
+ return iterator.link_->keys_[iterator.itemIndex_];
+}
+
+const char *
+ValueInternalMap::key( const IteratorState &iterator, bool &isStatic )
+{
+ JSON_ASSERT_MESSAGE( iterator.link_, "Attempting to iterate using invalid iterator." );
+ isStatic = iterator.link_->items_[iterator.itemIndex_].isMemberNameStatic();
+ return iterator.link_->keys_[iterator.itemIndex_];
+}
+
+
+Value &
+ValueInternalMap::value( const IteratorState &iterator )
+{
+ JSON_ASSERT_MESSAGE( iterator.link_, "Attempting to iterate using invalid iterator." );
+ return iterator.link_->items_[iterator.itemIndex_];
+}
+
+
+int
+ValueInternalMap::distance( const IteratorState &x, const IteratorState &y )
+{
+ int offset = 0;
+ IteratorState it = x;
+ while ( !equals( it, y ) )
+ increment( it );
+ return offset;
+}
diff --git a/src/blackberry10/native/public/json_reader.cpp b/src/blackberry10/native/public/json_reader.cpp
new file mode 100644
index 00000000..5af16c8d
--- /dev/null
+++ b/src/blackberry10/native/public/json_reader.cpp
@@ -0,0 +1,892 @@
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#if _MSC_VER >= 1400 // VC++ 8.0
+#pragma warning( disable : 4996 ) // disable warning about strdup being deprecated.
+#endif
+
+namespace Json {
+
+// QNX is strict about declaring C symbols in the std namespace.
+#ifdef __QNXNTO__
+using std::memcpy;
+using std::sprintf;
+using std::sscanf;
+#endif
+
+// Implementation of class Features
+// ////////////////////////////////
+
+Features::Features()
+ : allowComments_( true )
+ , strictRoot_( false )
+{
+}
+
+
+Features
+Features::all()
+{
+ return Features();
+}
+
+
+Features
+Features::strictMode()
+{
+ Features features;
+ features.allowComments_ = false;
+ features.strictRoot_ = true;
+ return features;
+}
+
+// Implementation of class Reader
+// ////////////////////////////////
+
+
+static inline bool
+in( Reader::Char c, Reader::Char c1, Reader::Char c2, Reader::Char c3, Reader::Char c4 )
+{
+ return c == c1 || c == c2 || c == c3 || c == c4;
+}
+
+static inline bool
+in( Reader::Char c, Reader::Char c1, Reader::Char c2, Reader::Char c3, Reader::Char c4, Reader::Char c5 )
+{
+ return c == c1 || c == c2 || c == c3 || c == c4 || c == c5;
+}
+
+
+static bool
+containsNewLine( Reader::Location begin,
+ Reader::Location end )
+{
+ for ( ;begin < end; ++begin )
+ if ( *begin == '\n' || *begin == '\r' )
+ return true;
+ return false;
+}
+
+static std::string codePointToUTF8(unsigned int cp)
+{
+ std::string result;
+
+ // based on description from http://en.wikipedia.org/wiki/UTF-8
+
+ if (cp <= 0x7f)
+ {
+ result.resize(1);
+ result[0] = static_cast(cp);
+ }
+ else if (cp <= 0x7FF)
+ {
+ result.resize(2);
+ result[1] = static_cast(0x80 | (0x3f & cp));
+ result[0] = static_cast(0xC0 | (0x1f & (cp >> 6)));
+ }
+ else if (cp <= 0xFFFF)
+ {
+ result.resize(3);
+ result[2] = static_cast(0x80 | (0x3f & cp));
+ result[1] = 0x80 | static_cast((0x3f & (cp >> 6)));
+ result[0] = 0xE0 | static_cast((0xf & (cp >> 12)));
+ }
+ else if (cp <= 0x10FFFF)
+ {
+ result.resize(4);
+ result[3] = static_cast(0x80 | (0x3f & cp));
+ result[2] = static_cast(0x80 | (0x3f & (cp >> 6)));
+ result[1] = static_cast(0x80 | (0x3f & (cp >> 12)));
+ result[0] = static_cast(0xF0 | (0x7 & (cp >> 18)));
+ }
+
+ return result;
+}
+
+
+// Class Reader
+// //////////////////////////////////////////////////////////////////
+
+Reader::Reader()
+ : features_( Features::all() )
+{
+}
+
+
+Reader::Reader( const Features &features )
+ : features_( features )
+{
+}
+
+
+bool
+Reader::parse( const std::string &document,
+ Value &root,
+ bool collectComments )
+{
+ document_ = document;
+ const char *begin = document_.c_str();
+ const char *end = begin + document_.length();
+ return parse( begin, end, root, collectComments );
+}
+
+
+bool
+Reader::parse( std::istream& sin,
+ Value &root,
+ bool collectComments )
+{
+ //std::istream_iterator begin(sin);
+ //std::istream_iterator end;
+ // Those would allow streamed input from a file, if parse() were a
+ // template function.
+
+ // Since std::string is reference-counted, this at least does not
+ // create an extra copy.
+ std::string doc;
+ std::getline(sin, doc, (char)EOF);
+ return parse( doc, root, collectComments );
+}
+
+bool
+Reader::parse( const char *beginDoc, const char *endDoc,
+ Value &root,
+ bool collectComments )
+{
+ if ( !features_.allowComments_ )
+ {
+ collectComments = false;
+ }
+
+ begin_ = beginDoc;
+ end_ = endDoc;
+ collectComments_ = collectComments;
+ current_ = begin_;
+ lastValueEnd_ = 0;
+ lastValue_ = 0;
+ commentsBefore_ = "";
+ errors_.clear();
+ while ( !nodes_.empty() )
+ nodes_.pop();
+ nodes_.push( &root );
+
+ bool successful = readValue();
+ Token token;
+ skipCommentTokens( token );
+ if ( collectComments_ && !commentsBefore_.empty() )
+ root.setComment( commentsBefore_, commentAfter );
+ if ( features_.strictRoot_ )
+ {
+ if ( !root.isArray() && !root.isObject() )
+ {
+ // Set error location to start of doc, ideally should be first token found in doc
+ token.type_ = tokenError;
+ token.start_ = beginDoc;
+ token.end_ = endDoc;
+ addError( "A valid JSON document must be either an array or an object value.",
+ token );
+ return false;
+ }
+ }
+ return successful;
+}
+
+
+bool
+Reader::readValue()
+{
+ Token token;
+ skipCommentTokens( token );
+ bool successful = true;
+
+ if ( collectComments_ && !commentsBefore_.empty() )
+ {
+ currentValue().setComment( commentsBefore_, commentBefore );
+ commentsBefore_ = "";
+ }
+
+
+ switch ( token.type_ )
+ {
+ case tokenObjectBegin:
+ successful = readObject( token );
+ break;
+ case tokenArrayBegin:
+ successful = readArray( token );
+ break;
+ case tokenNumber:
+ successful = decodeNumber( token );
+ break;
+ case tokenString:
+ successful = decodeString( token );
+ break;
+ case tokenTrue:
+ currentValue() = true;
+ break;
+ case tokenFalse:
+ currentValue() = false;
+ break;
+ case tokenNull:
+ currentValue() = Value();
+ break;
+ default:
+ return addError( "Syntax error: value, object or array expected.", token );
+ }
+
+ if ( collectComments_ )
+ {
+ lastValueEnd_ = current_;
+ lastValue_ = ¤tValue();
+ }
+
+ return successful;
+}
+
+
+void
+Reader::skipCommentTokens( Token &token )
+{
+ if ( features_.allowComments_ )
+ {
+ do
+ {
+ readToken( token );
+ }
+ while ( token.type_ == tokenComment );
+ }
+ else
+ {
+ readToken( token );
+ }
+}
+
+
+bool
+Reader::expectToken( TokenType type, Token &token, const char *message )
+{
+ readToken( token );
+ if ( token.type_ != type )
+ return addError( message, token );
+ return true;
+}
+
+
+bool
+Reader::readToken( Token &token )
+{
+ skipSpaces();
+ token.start_ = current_;
+ Char c = getNextChar();
+ bool ok = true;
+ switch ( c )
+ {
+ case '{':
+ token.type_ = tokenObjectBegin;
+ break;
+ case '}':
+ token.type_ = tokenObjectEnd;
+ break;
+ case '[':
+ token.type_ = tokenArrayBegin;
+ break;
+ case ']':
+ token.type_ = tokenArrayEnd;
+ break;
+ case '"':
+ token.type_ = tokenString;
+ ok = readString();
+ break;
+ case '/':
+ token.type_ = tokenComment;
+ ok = readComment();
+ break;
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ case '-':
+ token.type_ = tokenNumber;
+ readNumber();
+ break;
+ case 't':
+ token.type_ = tokenTrue;
+ ok = match( "rue", 3 );
+ break;
+ case 'f':
+ token.type_ = tokenFalse;
+ ok = match( "alse", 4 );
+ break;
+ case 'n':
+ token.type_ = tokenNull;
+ ok = match( "ull", 3 );
+ break;
+ case ',':
+ token.type_ = tokenArraySeparator;
+ break;
+ case ':':
+ token.type_ = tokenMemberSeparator;
+ break;
+ case 0:
+ token.type_ = tokenEndOfStream;
+ break;
+ default:
+ ok = false;
+ break;
+ }
+ if ( !ok )
+ token.type_ = tokenError;
+ token.end_ = current_;
+ return true;
+}
+
+
+void
+Reader::skipSpaces()
+{
+ while ( current_ != end_ )
+ {
+ Char c = *current_;
+ if ( c == ' ' || c == '\t' || c == '\r' || c == '\n' )
+ ++current_;
+ else
+ break;
+ }
+}
+
+
+bool
+Reader::match( Location pattern,
+ int patternLength )
+{
+ if ( end_ - current_ < patternLength )
+ return false;
+ int index = patternLength;
+ while ( index-- )
+ if ( current_[index] != pattern[index] )
+ return false;
+ current_ += patternLength;
+ return true;
+}
+
+
+bool
+Reader::readComment()
+{
+ Location commentBegin = current_ - 1;
+ Char c = getNextChar();
+ bool successful = false;
+ if ( c == '*' )
+ successful = readCStyleComment();
+ else if ( c == '/' )
+ successful = readCppStyleComment();
+ if ( !successful )
+ return false;
+
+ if ( collectComments_ )
+ {
+ CommentPlacement placement = commentBefore;
+ if ( lastValueEnd_ && !containsNewLine( lastValueEnd_, commentBegin ) )
+ {
+ if ( c != '*' || !containsNewLine( commentBegin, current_ ) )
+ placement = commentAfterOnSameLine;
+ }
+
+ addComment( commentBegin, current_, placement );
+ }
+ return true;
+}
+
+
+void
+Reader::addComment( Location begin,
+ Location end,
+ CommentPlacement placement )
+{
+ assert( collectComments_ );
+ if ( placement == commentAfterOnSameLine )
+ {
+ assert( lastValue_ != 0 );
+ lastValue_->setComment( std::string( begin, end ), placement );
+ }
+ else
+ {
+ if ( !commentsBefore_.empty() )
+ commentsBefore_ += "\n";
+ commentsBefore_ += std::string( begin, end );
+ }
+}
+
+
+bool
+Reader::readCStyleComment()
+{
+ while ( current_ != end_ )
+ {
+ Char c = getNextChar();
+ if ( c == '*' && *current_ == '/' )
+ break;
+ }
+ return getNextChar() == '/';
+}
+
+
+bool
+Reader::readCppStyleComment()
+{
+ while ( current_ != end_ )
+ {
+ Char c = getNextChar();
+ if ( c == '\r' || c == '\n' )
+ break;
+ }
+ return true;
+}
+
+
+void
+Reader::readNumber()
+{
+ while ( current_ != end_ )
+ {
+ if ( !(*current_ >= '0' && *current_ <= '9') &&
+ !in( *current_, '.', 'e', 'E', '+', '-' ) )
+ break;
+ ++current_;
+ }
+}
+
+bool
+Reader::readString()
+{
+ Char c = 0;
+ while ( current_ != end_ )
+ {
+ c = getNextChar();
+ if ( c == '\\' )
+ getNextChar();
+ else if ( c == '"' )
+ break;
+ }
+ return c == '"';
+}
+
+
+bool
+Reader::readObject( Token &tokenStart )
+{
+ Token tokenName;
+ std::string name;
+ currentValue() = Value( objectValue );
+ while ( readToken( tokenName ) )
+ {
+ bool initialTokenOk = true;
+ while ( tokenName.type_ == tokenComment && initialTokenOk )
+ initialTokenOk = readToken( tokenName );
+ if ( !initialTokenOk )
+ break;
+ if ( tokenName.type_ == tokenObjectEnd && name.empty() ) // empty object
+ return true;
+ if ( tokenName.type_ != tokenString )
+ break;
+
+ name = "";
+ if ( !decodeString( tokenName, name ) )
+ return recoverFromError( tokenObjectEnd );
+
+ Token colon;
+ if ( !readToken( colon ) || colon.type_ != tokenMemberSeparator )
+ {
+ return addErrorAndRecover( "Missing ':' after object member name",
+ colon,
+ tokenObjectEnd );
+ }
+ Value &value = currentValue()[ name ];
+ nodes_.push( &value );
+ bool ok = readValue();
+ nodes_.pop();
+ if ( !ok ) // error already set
+ return recoverFromError( tokenObjectEnd );
+
+ Token comma;
+ if ( !readToken( comma )
+ || ( comma.type_ != tokenObjectEnd &&
+ comma.type_ != tokenArraySeparator &&
+ comma.type_ != tokenComment ) )
+ {
+ return addErrorAndRecover( "Missing ',' or '}' in object declaration",
+ comma,
+ tokenObjectEnd );
+ }
+ bool finalizeTokenOk = true;
+ while ( comma.type_ == tokenComment &&
+ finalizeTokenOk )
+ finalizeTokenOk = readToken( comma );
+ if ( comma.type_ == tokenObjectEnd )
+ return true;
+ }
+ return addErrorAndRecover( "Missing '}' or object member name",
+ tokenName,
+ tokenObjectEnd );
+}
+
+
+bool
+Reader::readArray( Token &tokenStart )
+{
+ currentValue() = Value( arrayValue );
+ skipSpaces();
+ if ( *current_ == ']' ) // empty array
+ {
+ Token endArray;
+ readToken( endArray );
+ return true;
+ }
+ int index = 0;
+ while ( true )
+ {
+ Value &value = currentValue()[ index++ ];
+ nodes_.push( &value );
+ bool ok = readValue();
+ nodes_.pop();
+ if ( !ok ) // error already set
+ return recoverFromError( tokenArrayEnd );
+
+ Token token;
+ // Accept Comment after last item in the array.
+ ok = readToken( token );
+ while ( token.type_ == tokenComment && ok )
+ {
+ ok = readToken( token );
+ }
+ bool badTokenType = ( token.type_ == tokenArraySeparator &&
+ token.type_ == tokenArrayEnd );
+ if ( !ok || badTokenType )
+ {
+ return addErrorAndRecover( "Missing ',' or ']' in array declaration",
+ token,
+ tokenArrayEnd );
+ }
+ if ( token.type_ == tokenArrayEnd )
+ break;
+ }
+ return true;
+}
+
+
+bool
+Reader::decodeNumber( Token &token )
+{
+ bool isDouble = false;
+ for ( Location inspect = token.start_; inspect != token.end_; ++inspect )
+ {
+ isDouble = isDouble
+ || in( *inspect, '.', 'e', 'E', '+' )
+ || ( *inspect == '-' && inspect != token.start_ );
+ }
+ if ( isDouble )
+ return decodeDouble( token );
+ Location current = token.start_;
+ bool isNegative = *current == '-';
+ if ( isNegative )
+ ++current;
+ Value::UInt threshold = (isNegative ? Value::UInt(-Value::minInt)
+ : Value::maxUInt) / 10;
+ Value::UInt value = 0;
+ while ( current < token.end_ )
+ {
+ Char c = *current++;
+ if ( c < '0' || c > '9' )
+ return addError( "'" + std::string( token.start_, token.end_ ) + "' is not a number.", token );
+ if ( value >= threshold )
+ return decodeDouble( token );
+ value = value * 10 + Value::UInt(c - '0');
+ }
+ if ( isNegative )
+ currentValue() = -Value::Int( value );
+ else if ( value <= Value::UInt(Value::maxInt) )
+ currentValue() = Value::Int( value );
+ else
+ currentValue() = value;
+ return true;
+}
+
+
+bool
+Reader::decodeDouble( Token &token )
+{
+ double value = 0;
+ const int bufferSize = 32;
+ int count;
+ int length = int(token.end_ - token.start_);
+ if ( length <= bufferSize )
+ {
+ Char buffer[bufferSize];
+ memcpy( buffer, token.start_, length );
+ buffer[length] = 0;
+ count = sscanf( buffer, "%lf", &value );
+ }
+ else
+ {
+ std::string buffer( token.start_, token.end_ );
+ count = sscanf( buffer.c_str(), "%lf", &value );
+ }
+
+ if ( count != 1 )
+ return addError( "'" + std::string( token.start_, token.end_ ) + "' is not a number.", token );
+ currentValue() = value;
+ return true;
+}
+
+
+bool
+Reader::decodeString( Token &token )
+{
+ std::string decoded;
+ if ( !decodeString( token, decoded ) )
+ return false;
+ currentValue() = decoded;
+ return true;
+}
+
+
+bool
+Reader::decodeString( Token &token, std::string &decoded )
+{
+ decoded.reserve( token.end_ - token.start_ - 2 );
+ Location current = token.start_ + 1; // skip '"'
+ Location end = token.end_ - 1; // do not include '"'
+ while ( current != end )
+ {
+ Char c = *current++;
+ if ( c == '"' )
+ break;
+ else if ( c == '\\' )
+ {
+ if ( current == end )
+ return addError( "Empty escape sequence in string", token, current );
+ Char escape = *current++;
+ switch ( escape )
+ {
+ case '"': decoded += '"'; break;
+ case '/': decoded += '/'; break;
+ case '\\': decoded += '\\'; break;
+ case 'b': decoded += '\b'; break;
+ case 'f': decoded += '\f'; break;
+ case 'n': decoded += '\n'; break;
+ case 'r': decoded += '\r'; break;
+ case 't': decoded += '\t'; break;
+ case 'u':
+ {
+ unsigned int unicode;
+ if ( !decodeUnicodeCodePoint( token, current, end, unicode ) )
+ return false;
+ decoded += codePointToUTF8(unicode);
+ }
+ break;
+ default:
+ return addError( "Bad escape sequence in string", token, current );
+ }
+ }
+ else
+ {
+ decoded += c;
+ }
+ }
+ return true;
+}
+
+bool
+Reader::decodeUnicodeCodePoint( Token &token,
+ Location ¤t,
+ Location end,
+ unsigned int &unicode )
+{
+
+ if ( !decodeUnicodeEscapeSequence( token, current, end, unicode ) )
+ return false;
+ if (unicode >= 0xD800 && unicode <= 0xDBFF)
+ {
+ // surrogate pairs
+ if (end - current < 6)
+ return addError( "additional six characters expected to parse unicode surrogate pair.", token, current );
+ unsigned int surrogatePair;
+ if (*(current++) == '\\' && *(current++)== 'u')
+ {
+ if (decodeUnicodeEscapeSequence( token, current, end, surrogatePair ))
+ {
+ unicode = 0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF);
+ }
+ else
+ return false;
+ }
+ else
+ return addError( "expecting another \\u token to begin the second half of a unicode surrogate pair", token, current );
+ }
+ return true;
+}
+
+bool
+Reader::decodeUnicodeEscapeSequence( Token &token,
+ Location ¤t,
+ Location end,
+ unsigned int &unicode )
+{
+ if ( end - current < 4 )
+ return addError( "Bad unicode escape sequence in string: four digits expected.", token, current );
+ unicode = 0;
+ for ( int index =0; index < 4; ++index )
+ {
+ Char c = *current++;
+ unicode *= 16;
+ if ( c >= '0' && c <= '9' )
+ unicode += c - '0';
+ else if ( c >= 'a' && c <= 'f' )
+ unicode += c - 'a' + 10;
+ else if ( c >= 'A' && c <= 'F' )
+ unicode += c - 'A' + 10;
+ else
+ return addError( "Bad unicode escape sequence in string: hexadecimal digit expected.", token, current );
+ }
+ return true;
+}
+
+
+bool
+Reader::addError( const std::string &message,
+ Token &token,
+ Location extra )
+{
+ ErrorInfo info;
+ info.token_ = token;
+ info.message_ = message;
+ info.extra_ = extra;
+ errors_.push_back( info );
+ return false;
+}
+
+
+bool
+Reader::recoverFromError( TokenType skipUntilToken )
+{
+ int errorCount = int(errors_.size());
+ Token skip;
+ while ( true )
+ {
+ if ( !readToken(skip) )
+ errors_.resize( errorCount ); // discard errors caused by recovery
+ if ( skip.type_ == skipUntilToken || skip.type_ == tokenEndOfStream )
+ break;
+ }
+ errors_.resize( errorCount );
+ return false;
+}
+
+
+bool
+Reader::addErrorAndRecover( const std::string &message,
+ Token &token,
+ TokenType skipUntilToken )
+{
+ addError( message, token );
+ return recoverFromError( skipUntilToken );
+}
+
+
+Value &
+Reader::currentValue()
+{
+ return *(nodes_.top());
+}
+
+
+Reader::Char
+Reader::getNextChar()
+{
+ if ( current_ == end_ )
+ return 0;
+ return *current_++;
+}
+
+
+void
+Reader::getLocationLineAndColumn( Location location,
+ int &line,
+ int &column ) const
+{
+ Location current = begin_;
+ Location lastLineStart = current;
+ line = 0;
+ while ( current < location && current != end_ )
+ {
+ Char c = *current++;
+ if ( c == '\r' )
+ {
+ if ( *current == '\n' )
+ ++current;
+ lastLineStart = current;
+ ++line;
+ }
+ else if ( c == '\n' )
+ {
+ lastLineStart = current;
+ ++line;
+ }
+ }
+ // column & line start at 1
+ column = int(location - lastLineStart) + 1;
+ ++line;
+}
+
+
+std::string
+Reader::getLocationLineAndColumn( Location location ) const
+{
+ int line, column;
+ getLocationLineAndColumn( location, line, column );
+ char buffer[18+16+16+1];
+ sprintf( buffer, "Line %d, Column %d", line, column );
+ return buffer;
+}
+
+
+std::string
+Reader::getFormatedErrorMessages() const
+{
+ std::string formattedMessage;
+ for ( Errors::const_iterator itError = errors_.begin();
+ itError != errors_.end();
+ ++itError )
+ {
+ const ErrorInfo &error = *itError;
+ formattedMessage += "* " + getLocationLineAndColumn( error.token_.start_ ) + "\n";
+ formattedMessage += " " + error.message_ + "\n";
+ if ( error.extra_ )
+ formattedMessage += "See " + getLocationLineAndColumn( error.extra_ ) + " for detail.\n";
+ }
+ return formattedMessage;
+}
+
+
+std::istream& operator>>( std::istream &sin, Value &root )
+{
+ Json::Reader reader;
+ bool ok = reader.parse(sin, root, true);
+ //JSON_ASSERT( ok );
+ if (!ok) throw std::runtime_error(reader.getFormatedErrorMessages());
+ return sin;
+}
+
+
+} // namespace Json
diff --git a/src/blackberry10/native/public/json_value.cpp b/src/blackberry10/native/public/json_value.cpp
new file mode 100644
index 00000000..6e5dcd3e
--- /dev/null
+++ b/src/blackberry10/native/public/json_value.cpp
@@ -0,0 +1,1726 @@
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#ifdef JSON_USE_CPPTL
+# include
+#endif
+#include // size_t
+#ifndef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR
+# include "json_batchallocator.h"
+#endif // #ifndef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR
+
+#define JSON_ASSERT_UNREACHABLE assert( false )
+#define JSON_ASSERT( condition ) assert( condition ); // @todo <= change this into an exception throw
+#define JSON_ASSERT_MESSAGE( condition, message ) if (!( condition )) throw std::runtime_error( message );
+
+namespace Json {
+
+// QNX is strict about declaring C symbols in the std namespace.
+#ifdef __QNXNTO__
+using std::memcpy;
+using std::strchr;
+using std::strcmp;
+using std::strlen;
+#endif
+
+const Value Value::null;
+const Int Value::minInt = Int( ~(UInt(-1)/2) );
+const Int Value::maxInt = Int( UInt(-1)/2 );
+const UInt Value::maxUInt = UInt(-1);
+
+// A "safe" implementation of strdup. Allow null pointer to be passed.
+// Also avoid warning on msvc80.
+//
+//inline char *safeStringDup( const char *czstring )
+//{
+// if ( czstring )
+// {
+// const size_t length = (unsigned int)( strlen(czstring) + 1 );
+// char *newString = static_cast( malloc( length ) );
+// memcpy( newString, czstring, length );
+// return newString;
+// }
+// return 0;
+//}
+//
+//inline char *safeStringDup( const std::string &str )
+//{
+// if ( !str.empty() )
+// {
+// const size_t length = str.length();
+// char *newString = static_cast( malloc( length + 1 ) );
+// memcpy( newString, str.c_str(), length );
+// newString[length] = 0;
+// return newString;
+// }
+// return 0;
+//}
+
+ValueAllocator::~ValueAllocator()
+{
+}
+
+class DefaultValueAllocator : public ValueAllocator
+{
+public:
+ virtual ~DefaultValueAllocator()
+ {
+ }
+
+ virtual char *makeMemberName( const char *memberName )
+ {
+ return duplicateStringValue( memberName );
+ }
+
+ virtual void releaseMemberName( char *memberName )
+ {
+ releaseStringValue( memberName );
+ }
+
+ virtual char *duplicateStringValue( const char *value,
+ unsigned int length = unknown )
+ {
+ //@todo invesgate this old optimization
+ //if ( !value || value[0] == 0 )
+ // return 0;
+
+ if ( length == unknown )
+ length = (unsigned int)strlen(value);
+ char *newString = static_cast( malloc( length + 1 ) );
+ memcpy( newString, value, length );
+ newString[length] = 0;
+ return newString;
+ }
+
+ virtual void releaseStringValue( char *value )
+ {
+ if ( value )
+ free( value );
+ }
+};
+
+static ValueAllocator *&valueAllocator()
+{
+ static DefaultValueAllocator defaultAllocator;
+ static ValueAllocator *valueAllocator = &defaultAllocator;
+ return valueAllocator;
+}
+
+static struct DummyValueAllocatorInitializer {
+ DummyValueAllocatorInitializer()
+ {
+ valueAllocator(); // ensure valueAllocator() statics are initialized before main().
+ }
+} dummyValueAllocatorInitializer;
+
+
+
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// ValueInternals...
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+#ifdef JSON_VALUE_USE_INTERNAL_MAP
+# include "json_internalarray.inl"
+# include "json_internalmap.inl"
+#endif // JSON_VALUE_USE_INTERNAL_MAP
+
+# include "json_valueiterator.inl"
+
+
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// class Value::CommentInfo
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+
+
+Value::CommentInfo::CommentInfo()
+ : comment_( 0 )
+{
+}
+
+Value::CommentInfo::~CommentInfo()
+{
+ if ( comment_ )
+ valueAllocator()->releaseStringValue( comment_ );
+}
+
+
+void
+Value::CommentInfo::setComment( const char *text )
+{
+ if ( comment_ )
+ valueAllocator()->releaseStringValue( comment_ );
+ JSON_ASSERT( text );
+ JSON_ASSERT_MESSAGE( text[0]=='\0' || text[0]=='/', "Comments must start with /");
+ // It seems that /**/ style comments are acceptable as well.
+ comment_ = valueAllocator()->duplicateStringValue( text );
+}
+
+
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// class Value::CZString
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+# ifndef JSON_VALUE_USE_INTERNAL_MAP
+
+// Notes: index_ indicates if the string was allocated when
+// a string is stored.
+
+Value::CZString::CZString( int index )
+ : cstr_( 0 )
+ , index_( index )
+{
+}
+
+Value::CZString::CZString( const char *cstr, DuplicationPolicy allocate )
+ : cstr_( allocate == duplicate ? valueAllocator()->makeMemberName(cstr)
+ : cstr )
+ , index_( allocate )
+{
+}
+
+Value::CZString::CZString( const CZString &other )
+: cstr_( other.index_ != noDuplication && other.cstr_ != 0
+ ? valueAllocator()->makeMemberName( other.cstr_ )
+ : other.cstr_ )
+ , index_( other.cstr_ ? (other.index_ == noDuplication ? noDuplication : duplicate)
+ : other.index_ )
+{
+}
+
+Value::CZString::~CZString()
+{
+ if ( cstr_ && index_ == duplicate )
+ valueAllocator()->releaseMemberName( const_cast( cstr_ ) );
+}
+
+void
+Value::CZString::swap( CZString &other )
+{
+ std::swap( cstr_, other.cstr_ );
+ std::swap( index_, other.index_ );
+}
+
+Value::CZString &
+Value::CZString::operator =( const CZString &other )
+{
+ CZString temp( other );
+ swap( temp );
+ return *this;
+}
+
+bool
+Value::CZString::operator<( const CZString &other ) const
+{
+ if ( cstr_ )
+ return strcmp( cstr_, other.cstr_ ) < 0;
+ return index_ < other.index_;
+}
+
+bool
+Value::CZString::operator==( const CZString &other ) const
+{
+ if ( cstr_ )
+ return strcmp( cstr_, other.cstr_ ) == 0;
+ return index_ == other.index_;
+}
+
+
+int
+Value::CZString::index() const
+{
+ return index_;
+}
+
+
+const char *
+Value::CZString::c_str() const
+{
+ return cstr_;
+}
+
+bool
+Value::CZString::isStaticString() const
+{
+ return index_ == noDuplication;
+}
+
+#endif // ifndef JSON_VALUE_USE_INTERNAL_MAP
+
+
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// class Value::Value
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+
+/*! \internal Default constructor initialization must be equivalent to:
+ * memset( this, 0, sizeof(Value) )
+ * This optimization is used in ValueInternalMap fast allocator.
+ */
+Value::Value( ValueType type )
+ : type_( type )
+ , allocated_( 0 )
+ , comments_( 0 )
+# ifdef JSON_VALUE_USE_INTERNAL_MAP
+ , itemIsUsed_( 0 )
+#endif
+{
+ switch ( type )
+ {
+ case nullValue:
+ break;
+ case intValue:
+ case uintValue:
+ value_.int_ = 0;
+ break;
+ case realValue:
+ value_.real_ = 0.0;
+ break;
+ case stringValue:
+ value_.string_ = 0;
+ break;
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+ case arrayValue:
+ case objectValue:
+ value_.map_ = new ObjectValues();
+ break;
+#else
+ case arrayValue:
+ value_.array_ = arrayAllocator()->newArray();
+ break;
+ case objectValue:
+ value_.map_ = mapAllocator()->newMap();
+ break;
+#endif
+ case booleanValue:
+ value_.bool_ = false;
+ break;
+ default:
+ JSON_ASSERT_UNREACHABLE;
+ }
+}
+
+
+Value::Value( Int value )
+ : type_( intValue )
+ , comments_( 0 )
+# ifdef JSON_VALUE_USE_INTERNAL_MAP
+ , itemIsUsed_( 0 )
+#endif
+{
+ value_.int_ = value;
+}
+
+
+Value::Value( UInt value )
+ : type_( uintValue )
+ , comments_( 0 )
+# ifdef JSON_VALUE_USE_INTERNAL_MAP
+ , itemIsUsed_( 0 )
+#endif
+{
+ value_.uint_ = value;
+}
+
+Value::Value( double value )
+ : type_( realValue )
+ , comments_( 0 )
+# ifdef JSON_VALUE_USE_INTERNAL_MAP
+ , itemIsUsed_( 0 )
+#endif
+{
+ value_.real_ = value;
+}
+
+Value::Value( const char *value )
+ : type_( stringValue )
+ , allocated_( true )
+ , comments_( 0 )
+# ifdef JSON_VALUE_USE_INTERNAL_MAP
+ , itemIsUsed_( 0 )
+#endif
+{
+ value_.string_ = valueAllocator()->duplicateStringValue( value );
+}
+
+
+Value::Value( const char *beginValue,
+ const char *endValue )
+ : type_( stringValue )
+ , allocated_( true )
+ , comments_( 0 )
+# ifdef JSON_VALUE_USE_INTERNAL_MAP
+ , itemIsUsed_( 0 )
+#endif
+{
+ value_.string_ = valueAllocator()->duplicateStringValue( beginValue,
+ UInt(endValue - beginValue) );
+}
+
+
+Value::Value( const std::string &value )
+ : type_( stringValue )
+ , allocated_( true )
+ , comments_( 0 )
+# ifdef JSON_VALUE_USE_INTERNAL_MAP
+ , itemIsUsed_( 0 )
+#endif
+{
+ value_.string_ = valueAllocator()->duplicateStringValue( value.c_str(),
+ (unsigned int)value.length() );
+
+}
+
+Value::Value( const StaticString &value )
+ : type_( stringValue )
+ , allocated_( false )
+ , comments_( 0 )
+# ifdef JSON_VALUE_USE_INTERNAL_MAP
+ , itemIsUsed_( 0 )
+#endif
+{
+ value_.string_ = const_cast( value.c_str() );
+}
+
+
+# ifdef JSON_USE_CPPTL
+Value::Value( const CppTL::ConstString &value )
+ : type_( stringValue )
+ , allocated_( true )
+ , comments_( 0 )
+# ifdef JSON_VALUE_USE_INTERNAL_MAP
+ , itemIsUsed_( 0 )
+#endif
+{
+ value_.string_ = valueAllocator()->duplicateStringValue( value, value.length() );
+}
+# endif
+
+Value::Value( bool value )
+ : type_( booleanValue )
+ , comments_( 0 )
+# ifdef JSON_VALUE_USE_INTERNAL_MAP
+ , itemIsUsed_( 0 )
+#endif
+{
+ value_.bool_ = value;
+}
+
+
+Value::Value( const Value &other )
+ : type_( other.type_ )
+ , comments_( 0 )
+# ifdef JSON_VALUE_USE_INTERNAL_MAP
+ , itemIsUsed_( 0 )
+#endif
+{
+ switch ( type_ )
+ {
+ case nullValue:
+ case intValue:
+ case uintValue:
+ case realValue:
+ case booleanValue:
+ value_ = other.value_;
+ break;
+ case stringValue:
+ if ( other.value_.string_ )
+ {
+ value_.string_ = valueAllocator()->duplicateStringValue( other.value_.string_ );
+ allocated_ = true;
+ }
+ else
+ value_.string_ = 0;
+ break;
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+ case arrayValue:
+ case objectValue:
+ value_.map_ = new ObjectValues( *other.value_.map_ );
+ break;
+#else
+ case arrayValue:
+ value_.array_ = arrayAllocator()->newArrayCopy( *other.value_.array_ );
+ break;
+ case objectValue:
+ value_.map_ = mapAllocator()->newMapCopy( *other.value_.map_ );
+ break;
+#endif
+ default:
+ JSON_ASSERT_UNREACHABLE;
+ }
+ if ( other.comments_ )
+ {
+ comments_ = new CommentInfo[numberOfCommentPlacement];
+ for ( int comment =0; comment < numberOfCommentPlacement; ++comment )
+ {
+ const CommentInfo &otherComment = other.comments_[comment];
+ if ( otherComment.comment_ )
+ comments_[comment].setComment( otherComment.comment_ );
+ }
+ }
+}
+
+
+Value::~Value()
+{
+ switch ( type_ )
+ {
+ case nullValue:
+ case intValue:
+ case uintValue:
+ case realValue:
+ case booleanValue:
+ break;
+ case stringValue:
+ if ( allocated_ )
+ valueAllocator()->releaseStringValue( value_.string_ );
+ break;
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+ case arrayValue:
+ case objectValue:
+ delete value_.map_;
+ break;
+#else
+ case arrayValue:
+ arrayAllocator()->destructArray( value_.array_ );
+ break;
+ case objectValue:
+ mapAllocator()->destructMap( value_.map_ );
+ break;
+#endif
+ default:
+ JSON_ASSERT_UNREACHABLE;
+ }
+
+ if ( comments_ )
+ delete[] comments_;
+}
+
+Value &
+Value::operator=( const Value &other )
+{
+ Value temp( other );
+ swap( temp );
+ return *this;
+}
+
+void
+Value::swap( Value &other )
+{
+ ValueType temp = type_;
+ type_ = other.type_;
+ other.type_ = temp;
+ std::swap( value_, other.value_ );
+ int temp2 = allocated_;
+ allocated_ = other.allocated_;
+ other.allocated_ = temp2;
+}
+
+ValueType
+Value::type() const
+{
+ return type_;
+}
+
+
+int
+Value::compare( const Value &other )
+{
+ /*
+ int typeDelta = other.type_ - type_;
+ switch ( type_ )
+ {
+ case nullValue:
+
+ return other.type_ == type_;
+ case intValue:
+ if ( other.type_.isNumeric()
+ case uintValue:
+ case realValue:
+ case booleanValue:
+ break;
+ case stringValue,
+ break;
+ case arrayValue:
+ delete value_.array_;
+ break;
+ case objectValue:
+ delete value_.map_;
+ default:
+ JSON_ASSERT_UNREACHABLE;
+ }
+ */
+ return 0; // unreachable
+}
+
+bool
+Value::operator <( const Value &other ) const
+{
+ int typeDelta = type_ - other.type_;
+ if ( typeDelta )
+ return typeDelta < 0 ? true : false;
+ switch ( type_ )
+ {
+ case nullValue:
+ return false;
+ case intValue:
+ return value_.int_ < other.value_.int_;
+ case uintValue:
+ return value_.uint_ < other.value_.uint_;
+ case realValue:
+ return value_.real_ < other.value_.real_;
+ case booleanValue:
+ return value_.bool_ < other.value_.bool_;
+ case stringValue:
+ return ( value_.string_ == 0 && other.value_.string_ )
+ || ( other.value_.string_
+ && value_.string_
+ && strcmp( value_.string_, other.value_.string_ ) < 0 );
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+ case arrayValue:
+ case objectValue:
+ {
+ int delta = int( value_.map_->size() - other.value_.map_->size() );
+ if ( delta )
+ return delta < 0;
+ return (*value_.map_) < (*other.value_.map_);
+ }
+#else
+ case arrayValue:
+ return value_.array_->compare( *(other.value_.array_) ) < 0;
+ case objectValue:
+ return value_.map_->compare( *(other.value_.map_) ) < 0;
+#endif
+ default:
+ JSON_ASSERT_UNREACHABLE;
+ }
+ return 0; // unreachable
+}
+
+bool
+Value::operator <=( const Value &other ) const
+{
+ return !(other > *this);
+}
+
+bool
+Value::operator >=( const Value &other ) const
+{
+ return !(*this < other);
+}
+
+bool
+Value::operator >( const Value &other ) const
+{
+ return other < *this;
+}
+
+bool
+Value::operator ==( const Value &other ) const
+{
+ //if ( type_ != other.type_ )
+ // GCC 2.95.3 says:
+ // attempt to take address of bit-field structure member `Json::Value::type_'
+ // Beats me, but a temp solves the problem.
+ int temp = other.type_;
+ if ( type_ != temp )
+ return false;
+ switch ( type_ )
+ {
+ case nullValue:
+ return true;
+ case intValue:
+ return value_.int_ == other.value_.int_;
+ case uintValue:
+ return value_.uint_ == other.value_.uint_;
+ case realValue:
+ return value_.real_ == other.value_.real_;
+ case booleanValue:
+ return value_.bool_ == other.value_.bool_;
+ case stringValue:
+ return ( value_.string_ == other.value_.string_ )
+ || ( other.value_.string_
+ && value_.string_
+ && strcmp( value_.string_, other.value_.string_ ) == 0 );
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+ case arrayValue:
+ case objectValue:
+ return value_.map_->size() == other.value_.map_->size()
+ && (*value_.map_) == (*other.value_.map_);
+#else
+ case arrayValue:
+ return value_.array_->compare( *(other.value_.array_) ) == 0;
+ case objectValue:
+ return value_.map_->compare( *(other.value_.map_) ) == 0;
+#endif
+ default:
+ JSON_ASSERT_UNREACHABLE;
+ }
+ return 0; // unreachable
+}
+
+bool
+Value::operator !=( const Value &other ) const
+{
+ return !( *this == other );
+}
+
+const char *
+Value::asCString() const
+{
+ JSON_ASSERT( type_ == stringValue );
+ return value_.string_;
+}
+
+
+std::string
+Value::asString() const
+{
+ switch ( type_ )
+ {
+ case nullValue:
+ return "";
+ case stringValue:
+ return value_.string_ ? value_.string_ : "";
+ case booleanValue:
+ return value_.bool_ ? "true" : "false";
+ case intValue:
+ case uintValue:
+ case realValue:
+ case arrayValue:
+ case objectValue:
+ JSON_ASSERT_MESSAGE( false, "Type is not convertible to string" );
+ default:
+ JSON_ASSERT_UNREACHABLE;
+ }
+ return ""; // unreachable
+}
+
+# ifdef JSON_USE_CPPTL
+CppTL::ConstString
+Value::asConstString() const
+{
+ return CppTL::ConstString( asString().c_str() );
+}
+# endif
+
+Value::Int
+Value::asInt() const
+{
+ switch ( type_ )
+ {
+ case nullValue:
+ return 0;
+ case intValue:
+ return value_.int_;
+ case uintValue:
+ JSON_ASSERT_MESSAGE( value_.uint_ < (unsigned)maxInt, "integer out of signed integer range" );
+ return value_.uint_;
+ case realValue:
+ JSON_ASSERT_MESSAGE( value_.real_ >= minInt && value_.real_ <= maxInt, "Real out of signed integer range" );
+ return Int( value_.real_ );
+ case booleanValue:
+ return value_.bool_ ? 1 : 0;
+ case stringValue:
+ case arrayValue:
+ case objectValue:
+ JSON_ASSERT_MESSAGE( false, "Type is not convertible to int" );
+ default:
+ JSON_ASSERT_UNREACHABLE;
+ }
+ return 0; // unreachable;
+}
+
+Value::UInt
+Value::asUInt() const
+{
+ switch ( type_ )
+ {
+ case nullValue:
+ return 0;
+ case intValue:
+ JSON_ASSERT_MESSAGE( value_.int_ >= 0, "Negative integer can not be converted to unsigned integer" );
+ return value_.int_;
+ case uintValue:
+ return value_.uint_;
+ case realValue:
+ JSON_ASSERT_MESSAGE( value_.real_ >= 0 && value_.real_ <= maxUInt, "Real out of unsigned integer range" );
+ return UInt( value_.real_ );
+ case booleanValue:
+ return value_.bool_ ? 1 : 0;
+ case stringValue:
+ case arrayValue:
+ case objectValue:
+ JSON_ASSERT_MESSAGE( false, "Type is not convertible to uint" );
+ default:
+ JSON_ASSERT_UNREACHABLE;
+ }
+ return 0; // unreachable;
+}
+
+double
+Value::asDouble() const
+{
+ switch ( type_ )
+ {
+ case nullValue:
+ return 0.0;
+ case intValue:
+ return value_.int_;
+ case uintValue:
+ return value_.uint_;
+ case realValue:
+ return value_.real_;
+ case booleanValue:
+ return value_.bool_ ? 1.0 : 0.0;
+ case stringValue:
+ case arrayValue:
+ case objectValue:
+ JSON_ASSERT_MESSAGE( false, "Type is not convertible to double" );
+ default:
+ JSON_ASSERT_UNREACHABLE;
+ }
+ return 0; // unreachable;
+}
+
+bool
+Value::asBool() const
+{
+ switch ( type_ )
+ {
+ case nullValue:
+ return false;
+ case intValue:
+ case uintValue:
+ return value_.int_ != 0;
+ case realValue:
+ return value_.real_ != 0.0;
+ case booleanValue:
+ return value_.bool_;
+ case stringValue:
+ return value_.string_ && value_.string_[0] != 0;
+ case arrayValue:
+ case objectValue:
+ return value_.map_->size() != 0;
+ default:
+ JSON_ASSERT_UNREACHABLE;
+ }
+ return false; // unreachable;
+}
+
+
+bool
+Value::isConvertibleTo( ValueType other ) const
+{
+ switch ( type_ )
+ {
+ case nullValue:
+ return true;
+ case intValue:
+ return ( other == nullValue && value_.int_ == 0 )
+ || other == intValue
+ || ( other == uintValue && value_.int_ >= 0 )
+ || other == realValue
+ || other == stringValue
+ || other == booleanValue;
+ case uintValue:
+ return ( other == nullValue && value_.uint_ == 0 )
+ || ( other == intValue && value_.uint_ <= (unsigned)maxInt )
+ || other == uintValue
+ || other == realValue
+ || other == stringValue
+ || other == booleanValue;
+ case realValue:
+ return ( other == nullValue && value_.real_ == 0.0 )
+ || ( other == intValue && value_.real_ >= minInt && value_.real_ <= maxInt )
+ || ( other == uintValue && value_.real_ >= 0 && value_.real_ <= maxUInt )
+ || other == realValue
+ || other == stringValue
+ || other == booleanValue;
+ case booleanValue:
+ return ( other == nullValue && value_.bool_ == false )
+ || other == intValue
+ || other == uintValue
+ || other == realValue
+ || other == stringValue
+ || other == booleanValue;
+ case stringValue:
+ return other == stringValue
+ || ( other == nullValue && (!value_.string_ || value_.string_[0] == 0) );
+ case arrayValue:
+ return other == arrayValue
+ || ( other == nullValue && value_.map_->size() == 0 );
+ case objectValue:
+ return other == objectValue
+ || ( other == nullValue && value_.map_->size() == 0 );
+ default:
+ JSON_ASSERT_UNREACHABLE;
+ }
+ return false; // unreachable;
+}
+
+
+/// Number of values in array or object
+Value::UInt
+Value::size() const
+{
+ switch ( type_ )
+ {
+ case nullValue:
+ case intValue:
+ case uintValue:
+ case realValue:
+ case booleanValue:
+ case stringValue:
+ return 0;
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+ case arrayValue: // size of the array is highest index + 1
+ if ( !value_.map_->empty() )
+ {
+ ObjectValues::const_iterator itLast = value_.map_->end();
+ --itLast;
+ return (*itLast).first.index()+1;
+ }
+ return 0;
+ case objectValue:
+ return Int( value_.map_->size() );
+#else
+ case arrayValue:
+ return Int( value_.array_->size() );
+ case objectValue:
+ return Int( value_.map_->size() );
+#endif
+ default:
+ JSON_ASSERT_UNREACHABLE;
+ }
+ return 0; // unreachable;
+}
+
+
+bool
+Value::empty() const
+{
+ if ( isNull() || isArray() || isObject() )
+ return size() == 0u;
+ else
+ return false;
+}
+
+
+bool
+Value::operator!() const
+{
+ return isNull();
+}
+
+
+void
+Value::clear()
+{
+ JSON_ASSERT( type_ == nullValue || type_ == arrayValue || type_ == objectValue );
+
+ switch ( type_ )
+ {
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+ case arrayValue:
+ case objectValue:
+ value_.map_->clear();
+ break;
+#else
+ case arrayValue:
+ value_.array_->clear();
+ break;
+ case objectValue:
+ value_.map_->clear();
+ break;
+#endif
+ default:
+ break;
+ }
+}
+
+void
+Value::resize( UInt newSize )
+{
+ JSON_ASSERT( type_ == nullValue || type_ == arrayValue );
+ if ( type_ == nullValue )
+ *this = Value( arrayValue );
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+ UInt oldSize = size();
+ if ( newSize == 0 )
+ clear();
+ else if ( newSize > oldSize )
+ (*this)[ newSize - 1 ];
+ else
+ {
+ for ( UInt index = newSize; index < oldSize; ++index )
+ value_.map_->erase( index );
+ assert( size() == newSize );
+ }
+#else
+ value_.array_->resize( newSize );
+#endif
+}
+
+
+Value &
+Value::operator[]( UInt index )
+{
+ JSON_ASSERT( type_ == nullValue || type_ == arrayValue );
+ if ( type_ == nullValue )
+ *this = Value( arrayValue );
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+ CZString key( index );
+ ObjectValues::iterator it = value_.map_->lower_bound( key );
+ if ( it != value_.map_->end() && (*it).first == key )
+ return (*it).second;
+
+ ObjectValues::value_type defaultValue( key, null );
+ it = value_.map_->insert( it, defaultValue );
+ return (*it).second;
+#else
+ return value_.array_->resolveReference( index );
+#endif
+}
+
+
+const Value &
+Value::operator[]( UInt index ) const
+{
+ JSON_ASSERT( type_ == nullValue || type_ == arrayValue );
+ if ( type_ == nullValue )
+ return null;
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+ CZString key( index );
+ ObjectValues::const_iterator it = value_.map_->find( key );
+ if ( it == value_.map_->end() )
+ return null;
+ return (*it).second;
+#else
+ Value *value = value_.array_->find( index );
+ return value ? *value : null;
+#endif
+}
+
+
+Value &
+Value::operator[]( const char *key )
+{
+ return resolveReference( key, false );
+}
+
+
+Value &
+Value::resolveReference( const char *key,
+ bool isStatic )
+{
+ JSON_ASSERT( type_ == nullValue || type_ == objectValue );
+ if ( type_ == nullValue )
+ *this = Value( objectValue );
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+ CZString actualKey( key, isStatic ? CZString::noDuplication
+ : CZString::duplicateOnCopy );
+ ObjectValues::iterator it = value_.map_->lower_bound( actualKey );
+ if ( it != value_.map_->end() && (*it).first == actualKey )
+ return (*it).second;
+
+ ObjectValues::value_type defaultValue( actualKey, null );
+ it = value_.map_->insert( it, defaultValue );
+ Value &value = (*it).second;
+ return value;
+#else
+ return value_.map_->resolveReference( key, isStatic );
+#endif
+}
+
+
+Value
+Value::get( UInt index,
+ const Value &defaultValue ) const
+{
+ const Value *value = &((*this)[index]);
+ return value == &null ? defaultValue : *value;
+}
+
+
+bool
+Value::isValidIndex( UInt index ) const
+{
+ return index < size();
+}
+
+
+
+const Value &
+Value::operator[]( const char *key ) const
+{
+ JSON_ASSERT( type_ == nullValue || type_ == objectValue );
+ if ( type_ == nullValue )
+ return null;
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+ CZString actualKey( key, CZString::noDuplication );
+ ObjectValues::const_iterator it = value_.map_->find( actualKey );
+ if ( it == value_.map_->end() )
+ return null;
+ return (*it).second;
+#else
+ const Value *value = value_.map_->find( key );
+ return value ? *value : null;
+#endif
+}
+
+
+Value &
+Value::operator[]( const std::string &key )
+{
+ return (*this)[ key.c_str() ];
+}
+
+
+const Value &
+Value::operator[]( const std::string &key ) const
+{
+ return (*this)[ key.c_str() ];
+}
+
+Value &
+Value::operator[]( const StaticString &key )
+{
+ return resolveReference( key, true );
+}
+
+
+# ifdef JSON_USE_CPPTL
+Value &
+Value::operator[]( const CppTL::ConstString &key )
+{
+ return (*this)[ key.c_str() ];
+}
+
+
+const Value &
+Value::operator[]( const CppTL::ConstString &key ) const
+{
+ return (*this)[ key.c_str() ];
+}
+# endif
+
+
+Value &
+Value::append( const Value &value )
+{
+ return (*this)[size()] = value;
+}
+
+
+Value
+Value::get( const char *key,
+ const Value &defaultValue ) const
+{
+ const Value *value = &((*this)[key]);
+ return value == &null ? defaultValue : *value;
+}
+
+
+Value
+Value::get( const std::string &key,
+ const Value &defaultValue ) const
+{
+ return get( key.c_str(), defaultValue );
+}
+
+Value
+Value::removeMember( const char* key )
+{
+ JSON_ASSERT( type_ == nullValue || type_ == objectValue );
+ if ( type_ == nullValue )
+ return null;
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+ CZString actualKey( key, CZString::noDuplication );
+ ObjectValues::iterator it = value_.map_->find( actualKey );
+ if ( it == value_.map_->end() )
+ return null;
+ Value old(it->second);
+ value_.map_->erase(it);
+ return old;
+#else
+ Value *value = value_.map_->find( key );
+ if (value){
+ Value old(*value);
+ value_.map_.remove( key );
+ return old;
+ } else {
+ return null;
+ }
+#endif
+}
+
+Value
+Value::removeMember( const std::string &key )
+{
+ return removeMember( key.c_str() );
+}
+
+# ifdef JSON_USE_CPPTL
+Value
+Value::get( const CppTL::ConstString &key,
+ const Value &defaultValue ) const
+{
+ return get( key.c_str(), defaultValue );
+}
+# endif
+
+bool
+Value::isMember( const char *key ) const
+{
+ const Value *value = &((*this)[key]);
+ return value != &null;
+}
+
+
+bool
+Value::isMember( const std::string &key ) const
+{
+ return isMember( key.c_str() );
+}
+
+
+# ifdef JSON_USE_CPPTL
+bool
+Value::isMember( const CppTL::ConstString &key ) const
+{
+ return isMember( key.c_str() );
+}
+#endif
+
+Value::Members
+Value::getMemberNames() const
+{
+ JSON_ASSERT( type_ == nullValue || type_ == objectValue );
+ if ( type_ == nullValue )
+ return Value::Members();
+ Members members;
+ members.reserve( value_.map_->size() );
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+ ObjectValues::const_iterator it = value_.map_->begin();
+ ObjectValues::const_iterator itEnd = value_.map_->end();
+ for ( ; it != itEnd; ++it )
+ members.push_back( std::string( (*it).first.c_str() ) );
+#else
+ ValueInternalMap::IteratorState it;
+ ValueInternalMap::IteratorState itEnd;
+ value_.map_->makeBeginIterator( it );
+ value_.map_->makeEndIterator( itEnd );
+ for ( ; !ValueInternalMap::equals( it, itEnd ); ValueInternalMap::increment(it) )
+ members.push_back( std::string( ValueInternalMap::key( it ) ) );
+#endif
+ return members;
+}
+//
+//# ifdef JSON_USE_CPPTL
+//EnumMemberNames
+//Value::enumMemberNames() const
+//{
+// if ( type_ == objectValue )
+// {
+// return CppTL::Enum::any( CppTL::Enum::transform(
+// CppTL::Enum::keys( *(value_.map_), CppTL::Type() ),
+// MemberNamesTransform() ) );
+// }
+// return EnumMemberNames();
+//}
+//
+//
+//EnumValues
+//Value::enumValues() const
+//{
+// if ( type_ == objectValue || type_ == arrayValue )
+// return CppTL::Enum::anyValues( *(value_.map_),
+// CppTL::Type() );
+// return EnumValues();
+//}
+//
+//# endif
+
+
+bool
+Value::isNull() const
+{
+ return type_ == nullValue;
+}
+
+
+bool
+Value::isBool() const
+{
+ return type_ == booleanValue;
+}
+
+
+bool
+Value::isInt() const
+{
+ return type_ == intValue;
+}
+
+
+bool
+Value::isUInt() const
+{
+ return type_ == uintValue;
+}
+
+
+bool
+Value::isIntegral() const
+{
+ return type_ == intValue
+ || type_ == uintValue
+ || type_ == booleanValue;
+}
+
+
+bool
+Value::isDouble() const
+{
+ return type_ == realValue;
+}
+
+
+bool
+Value::isNumeric() const
+{
+ return isIntegral() || isDouble();
+}
+
+
+bool
+Value::isString() const
+{
+ return type_ == stringValue;
+}
+
+
+bool
+Value::isArray() const
+{
+ return type_ == nullValue || type_ == arrayValue;
+}
+
+
+bool
+Value::isObject() const
+{
+ return type_ == nullValue || type_ == objectValue;
+}
+
+
+void
+Value::setComment( const char *comment,
+ CommentPlacement placement )
+{
+ if ( !comments_ )
+ comments_ = new CommentInfo[numberOfCommentPlacement];
+ comments_[placement].setComment( comment );
+}
+
+
+void
+Value::setComment( const std::string &comment,
+ CommentPlacement placement )
+{
+ setComment( comment.c_str(), placement );
+}
+
+
+bool
+Value::hasComment( CommentPlacement placement ) const
+{
+ return comments_ != 0 && comments_[placement].comment_ != 0;
+}
+
+std::string
+Value::getComment( CommentPlacement placement ) const
+{
+ if ( hasComment(placement) )
+ return comments_[placement].comment_;
+ return "";
+}
+
+
+std::string
+Value::toStyledString() const
+{
+ StyledWriter writer;
+ return writer.write( *this );
+}
+
+
+Value::const_iterator
+Value::begin() const
+{
+ switch ( type_ )
+ {
+#ifdef JSON_VALUE_USE_INTERNAL_MAP
+ case arrayValue:
+ if ( value_.array_ )
+ {
+ ValueInternalArray::IteratorState it;
+ value_.array_->makeBeginIterator( it );
+ return const_iterator( it );
+ }
+ break;
+ case objectValue:
+ if ( value_.map_ )
+ {
+ ValueInternalMap::IteratorState it;
+ value_.map_->makeBeginIterator( it );
+ return const_iterator( it );
+ }
+ break;
+#else
+ case arrayValue:
+ case objectValue:
+ if ( value_.map_ )
+ return const_iterator( value_.map_->begin() );
+ break;
+#endif
+ default:
+ break;
+ }
+ return const_iterator();
+}
+
+Value::const_iterator
+Value::end() const
+{
+ switch ( type_ )
+ {
+#ifdef JSON_VALUE_USE_INTERNAL_MAP
+ case arrayValue:
+ if ( value_.array_ )
+ {
+ ValueInternalArray::IteratorState it;
+ value_.array_->makeEndIterator( it );
+ return const_iterator( it );
+ }
+ break;
+ case objectValue:
+ if ( value_.map_ )
+ {
+ ValueInternalMap::IteratorState it;
+ value_.map_->makeEndIterator( it );
+ return const_iterator( it );
+ }
+ break;
+#else
+ case arrayValue:
+ case objectValue:
+ if ( value_.map_ )
+ return const_iterator( value_.map_->end() );
+ break;
+#endif
+ default:
+ break;
+ }
+ return const_iterator();
+}
+
+
+Value::iterator
+Value::begin()
+{
+ switch ( type_ )
+ {
+#ifdef JSON_VALUE_USE_INTERNAL_MAP
+ case arrayValue:
+ if ( value_.array_ )
+ {
+ ValueInternalArray::IteratorState it;
+ value_.array_->makeBeginIterator( it );
+ return iterator( it );
+ }
+ break;
+ case objectValue:
+ if ( value_.map_ )
+ {
+ ValueInternalMap::IteratorState it;
+ value_.map_->makeBeginIterator( it );
+ return iterator( it );
+ }
+ break;
+#else
+ case arrayValue:
+ case objectValue:
+ if ( value_.map_ )
+ return iterator( value_.map_->begin() );
+ break;
+#endif
+ default:
+ break;
+ }
+ return iterator();
+}
+
+Value::iterator
+Value::end()
+{
+ switch ( type_ )
+ {
+#ifdef JSON_VALUE_USE_INTERNAL_MAP
+ case arrayValue:
+ if ( value_.array_ )
+ {
+ ValueInternalArray::IteratorState it;
+ value_.array_->makeEndIterator( it );
+ return iterator( it );
+ }
+ break;
+ case objectValue:
+ if ( value_.map_ )
+ {
+ ValueInternalMap::IteratorState it;
+ value_.map_->makeEndIterator( it );
+ return iterator( it );
+ }
+ break;
+#else
+ case arrayValue:
+ case objectValue:
+ if ( value_.map_ )
+ return iterator( value_.map_->end() );
+ break;
+#endif
+ default:
+ break;
+ }
+ return iterator();
+}
+
+
+// class PathArgument
+// //////////////////////////////////////////////////////////////////
+
+PathArgument::PathArgument()
+ : kind_( kindNone )
+{
+}
+
+
+PathArgument::PathArgument( Value::UInt index )
+ : index_( index )
+ , kind_( kindIndex )
+{
+}
+
+
+PathArgument::PathArgument( const char *key )
+ : key_( key )
+ , kind_( kindKey )
+{
+}
+
+
+PathArgument::PathArgument( const std::string &key )
+ : key_( key.c_str() )
+ , kind_( kindKey )
+{
+}
+
+// class Path
+// //////////////////////////////////////////////////////////////////
+
+Path::Path( const std::string &path,
+ const PathArgument &a1,
+ const PathArgument &a2,
+ const PathArgument &a3,
+ const PathArgument &a4,
+ const PathArgument &a5 )
+{
+ InArgs in;
+ in.push_back( &a1 );
+ in.push_back( &a2 );
+ in.push_back( &a3 );
+ in.push_back( &a4 );
+ in.push_back( &a5 );
+ makePath( path, in );
+}
+
+
+void
+Path::makePath( const std::string &path,
+ const InArgs &in )
+{
+ const char *current = path.c_str();
+ const char *end = current + path.length();
+ InArgs::const_iterator itInArg = in.begin();
+ while ( current != end )
+ {
+ if ( *current == '[' )
+ {
+ ++current;
+ if ( *current == '%' )
+ addPathInArg( path, in, itInArg, PathArgument::kindIndex );
+ else
+ {
+ Value::UInt index = 0;
+ for ( ; current != end && *current >= '0' && *current <= '9'; ++current )
+ index = index * 10 + Value::UInt(*current - '0');
+ args_.push_back( index );
+ }
+ if ( current == end || *current++ != ']' )
+ invalidPath( path, int(current - path.c_str()) );
+ }
+ else if ( *current == '%' )
+ {
+ addPathInArg( path, in, itInArg, PathArgument::kindKey );
+ ++current;
+ }
+ else if ( *current == '.' )
+ {
+ ++current;
+ }
+ else
+ {
+ const char *beginName = current;
+ while ( current != end && !strchr( "[.", *current ) )
+ ++current;
+ args_.push_back( std::string( beginName, current ) );
+ }
+ }
+}
+
+
+void
+Path::addPathInArg( const std::string &path,
+ const InArgs &in,
+ InArgs::const_iterator &itInArg,
+ PathArgument::Kind kind )
+{
+ if ( itInArg == in.end() )
+ {
+ // Error: missing argument %d
+ }
+ else if ( (*itInArg)->kind_ != kind )
+ {
+ // Error: bad argument type
+ }
+ else
+ {
+ args_.push_back( **itInArg );
+ }
+}
+
+
+void
+Path::invalidPath( const std::string &path,
+ int location )
+{
+ // Error: invalid path.
+}
+
+
+const Value &
+Path::resolve( const Value &root ) const
+{
+ const Value *node = &root;
+ for ( Args::const_iterator it = args_.begin(); it != args_.end(); ++it )
+ {
+ const PathArgument &arg = *it;
+ if ( arg.kind_ == PathArgument::kindIndex )
+ {
+ if ( !node->isArray() || node->isValidIndex( arg.index_ ) )
+ {
+ // Error: unable to resolve path (array value expected at position...
+ }
+ node = &((*node)[arg.index_]);
+ }
+ else if ( arg.kind_ == PathArgument::kindKey )
+ {
+ if ( !node->isObject() )
+ {
+ // Error: unable to resolve path (object value expected at position...)
+ }
+ node = &((*node)[arg.key_]);
+ if ( node == &Value::null )
+ {
+ // Error: unable to resolve path (object has no member named '' at position...)
+ }
+ }
+ }
+ return *node;
+}
+
+
+Value
+Path::resolve( const Value &root,
+ const Value &defaultValue ) const
+{
+ const Value *node = &root;
+ for ( Args::const_iterator it = args_.begin(); it != args_.end(); ++it )
+ {
+ const PathArgument &arg = *it;
+ if ( arg.kind_ == PathArgument::kindIndex )
+ {
+ if ( !node->isArray() || node->isValidIndex( arg.index_ ) )
+ return defaultValue;
+ node = &((*node)[arg.index_]);
+ }
+ else if ( arg.kind_ == PathArgument::kindKey )
+ {
+ if ( !node->isObject() )
+ return defaultValue;
+ node = &((*node)[arg.key_]);
+ if ( node == &Value::null )
+ return defaultValue;
+ }
+ }
+ return *node;
+}
+
+
+Value &
+Path::make( Value &root ) const
+{
+ Value *node = &root;
+ for ( Args::const_iterator it = args_.begin(); it != args_.end(); ++it )
+ {
+ const PathArgument &arg = *it;
+ if ( arg.kind_ == PathArgument::kindIndex )
+ {
+ if ( !node->isArray() )
+ {
+ // Error: node is not an array at position ...
+ }
+ node = &((*node)[arg.index_]);
+ }
+ else if ( arg.kind_ == PathArgument::kindKey )
+ {
+ if ( !node->isObject() )
+ {
+ // Error: node is not an object at position...
+ }
+ node = &((*node)[arg.key_]);
+ }
+ }
+ return *node;
+}
+
+
+} // namespace Json
diff --git a/src/blackberry10/native/public/json_valueiterator.inl b/src/blackberry10/native/public/json_valueiterator.inl
new file mode 100644
index 00000000..736e260e
--- /dev/null
+++ b/src/blackberry10/native/public/json_valueiterator.inl
@@ -0,0 +1,292 @@
+// included by json_value.cpp
+// everything is within Json namespace
+
+
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// class ValueIteratorBase
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+
+ValueIteratorBase::ValueIteratorBase()
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+ : current_()
+ , isNull_( true )
+{
+}
+#else
+ : isArray_( true )
+ , isNull_( true )
+{
+ iterator_.array_ = ValueInternalArray::IteratorState();
+}
+#endif
+
+
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+ValueIteratorBase::ValueIteratorBase( const Value::ObjectValues::iterator ¤t )
+ : current_( current )
+ , isNull_( false )
+{
+}
+#else
+ValueIteratorBase::ValueIteratorBase( const ValueInternalArray::IteratorState &state )
+ : isArray_( true )
+{
+ iterator_.array_ = state;
+}
+
+
+ValueIteratorBase::ValueIteratorBase( const ValueInternalMap::IteratorState &state )
+ : isArray_( false )
+{
+ iterator_.map_ = state;
+}
+#endif
+
+Value &
+ValueIteratorBase::deref() const
+{
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+ return current_->second;
+#else
+ if ( isArray_ )
+ return ValueInternalArray::dereference( iterator_.array_ );
+ return ValueInternalMap::value( iterator_.map_ );
+#endif
+}
+
+
+void
+ValueIteratorBase::increment()
+{
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+ ++current_;
+#else
+ if ( isArray_ )
+ ValueInternalArray::increment( iterator_.array_ );
+ ValueInternalMap::increment( iterator_.map_ );
+#endif
+}
+
+
+void
+ValueIteratorBase::decrement()
+{
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+ --current_;
+#else
+ if ( isArray_ )
+ ValueInternalArray::decrement( iterator_.array_ );
+ ValueInternalMap::decrement( iterator_.map_ );
+#endif
+}
+
+
+ValueIteratorBase::difference_type
+ValueIteratorBase::computeDistance( const SelfType &other ) const
+{
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+# ifdef JSON_USE_CPPTL_SMALLMAP
+ return current_ - other.current_;
+# else
+ // Iterator for null value are initialized using the default
+ // constructor, which initialize current_ to the default
+ // std::map::iterator. As begin() and end() are two instance
+ // of the default std::map::iterator, they can not be compared.
+ // To allow this, we handle this comparison specifically.
+ if ( isNull_ && other.isNull_ )
+ {
+ return 0;
+ }
+
+
+ // Usage of std::distance is not portable (does not compile with Sun Studio 12 RogueWave STL,
+ // which is the one used by default).
+ // Using a portable hand-made version for non random iterator instead:
+ // return difference_type( std::distance( current_, other.current_ ) );
+ difference_type myDistance = 0;
+ for ( Value::ObjectValues::iterator it = current_; it != other.current_; ++it )
+ {
+ ++myDistance;
+ }
+ return myDistance;
+# endif
+#else
+ if ( isArray_ )
+ return ValueInternalArray::distance( iterator_.array_, other.iterator_.array_ );
+ return ValueInternalMap::distance( iterator_.map_, other.iterator_.map_ );
+#endif
+}
+
+
+bool
+ValueIteratorBase::isEqual( const SelfType &other ) const
+{
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+ if ( isNull_ )
+ {
+ return other.isNull_;
+ }
+ return current_ == other.current_;
+#else
+ if ( isArray_ )
+ return ValueInternalArray::equals( iterator_.array_, other.iterator_.array_ );
+ return ValueInternalMap::equals( iterator_.map_, other.iterator_.map_ );
+#endif
+}
+
+
+void
+ValueIteratorBase::copy( const SelfType &other )
+{
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+ current_ = other.current_;
+#else
+ if ( isArray_ )
+ iterator_.array_ = other.iterator_.array_;
+ iterator_.map_ = other.iterator_.map_;
+#endif
+}
+
+
+Value
+ValueIteratorBase::key() const
+{
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+ const Value::CZString czstring = (*current_).first;
+ if ( czstring.c_str() )
+ {
+ if ( czstring.isStaticString() )
+ return Value( StaticString( czstring.c_str() ) );
+ return Value( czstring.c_str() );
+ }
+ return Value( czstring.index() );
+#else
+ if ( isArray_ )
+ return Value( ValueInternalArray::indexOf( iterator_.array_ ) );
+ bool isStatic;
+ const char *memberName = ValueInternalMap::key( iterator_.map_, isStatic );
+ if ( isStatic )
+ return Value( StaticString( memberName ) );
+ return Value( memberName );
+#endif
+}
+
+
+UInt
+ValueIteratorBase::index() const
+{
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+ const Value::CZString czstring = (*current_).first;
+ if ( !czstring.c_str() )
+ return czstring.index();
+ return Value::UInt( -1 );
+#else
+ if ( isArray_ )
+ return Value::UInt( ValueInternalArray::indexOf( iterator_.array_ ) );
+ return Value::UInt( -1 );
+#endif
+}
+
+
+const char *
+ValueIteratorBase::memberName() const
+{
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+ const char *name = (*current_).first.c_str();
+ return name ? name : "";
+#else
+ if ( !isArray_ )
+ return ValueInternalMap::key( iterator_.map_ );
+ return "";
+#endif
+}
+
+
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// class ValueConstIterator
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+
+ValueConstIterator::ValueConstIterator()
+{
+}
+
+
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+ValueConstIterator::ValueConstIterator( const Value::ObjectValues::iterator ¤t )
+ : ValueIteratorBase( current )
+{
+}
+#else
+ValueConstIterator::ValueConstIterator( const ValueInternalArray::IteratorState &state )
+ : ValueIteratorBase( state )
+{
+}
+
+ValueConstIterator::ValueConstIterator( const ValueInternalMap::IteratorState &state )
+ : ValueIteratorBase( state )
+{
+}
+#endif
+
+ValueConstIterator &
+ValueConstIterator::operator =( const ValueIteratorBase &other )
+{
+ copy( other );
+ return *this;
+}
+
+
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// class ValueIterator
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+
+ValueIterator::ValueIterator()
+{
+}
+
+
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+ValueIterator::ValueIterator( const Value::ObjectValues::iterator ¤t )
+ : ValueIteratorBase( current )
+{
+}
+#else
+ValueIterator::ValueIterator( const ValueInternalArray::IteratorState &state )
+ : ValueIteratorBase( state )
+{
+}
+
+ValueIterator::ValueIterator( const ValueInternalMap::IteratorState &state )
+ : ValueIteratorBase( state )
+{
+}
+#endif
+
+ValueIterator::ValueIterator( const ValueConstIterator &other )
+ : ValueIteratorBase( other )
+{
+}
+
+ValueIterator::ValueIterator( const ValueIterator &other )
+ : ValueIteratorBase( other )
+{
+}
+
+ValueIterator &
+ValueIterator::operator =( const SelfType &other )
+{
+ copy( other );
+ return *this;
+}
diff --git a/src/blackberry10/native/public/json_writer.cpp b/src/blackberry10/native/public/json_writer.cpp
new file mode 100644
index 00000000..cdf4188f
--- /dev/null
+++ b/src/blackberry10/native/public/json_writer.cpp
@@ -0,0 +1,829 @@
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#if _MSC_VER >= 1400 // VC++ 8.0
+#pragma warning( disable : 4996 ) // disable warning about strdup being deprecated.
+#endif
+
+namespace Json {
+
+static bool isControlCharacter(char ch)
+{
+ return ch > 0 && ch <= 0x1F;
+}
+
+static bool containsControlCharacter( const char* str )
+{
+ while ( *str )
+ {
+ if ( isControlCharacter( *(str++) ) )
+ return true;
+ }
+ return false;
+}
+static void uintToString( unsigned int value,
+ char *¤t )
+{
+ *--current = 0;
+ do
+ {
+ *--current = (value % 10) + '0';
+ value /= 10;
+ }
+ while ( value != 0 );
+}
+
+std::string valueToString( Int value )
+{
+ char buffer[32];
+ char *current = buffer + sizeof(buffer);
+ bool isNegative = value < 0;
+ if ( isNegative )
+ value = -value;
+ uintToString( UInt(value), current );
+ if ( isNegative )
+ *--current = '-';
+ assert( current >= buffer );
+ return current;
+}
+
+
+std::string valueToString( UInt value )
+{
+ char buffer[32];
+ char *current = buffer + sizeof(buffer);
+ uintToString( value, current );
+ assert( current >= buffer );
+ return current;
+}
+
+std::string valueToString( double value )
+{
+ char buffer[32];
+#if defined(_MSC_VER) && defined(__STDC_SECURE_LIB__) // Use secure version with visual studio 2005 to avoid warning.
+ sprintf_s(buffer, sizeof(buffer), "%#.16g", value);
+#else
+ sprintf(buffer, "%#.16g", value);
+#endif
+ char* ch = buffer + strlen(buffer) - 1;
+ if (*ch != '0') return buffer; // nothing to truncate, so save time
+ while(ch > buffer && *ch == '0'){
+ --ch;
+ }
+ char* last_nonzero = ch;
+ while(ch >= buffer){
+ switch(*ch){
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ --ch;
+ continue;
+ case '.':
+ // Truncate zeroes to save bytes in output, but keep one.
+ *(last_nonzero+2) = '\0';
+ return buffer;
+ default:
+ return buffer;
+ }
+ }
+ return buffer;
+}
+
+
+std::string valueToString( bool value )
+{
+ return value ? "true" : "false";
+}
+
+std::string valueToQuotedString( const char *value )
+{
+ // Not sure how to handle unicode...
+ if (strpbrk(value, "\"\\\b\f\n\r\t") == NULL && !containsControlCharacter( value ))
+ return std::string("\"") + value + "\"";
+ // We have to walk value and escape any special characters.
+ // Appending to std::string is not efficient, but this should be rare.
+ // (Note: forward slashes are *not* rare, but I am not escaping them.)
+ unsigned maxsize = strlen(value)*2 + 3; // allescaped+quotes+NULL
+ std::string result;
+ result.reserve(maxsize); // to avoid lots of mallocs
+ result += "\"";
+ for (const char* c=value; *c != 0; ++c)
+ {
+ switch(*c)
+ {
+ case '\"':
+ result += "\\\"";
+ break;
+ case '\\':
+ result += "\\\\";
+ break;
+ case '\b':
+ result += "\\b";
+ break;
+ case '\f':
+ result += "\\f";
+ break;
+ case '\n':
+ result += "\\n";
+ break;
+ case '\r':
+ result += "\\r";
+ break;
+ case '\t':
+ result += "\\t";
+ break;
+ //case '/':
+ // Even though \/ is considered a legal escape in JSON, a bare
+ // slash is also legal, so I see no reason to escape it.
+ // (I hope I am not misunderstanding something.
+ // blep notes: actually escaping \/ may be useful in javascript to avoid
+ // sequence.
+ // Should add a flag to allow this compatibility mode and prevent this
+ // sequence from occurring.
+ default:
+ if ( isControlCharacter( *c ) )
+ {
+ std::ostringstream oss;
+ oss << "\\u" << std::hex << std::uppercase << std::setfill('0') << std::setw(4) << static_cast(*c);
+ result += oss.str();
+ }
+ else
+ {
+ result += *c;
+ }
+ break;
+ }
+ }
+ result += "\"";
+ return result;
+}
+
+// Class Writer
+// //////////////////////////////////////////////////////////////////
+Writer::~Writer()
+{
+}
+
+
+// Class FastWriter
+// //////////////////////////////////////////////////////////////////
+
+FastWriter::FastWriter()
+ : yamlCompatiblityEnabled_( false )
+{
+}
+
+
+void
+FastWriter::enableYAMLCompatibility()
+{
+ yamlCompatiblityEnabled_ = true;
+}
+
+
+std::string
+FastWriter::write( const Value &root )
+{
+ document_ = "";
+ writeValue( root );
+ document_ += "\n";
+ return document_;
+}
+
+
+void
+FastWriter::writeValue( const Value &value )
+{
+ switch ( value.type() )
+ {
+ case nullValue:
+ document_ += "null";
+ break;
+ case intValue:
+ document_ += valueToString( value.asInt() );
+ break;
+ case uintValue:
+ document_ += valueToString( value.asUInt() );
+ break;
+ case realValue:
+ document_ += valueToString( value.asDouble() );
+ break;
+ case stringValue:
+ document_ += valueToQuotedString( value.asCString() );
+ break;
+ case booleanValue:
+ document_ += valueToString( value.asBool() );
+ break;
+ case arrayValue:
+ {
+ document_ += "[";
+ int size = value.size();
+ for ( int index =0; index < size; ++index )
+ {
+ if ( index > 0 )
+ document_ += ",";
+ writeValue( value[index] );
+ }
+ document_ += "]";
+ }
+ break;
+ case objectValue:
+ {
+ Value::Members members( value.getMemberNames() );
+ document_ += "{";
+ for ( Value::Members::iterator it = members.begin();
+ it != members.end();
+ ++it )
+ {
+ const std::string &name = *it;
+ if ( it != members.begin() )
+ document_ += ",";
+ document_ += valueToQuotedString( name.c_str() );
+ document_ += yamlCompatiblityEnabled_ ? ": "
+ : ":";
+ writeValue( value[name] );
+ }
+ document_ += "}";
+ }
+ break;
+ }
+}
+
+
+// Class StyledWriter
+// //////////////////////////////////////////////////////////////////
+
+StyledWriter::StyledWriter()
+ : rightMargin_( 74 )
+ , indentSize_( 3 )
+{
+}
+
+
+std::string
+StyledWriter::write( const Value &root )
+{
+ document_ = "";
+ addChildValues_ = false;
+ indentString_ = "";
+ writeCommentBeforeValue( root );
+ writeValue( root );
+ writeCommentAfterValueOnSameLine( root );
+ document_ += "\n";
+ return document_;
+}
+
+
+void
+StyledWriter::writeValue( const Value &value )
+{
+ switch ( value.type() )
+ {
+ case nullValue:
+ pushValue( "null" );
+ break;
+ case intValue:
+ pushValue( valueToString( value.asInt() ) );
+ break;
+ case uintValue:
+ pushValue( valueToString( value.asUInt() ) );
+ break;
+ case realValue:
+ pushValue( valueToString( value.asDouble() ) );
+ break;
+ case stringValue:
+ pushValue( valueToQuotedString( value.asCString() ) );
+ break;
+ case booleanValue:
+ pushValue( valueToString( value.asBool() ) );
+ break;
+ case arrayValue:
+ writeArrayValue( value);
+ break;
+ case objectValue:
+ {
+ Value::Members members( value.getMemberNames() );
+ if ( members.empty() )
+ pushValue( "{}" );
+ else
+ {
+ writeWithIndent( "{" );
+ indent();
+ Value::Members::iterator it = members.begin();
+ while ( true )
+ {
+ const std::string &name = *it;
+ const Value &childValue = value[name];
+ writeCommentBeforeValue( childValue );
+ writeWithIndent( valueToQuotedString( name.c_str() ) );
+ document_ += " : ";
+ writeValue( childValue );
+ if ( ++it == members.end() )
+ {
+ writeCommentAfterValueOnSameLine( childValue );
+ break;
+ }
+ document_ += ",";
+ writeCommentAfterValueOnSameLine( childValue );
+ }
+ unindent();
+ writeWithIndent( "}" );
+ }
+ }
+ break;
+ }
+}
+
+
+void
+StyledWriter::writeArrayValue( const Value &value )
+{
+ unsigned size = value.size();
+ if ( size == 0 )
+ pushValue( "[]" );
+ else
+ {
+ bool isArrayMultiLine = isMultineArray( value );
+ if ( isArrayMultiLine )
+ {
+ writeWithIndent( "[" );
+ indent();
+ bool hasChildValue = !childValues_.empty();
+ unsigned index =0;
+ while ( true )
+ {
+ const Value &childValue = value[index];
+ writeCommentBeforeValue( childValue );
+ if ( hasChildValue )
+ writeWithIndent( childValues_[index] );
+ else
+ {
+ writeIndent();
+ writeValue( childValue );
+ }
+ if ( ++index == size )
+ {
+ writeCommentAfterValueOnSameLine( childValue );
+ break;
+ }
+ document_ += ",";
+ writeCommentAfterValueOnSameLine( childValue );
+ }
+ unindent();
+ writeWithIndent( "]" );
+ }
+ else // output on a single line
+ {
+ assert( childValues_.size() == size );
+ document_ += "[ ";
+ for ( unsigned index =0; index < size; ++index )
+ {
+ if ( index > 0 )
+ document_ += ", ";
+ document_ += childValues_[index];
+ }
+ document_ += " ]";
+ }
+ }
+}
+
+
+bool
+StyledWriter::isMultineArray( const Value &value )
+{
+ int size = value.size();
+ bool isMultiLine = size*3 >= rightMargin_ ;
+ childValues_.clear();
+ for ( int index =0; index < size && !isMultiLine; ++index )
+ {
+ const Value &childValue = value[index];
+ isMultiLine = isMultiLine ||
+ ( (childValue.isArray() || childValue.isObject()) &&
+ childValue.size() > 0 );
+ }
+ if ( !isMultiLine ) // check if line length > max line length
+ {
+ childValues_.reserve( size );
+ addChildValues_ = true;
+ int lineLength = 4 + (size-1)*2; // '[ ' + ', '*n + ' ]'
+ for ( int index =0; index < size && !isMultiLine; ++index )
+ {
+ writeValue( value[index] );
+ lineLength += int( childValues_[index].length() );
+ isMultiLine = isMultiLine && hasCommentForValue( value[index] );
+ }
+ addChildValues_ = false;
+ isMultiLine = isMultiLine || lineLength >= rightMargin_;
+ }
+ return isMultiLine;
+}
+
+
+void
+StyledWriter::pushValue( const std::string &value )
+{
+ if ( addChildValues_ )
+ childValues_.push_back( value );
+ else
+ document_ += value;
+}
+
+
+void
+StyledWriter::writeIndent()
+{
+ if ( !document_.empty() )
+ {
+ char last = document_[document_.length()-1];
+ if ( last == ' ' ) // already indented
+ return;
+ if ( last != '\n' ) // Comments may add new-line
+ document_ += '\n';
+ }
+ document_ += indentString_;
+}
+
+
+void
+StyledWriter::writeWithIndent( const std::string &value )
+{
+ writeIndent();
+ document_ += value;
+}
+
+
+void
+StyledWriter::indent()
+{
+ indentString_ += std::string( indentSize_, ' ' );
+}
+
+
+void
+StyledWriter::unindent()
+{
+ assert( int(indentString_.size()) >= indentSize_ );
+ indentString_.resize( indentString_.size() - indentSize_ );
+}
+
+
+void
+StyledWriter::writeCommentBeforeValue( const Value &root )
+{
+ if ( !root.hasComment( commentBefore ) )
+ return;
+ document_ += normalizeEOL( root.getComment( commentBefore ) );
+ document_ += "\n";
+}
+
+
+void
+StyledWriter::writeCommentAfterValueOnSameLine( const Value &root )
+{
+ if ( root.hasComment( commentAfterOnSameLine ) )
+ document_ += " " + normalizeEOL( root.getComment( commentAfterOnSameLine ) );
+
+ if ( root.hasComment( commentAfter ) )
+ {
+ document_ += "\n";
+ document_ += normalizeEOL( root.getComment( commentAfter ) );
+ document_ += "\n";
+ }
+}
+
+
+bool
+StyledWriter::hasCommentForValue( const Value &value )
+{
+ return value.hasComment( commentBefore )
+ || value.hasComment( commentAfterOnSameLine )
+ || value.hasComment( commentAfter );
+}
+
+
+std::string
+StyledWriter::normalizeEOL( const std::string &text )
+{
+ std::string normalized;
+ normalized.reserve( text.length() );
+ const char *begin = text.c_str();
+ const char *end = begin + text.length();
+ const char *current = begin;
+ while ( current != end )
+ {
+ char c = *current++;
+ if ( c == '\r' ) // mac or dos EOL
+ {
+ if ( *current == '\n' ) // convert dos EOL
+ ++current;
+ normalized += '\n';
+ }
+ else // handle unix EOL & other char
+ normalized += c;
+ }
+ return normalized;
+}
+
+
+// Class StyledStreamWriter
+// //////////////////////////////////////////////////////////////////
+
+StyledStreamWriter::StyledStreamWriter( std::string indentation )
+ : document_(NULL)
+ , rightMargin_( 74 )
+ , indentation_( indentation )
+{
+}
+
+
+void
+StyledStreamWriter::write( std::ostream &out, const Value &root )
+{
+ document_ = &out;
+ addChildValues_ = false;
+ indentString_ = "";
+ writeCommentBeforeValue( root );
+ writeValue( root );
+ writeCommentAfterValueOnSameLine( root );
+ *document_ << "\n";
+ document_ = NULL; // Forget the stream, for safety.
+}
+
+
+void
+StyledStreamWriter::writeValue( const Value &value )
+{
+ switch ( value.type() )
+ {
+ case nullValue:
+ pushValue( "null" );
+ break;
+ case intValue:
+ pushValue( valueToString( value.asInt() ) );
+ break;
+ case uintValue:
+ pushValue( valueToString( value.asUInt() ) );
+ break;
+ case realValue:
+ pushValue( valueToString( value.asDouble() ) );
+ break;
+ case stringValue:
+ pushValue( valueToQuotedString( value.asCString() ) );
+ break;
+ case booleanValue:
+ pushValue( valueToString( value.asBool() ) );
+ break;
+ case arrayValue:
+ writeArrayValue( value);
+ break;
+ case objectValue:
+ {
+ Value::Members members( value.getMemberNames() );
+ if ( members.empty() )
+ pushValue( "{}" );
+ else
+ {
+ writeWithIndent( "{" );
+ indent();
+ Value::Members::iterator it = members.begin();
+ while ( true )
+ {
+ const std::string &name = *it;
+ const Value &childValue = value[name];
+ writeCommentBeforeValue( childValue );
+ writeWithIndent( valueToQuotedString( name.c_str() ) );
+ *document_ << " : ";
+ writeValue( childValue );
+ if ( ++it == members.end() )
+ {
+ writeCommentAfterValueOnSameLine( childValue );
+ break;
+ }
+ *document_ << ",";
+ writeCommentAfterValueOnSameLine( childValue );
+ }
+ unindent();
+ writeWithIndent( "}" );
+ }
+ }
+ break;
+ }
+}
+
+
+void
+StyledStreamWriter::writeArrayValue( const Value &value )
+{
+ unsigned size = value.size();
+ if ( size == 0 )
+ pushValue( "[]" );
+ else
+ {
+ bool isArrayMultiLine = isMultineArray( value );
+ if ( isArrayMultiLine )
+ {
+ writeWithIndent( "[" );
+ indent();
+ bool hasChildValue = !childValues_.empty();
+ unsigned index =0;
+ while ( true )
+ {
+ const Value &childValue = value[index];
+ writeCommentBeforeValue( childValue );
+ if ( hasChildValue )
+ writeWithIndent( childValues_[index] );
+ else
+ {
+ writeIndent();
+ writeValue( childValue );
+ }
+ if ( ++index == size )
+ {
+ writeCommentAfterValueOnSameLine( childValue );
+ break;
+ }
+ *document_ << ",";
+ writeCommentAfterValueOnSameLine( childValue );
+ }
+ unindent();
+ writeWithIndent( "]" );
+ }
+ else // output on a single line
+ {
+ assert( childValues_.size() == size );
+ *document_ << "[ ";
+ for ( unsigned index =0; index < size; ++index )
+ {
+ if ( index > 0 )
+ *document_ << ", ";
+ *document_ << childValues_[index];
+ }
+ *document_ << " ]";
+ }
+ }
+}
+
+
+bool
+StyledStreamWriter::isMultineArray( const Value &value )
+{
+ int size = value.size();
+ bool isMultiLine = size*3 >= rightMargin_ ;
+ childValues_.clear();
+ for ( int index =0; index < size && !isMultiLine; ++index )
+ {
+ const Value &childValue = value[index];
+ isMultiLine = isMultiLine ||
+ ( (childValue.isArray() || childValue.isObject()) &&
+ childValue.size() > 0 );
+ }
+ if ( !isMultiLine ) // check if line length > max line length
+ {
+ childValues_.reserve( size );
+ addChildValues_ = true;
+ int lineLength = 4 + (size-1)*2; // '[ ' + ', '*n + ' ]'
+ for ( int index =0; index < size && !isMultiLine; ++index )
+ {
+ writeValue( value[index] );
+ lineLength += int( childValues_[index].length() );
+ isMultiLine = isMultiLine && hasCommentForValue( value[index] );
+ }
+ addChildValues_ = false;
+ isMultiLine = isMultiLine || lineLength >= rightMargin_;
+ }
+ return isMultiLine;
+}
+
+
+void
+StyledStreamWriter::pushValue( const std::string &value )
+{
+ if ( addChildValues_ )
+ childValues_.push_back( value );
+ else
+ *document_ << value;
+}
+
+
+void
+StyledStreamWriter::writeIndent()
+{
+ /*
+ Some comments in this method would have been nice. ;-)
+
+ if ( !document_.empty() )
+ {
+ char last = document_[document_.length()-1];
+ if ( last == ' ' ) // already indented
+ return;
+ if ( last != '\n' ) // Comments may add new-line
+ *document_ << '\n';
+ }
+ */
+ *document_ << '\n' << indentString_;
+}
+
+
+void
+StyledStreamWriter::writeWithIndent( const std::string &value )
+{
+ writeIndent();
+ *document_ << value;
+}
+
+
+void
+StyledStreamWriter::indent()
+{
+ indentString_ += indentation_;
+}
+
+
+void
+StyledStreamWriter::unindent()
+{
+ assert( indentString_.size() >= indentation_.size() );
+ indentString_.resize( indentString_.size() - indentation_.size() );
+}
+
+
+void
+StyledStreamWriter::writeCommentBeforeValue( const Value &root )
+{
+ if ( !root.hasComment( commentBefore ) )
+ return;
+ *document_ << normalizeEOL( root.getComment( commentBefore ) );
+ *document_ << "\n";
+}
+
+
+void
+StyledStreamWriter::writeCommentAfterValueOnSameLine( const Value &root )
+{
+ if ( root.hasComment( commentAfterOnSameLine ) )
+ *document_ << " " + normalizeEOL( root.getComment( commentAfterOnSameLine ) );
+
+ if ( root.hasComment( commentAfter ) )
+ {
+ *document_ << "\n";
+ *document_ << normalizeEOL( root.getComment( commentAfter ) );
+ *document_ << "\n";
+ }
+}
+
+
+bool
+StyledStreamWriter::hasCommentForValue( const Value &value )
+{
+ return value.hasComment( commentBefore )
+ || value.hasComment( commentAfterOnSameLine )
+ || value.hasComment( commentAfter );
+}
+
+
+std::string
+StyledStreamWriter::normalizeEOL( const std::string &text )
+{
+ std::string normalized;
+ normalized.reserve( text.length() );
+ const char *begin = text.c_str();
+ const char *end = begin + text.length();
+ const char *current = begin;
+ while ( current != end )
+ {
+ char c = *current++;
+ if ( c == '\r' ) // mac or dos EOL
+ {
+ if ( *current == '\n' ) // convert dos EOL
+ ++current;
+ normalized += '\n';
+ }
+ else // handle unix EOL & other char
+ normalized += c;
+ }
+ return normalized;
+}
+
+
+std::ostream& operator<<( std::ostream &sout, const Value &root )
+{
+ Json::StyledStreamWriter writer;
+ writer.write(sout, root);
+ return sout;
+}
+
+
+} // namespace Json
diff --git a/src/blackberry10/native/public/plugin.cpp b/src/blackberry10/native/public/plugin.cpp
new file mode 100644
index 00000000..6906275e
--- /dev/null
+++ b/src/blackberry10/native/public/plugin.cpp
@@ -0,0 +1,320 @@
+#include "plugin.h"
+#include "tokenizer.h"
+
+#ifdef _WINDOWS
+#include
+BOOL APIENTRY DllMain( HANDLE hModule,
+ DWORD ul_reason_for_call,
+ LPVOID lpReserved )
+{
+ return TRUE;
+}
+#else
+#include
+#include
+
+extern int errno;
+#endif
+
+SendPluginEv SendPluginEvent;
+
+string g_GetSysErrMsg( void )
+{
+ string strError = "Unknown";
+ // Problem loading
+#ifdef _WINDOWS
+ int nErrorCode = GetLastError();
+ LPTSTR s;
+ if ( ::FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
+ NULL, nErrorCode, 0, ( LPTSTR ) &s, 0, NULL ) )
+ {
+ strError = s;
+ }
+ else
+ {
+ char szBuf[ 20 ];
+ _snprintf_s( szBuf, _countof(szBuf), 19, "%d", nErrorCode );
+ strError = szBuf;
+ }
+#else
+ char szError[80];
+ if ( strerror_r( errno, szError, sizeof(szError) ) )
+ {
+ strError = "no description found";
+ }
+ else
+ {
+ strError = szError;
+ }
+#endif
+ return strError;
+}
+
+void g_sleep( unsigned int mseconds )
+{
+#ifdef _WINDOWS
+ Sleep( mseconds );
+#else
+ usleep( mseconds * 1000 );
+#endif
+}
+
+string& g_trim( string& str )
+{
+ // Whitespace characters
+ char whspc[] = " \t\r\n\v\f";
+
+ // Whack off first part
+ size_t pos = str.find_first_not_of( whspc );
+
+ if ( pos != string::npos )
+ str.replace( 0, pos, "" );
+
+ // Whack off trailing stuff
+ pos = str.find_last_not_of( whspc );
+
+ if ( pos != string::npos )
+ str.replace( pos + 1, str.length() - pos, "" );
+
+ return str;
+}
+
+void g_tokenize( const string& str, const string& delimiters, vector& tokens )
+{
+ tokenize( str, tokens, delimiters );
+}
+
+char* SetEventFunc( SendPluginEv funcPtr )
+{
+ static char * szObjList = onGetObjList();
+ SendPluginEvent = funcPtr;
+ return szObjList;
+}
+
+
+const int nMAXSIZE = 512;
+char* g_pszRetVal = NULL;
+
+//-----------------------------------------------------------
+// Map from an object Id to an object instance
+//-----------------------------------------------------------
+typedef std::map StringToJExt_T;
+
+//-----------------------------------------------------------
+// Map from a browser context to an id mapping
+//-----------------------------------------------------------
+typedef std::map VoidToMap_T;
+
+VoidToMap_T g_context2Map;
+
+class GlobalSharedModule
+{
+
+public:
+ GlobalSharedModule( void )
+ {
+ g_pszRetVal = new char[ nMAXSIZE ];
+ }
+
+ ~GlobalSharedModule()
+ {
+ delete [] g_pszRetVal;
+
+ VoidToMap_T::iterator posMaps;
+
+ for ( posMaps = g_context2Map.begin(); posMaps != g_context2Map.end(); ++posMaps )
+ {
+ StringToJExt_T& id2Obj = *posMaps->second;
+ StringToJExt_T::iterator posMap;
+
+ for ( posMap = id2Obj.begin(); posMap != id2Obj.end(); ++posMap )
+ {
+ JSExt* pJSExt = posMap->second;
+
+ if ( pJSExt->CanDelete() )
+ {
+ delete pJSExt;
+ }
+ }
+
+ id2Obj.erase( id2Obj.begin(), id2Obj.end() );
+ }
+
+ g_context2Map.erase( g_context2Map.begin(), g_context2Map.end() );
+ }
+};
+
+GlobalSharedModule g_sharedModule;
+
+char* g_str2global( const string& strRetVal )
+{
+ int nLen = strRetVal.size();
+
+ if ( nLen >= nMAXSIZE )
+ {
+ delete [] g_pszRetVal;
+ g_pszRetVal = new char[ nLen + 1 ];
+ }
+
+ else
+ {
+ // To minimaize the number of memory reallocations, the assumption
+ // is that in most times this will be the case
+ delete [] g_pszRetVal;
+ g_pszRetVal = new char[ nMAXSIZE ];
+ }
+
+ strcpy( g_pszRetVal, strRetVal.c_str() );
+ return g_pszRetVal;
+}
+
+bool g_unregisterObject( const string& strObjId, void* pContext )
+{
+ // Called by the plugin extension implementation
+ // if the extension handles the deletion of its object
+
+ StringToJExt_T * pID2Obj = NULL;
+
+ VoidToMap_T::iterator iter = g_context2Map.find( pContext );
+
+ if ( iter != g_context2Map.end() )
+ {
+ pID2Obj = iter->second;
+ }
+ else
+ {
+ return false;
+ }
+
+ StringToJExt_T& mapID2Obj = *pID2Obj;
+
+ StringToJExt_T::iterator r = mapID2Obj.find( strObjId );
+
+ if ( r == mapID2Obj.end() )
+ {
+ return false;
+ }
+
+ mapID2Obj.erase( strObjId );
+ return true;
+}
+
+char* InvokeFunction( const char* szCommand, void* pContext )
+{
+ StringToJExt_T * pID2Obj = NULL;
+
+ VoidToMap_T::iterator iter = g_context2Map.find( pContext );
+
+ if ( iter != g_context2Map.end() )
+ {
+ pID2Obj = iter->second;
+ }
+ else
+ {
+ pID2Obj = new StringToJExt_T;
+ g_context2Map[ pContext ] = pID2Obj;
+ }
+
+ StringToJExt_T& mapID2Obj = *pID2Obj;
+
+ string strFullCommand = szCommand;
+ vector arParams;
+ g_tokenize( strFullCommand, " ", arParams );
+ string strCommand = arParams[ 0 ];
+ string strRetVal = szERROR;
+
+ if ( strCommand == szCREATE )
+ {
+ string strClassName = arParams[ 1 ];
+ string strObjId = arParams[ 2 ];
+
+ StringToJExt_T::iterator r = mapID2Obj.find( strObjId );
+
+ if ( r != mapID2Obj.end() )
+ {
+ strRetVal += strObjId;
+ strRetVal += " :Object already exists.";
+ return g_str2global( strRetVal );
+ }
+
+ JSExt* pJSExt = onCreateObject( strClassName, strObjId );
+
+ if ( pJSExt == NULL )
+ {
+ strRetVal += strObjId;
+ strRetVal += " :Unknown object type ";
+ strRetVal += strClassName;
+ return g_str2global( strRetVal );
+ }
+
+ pJSExt->m_pContext = pContext;
+ mapID2Obj[ strObjId ] = pJSExt;
+
+ strRetVal = szOK;
+ strRetVal += strObjId;
+ return g_str2global( strRetVal );
+ }
+ else
+ if ( strCommand == szINVOKE )
+ {
+ string strObjId = arParams[ 1 ];
+ string strMethod = arParams[ 2 ];
+
+ StringToJExt_T::iterator r = mapID2Obj.find( strObjId );
+
+ if ( r == mapID2Obj.end() )
+ {
+ strRetVal += strObjId;
+ strRetVal += " :No object found for id.";
+ return g_str2global( strRetVal );
+ }
+
+ JSExt* pJSExt = r->second;
+
+ size_t nLoc = strFullCommand.find( strObjId );
+
+ if ( nLoc == string::npos )
+ {
+ strRetVal += strObjId;
+ strRetVal += " :Internal InvokeMethod error.";
+ return g_str2global( strRetVal );
+ }
+
+ if ( strMethod == szDISPOSE )
+ {
+ StringToJExt_T::iterator r = mapID2Obj.find( strObjId );
+
+ if ( r == mapID2Obj.end() )
+ {
+ strRetVal = szERROR;
+ strRetVal += strObjId;
+ return g_str2global( strRetVal );
+ }
+
+ JSExt * pJSExt = mapID2Obj[ strObjId ];
+
+ if ( pJSExt->CanDelete() )
+ {
+ delete pJSExt;
+ }
+
+ mapID2Obj.erase( strObjId );
+ strRetVal = szOK;
+ strRetVal += strObjId;
+ return g_str2global( strRetVal );
+ }
+
+ size_t nSuffixLoc = nLoc + strObjId.size();
+ string strInvoke = strFullCommand.substr( nSuffixLoc );
+ strInvoke = g_trim( strInvoke );
+ strRetVal = pJSExt->InvokeMethod( strInvoke );
+ return g_str2global( strRetVal );
+ }
+
+ strRetVal += " :Unknown command ";
+ strRetVal += strCommand;
+ return g_str2global( strRetVal );
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
diff --git a/src/blackberry10/native/public/plugin.h b/src/blackberry10/native/public/plugin.h
new file mode 100644
index 00000000..4ef71169
--- /dev/null
+++ b/src/blackberry10/native/public/plugin.h
@@ -0,0 +1,70 @@
+#ifndef _PLUGIN_H
+#define _PLUGIN_H
+
+#include
+#include
+#include
+#include
+//#include "tokenizer.h"
+
+using namespace std;
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+//%% Functions exported by this DLL
+//%% Should always be only SetEventFunc and InvokeFunction
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+// g++ requires extern "C" otherwise the names of SetEventFunc and InvokeFunction
+// are mangled C++ style. MS Visual Studio doesn't seem to care though.
+extern "C"
+{
+ typedef void (*SendPluginEv)( const char* szEvent, void* pContext );
+ char* SetEventFunc(SendPluginEv funcPtr);
+ char* InvokeFunction( const char* szCommand, void* pContext );
+}
+
+// JNEXT Framework function of the form:
+// typedef void (*SendPluginEv)( const char* szEvent );
+// used to notify JavaScript of an asynchronous event
+extern SendPluginEv SendPluginEvent;
+
+/////////////////////////////////////////////////////////////////////////
+// Constants and methods common to all JNEXT extensions types
+/////////////////////////////////////////////////////////////////////////
+#define szERROR "Error "
+#define szOK "Ok "
+
+#define szDISPOSE "Dispose"
+#define szINVOKE "InvokeMethod"
+#define szCREATE "CreateObj"
+
+/////////////////////////////////////////////////////////////////////////
+// Utility functions
+/////////////////////////////////////////////////////////////////////////
+string& g_trim( string& str );
+void g_tokenize(const string& str,const string& delimiters, vector& tokens);
+char* g_str2static( const string& strRetVal );
+void g_sleep( unsigned int mseconds );
+bool g_unregisterObject( const string& strObjId, void* pContext );
+
+
+/////////////////////////////////////////////////////////////////////////
+// Abstract extension object
+/////////////////////////////////////////////////////////////////////////
+class JSExt
+{
+public:
+ virtual ~JSExt() {};
+ virtual string InvokeMethod( const string& strCommand ) = 0;
+ virtual bool CanDelete( void ) = 0;
+ virtual void TryDelete( void ) {}
+public:
+ void* m_pContext;
+};
+
+/////////////////////////////////////////////////////////////////////////
+// Callback functions to be implemented by the plugin implementation
+/////////////////////////////////////////////////////////////////////////
+extern char* onGetObjList( void );
+extern JSExt* onCreateObject( const string& strClassName, const string& strObjId );
+
+#endif
diff --git a/src/blackberry10/native/public/tokenizer.cpp b/src/blackberry10/native/public/tokenizer.cpp
new file mode 100644
index 00000000..4a39573b
--- /dev/null
+++ b/src/blackberry10/native/public/tokenizer.cpp
@@ -0,0 +1,222 @@
+/************************************************************************
+The zlib/libpng License
+
+Copyright (c) 2006 Joerg Wiedenmann
+
+This software is provided 'as-is', without any express or implied warranty.
+In no event will the authors be held liable for any damages arising from
+the use of this software.
+
+Permission is granted to anyone to use this software for any purpose,
+including commercial applications, and to alter it and redistribute it
+freely, subject to the following restrictions:
+
+1. The origin of this software must not be misrepresented;
+you must not claim that you wrote the original software.
+If you use this software in a product, an acknowledgment
+in the product documentation would be appreciated but is
+not required.
+
+2. Altered source versions must be plainly marked as such,
+and must not be misrepresented as being the original software.
+
+3. This notice may not be removed or altered from any source distribution.
+
+***********************************************************************/
+
+/********************************************************************
+ created: 2006-01-28
+ filename: tokenizer.cpp
+ author: Jörg Wiedenmann
+
+ purpose: A tokenizer function which provides a very
+ customizable way of breaking up strings.
+
+ history: 2006-01-28, Original version
+ 2006-03-04, Fixed a small parsing bug, thanks Elias.
+*********************************************************************/
+
+#include "tokenizer.h"
+
+using namespace std;
+
+void tokenize ( const string& str, vector& result,
+ const string& delimiters, const string& delimiters_preserve,
+ const string& quote, const string& esc )
+{
+ // clear the vector
+ if ( false == result.empty() )
+ {
+ result.clear();
+ }
+
+ string::size_type pos = 0; // the current position (char) in the string
+ char ch = 0; // buffer for the current character
+ char delimiter = 0; // the buffer for the delimiter char which
+ // will be added to the tokens if the delimiter
+ // is preserved
+ char current_quote = 0; // the char of the current open quote
+ bool quoted = false; // indicator if there is an open quote
+ string token; // string buffer for the token
+ bool token_complete = false; // indicates if the current token is
+ // read to be added to the result vector
+ string::size_type len = str.length(); // length of the input-string
+
+ // for every char in the input-string
+ while ( len > pos )
+ {
+ // get the character of the string and reset the delimiter buffer
+ ch = str.at(pos);
+ delimiter = 0;
+
+ // assume ch isn't a delimiter
+ bool add_char = true;
+
+ // check ...
+
+ // ... if the delimiter is an escaped character
+ bool escaped = false; // indicates if the next char is protected
+ if ( false == esc.empty() ) // check if esc-chars are provided
+ {
+ if ( string::npos != esc.find_first_of(ch) )
+ {
+ // get the escaped char
+ ++pos;
+ if ( pos < len ) // if there are more chars left
+ {
+ // get the next one
+ ch = str.at(pos);
+
+ // add the escaped character to the token
+ add_char = true;
+ }
+ else // cannot get any more characters
+ {
+ // don't add the esc-char
+ add_char = false;
+ }
+
+ // ignore the remaining delimiter checks
+ escaped = true;
+ }
+ }
+
+ // ... if the delimiter is a quote
+ if ( false == quote.empty() && false == escaped )
+ {
+ // if quote chars are provided and the char isn't protected
+ if ( string::npos != quote.find_first_of(ch) )
+ {
+ // if not quoted, set state to open quote and set
+ // the quote character
+ if ( false == quoted )
+ {
+ quoted = true;
+ current_quote = ch;
+
+ // don't add the quote-char to the token
+ add_char = false;
+ }
+ else // if quote is open already
+ {
+ // check if it is the matching character to close it
+ if ( current_quote == ch )
+ {
+ // close quote and reset the quote character
+ quoted = false;
+ current_quote = 0;
+
+ // don't add the quote-char to the token
+ add_char = false;
+ }
+ } // else
+ }
+ }
+
+ // ... if the delimiter isn't preserved
+ if ( false == delimiters.empty() && false == escaped &&
+ false == quoted )
+ {
+ // if a delimiter is provided and the char isn't protected by
+ // quote or escape char
+ if ( string::npos != delimiters.find_first_of(ch) )
+ {
+ // if ch is a delimiter and the token string isn't empty
+ // the token is complete
+ if ( false == token.empty() ) // BUGFIX: 2006-03-04
+ {
+ token_complete = true;
+ }
+
+ // don't add the delimiter to the token
+ add_char = false;
+ }
+ }
+
+ // ... if the delimiter is preserved - add it as a token
+ bool add_delimiter = false;
+ if ( false == delimiters_preserve.empty() && false == escaped &&
+ false == quoted )
+ {
+ // if a delimiter which will be preserved is provided and the
+ // char isn't protected by quote or escape char
+ if ( string::npos != delimiters_preserve.find_first_of(ch) )
+ {
+ // if ch is a delimiter and the token string isn't empty
+ // the token is complete
+ if ( false == token.empty() ) // BUGFIX: 2006-03-04
+ {
+ token_complete = true;
+ }
+
+ // don't add the delimiter to the token
+ add_char = false;
+
+ // add the delimiter
+ delimiter = ch;
+ add_delimiter = true;
+ }
+ }
+
+
+ // add the character to the token
+ if ( true == add_char )
+ {
+ // add the current char
+ token.push_back( ch );
+ }
+
+ // add the token if it is complete
+ if ( true == token_complete && false == token.empty() )
+ {
+ // add the token string
+ result.push_back( token );
+
+ // clear the contents
+ token.clear();
+
+ // build the next token
+ token_complete = false;
+ }
+
+ // add the delimiter
+ if ( true == add_delimiter )
+ {
+ // the next token is the delimiter
+ string delim_token;
+ delim_token.push_back( delimiter );
+ result.push_back( delim_token );
+
+ // REMOVED: 2006-03-04, Bugfix
+ }
+
+ // repeat for the next character
+ ++pos;
+ } // while
+
+ // add the final token
+ if ( false == token.empty() )
+ {
+ result.push_back( token );
+ }
+}
diff --git a/src/blackberry10/native/public/tokenizer.h b/src/blackberry10/native/public/tokenizer.h
new file mode 100644
index 00000000..75f567ce
--- /dev/null
+++ b/src/blackberry10/native/public/tokenizer.h
@@ -0,0 +1,55 @@
+/************************************************************************
+The zlib/libpng License
+
+Copyright (c) 2006 Joerg Wiedenmann
+
+This software is provided 'as-is', without any express or implied warranty.
+In no event will the authors be held liable for any damages arising from
+the use of this software.
+
+Permission is granted to anyone to use this software for any purpose,
+including commercial applications, and to alter it and redistribute it
+freely, subject to the following restrictions:
+
+1. The origin of this software must not be misrepresented;
+ you must not claim that you wrote the original software.
+ If you use this software in a product, an acknowledgment
+ in the product documentation would be appreciated but is
+ not required.
+
+2. Altered source versions must be plainly marked as such,
+ and must not be misrepresented as being the original software.
+
+3. This notice may not be removed or altered from any source distribution.
+
+***********************************************************************/
+
+/********************************************************************
+ created: 2006-01-28
+ filename: tokenizer.cpp
+ author: Jörg Wiedenmann
+
+ purpose: A tokenizer function which provides a very
+ customizable way of breaking up strings.
+*********************************************************************/
+
+#include
+#include
+using namespace std;
+
+// Function to break up a string into tokens
+//
+// Parameters:
+//-----------
+// str = the input string that will be tokenized
+// result = the tokens for str
+// delimiters = the delimiter characters
+// delimiters preserve = same as above, but the delimiter characters
+// will be put into the result as a token
+// quote = characters to protect the enclosed characters
+// esc = characters to protect a single character
+//
+
+void tokenize ( const string& str, vector& result,
+ const string& delimiters, const string& delimiters_preserve = "",
+ const string& quote = "\"", const string& esc = "\\" );
diff --git a/src/blackberry10/native/simulator/libLowLatencyAudio.so b/src/blackberry10/native/simulator/libLowLatencyAudio.so
new file mode 100755
index 00000000..cabec8dc
Binary files /dev/null and b/src/blackberry10/native/simulator/libLowLatencyAudio.so differ
diff --git a/src/blackberry10/native/simulator/public/json_reader.o b/src/blackberry10/native/simulator/public/json_reader.o
new file mode 100644
index 00000000..96a8fe14
Binary files /dev/null and b/src/blackberry10/native/simulator/public/json_reader.o differ
diff --git a/src/blackberry10/native/simulator/public/json_value.o b/src/blackberry10/native/simulator/public/json_value.o
new file mode 100644
index 00000000..17af083e
Binary files /dev/null and b/src/blackberry10/native/simulator/public/json_value.o differ
diff --git a/src/blackberry10/native/simulator/public/json_writer.o b/src/blackberry10/native/simulator/public/json_writer.o
new file mode 100644
index 00000000..faf6f91f
Binary files /dev/null and b/src/blackberry10/native/simulator/public/json_writer.o differ
diff --git a/src/blackberry10/native/simulator/public/plugin.o b/src/blackberry10/native/simulator/public/plugin.o
new file mode 100644
index 00000000..53c9e6d4
Binary files /dev/null and b/src/blackberry10/native/simulator/public/plugin.o differ
diff --git a/src/blackberry10/native/simulator/public/tokenizer.o b/src/blackberry10/native/simulator/public/tokenizer.o
new file mode 100644
index 00000000..11a0f1c5
Binary files /dev/null and b/src/blackberry10/native/simulator/public/tokenizer.o differ
diff --git a/src/blackberry10/native/simulator/src/lowlatencyaudio_js.o b/src/blackberry10/native/simulator/src/lowlatencyaudio_js.o
new file mode 100644
index 00000000..e3bd4bca
Binary files /dev/null and b/src/blackberry10/native/simulator/src/lowlatencyaudio_js.o differ
diff --git a/src/blackberry10/native/src/lowlatencyaudio_js.cpp b/src/blackberry10/native/src/lowlatencyaudio_js.cpp
new file mode 100644
index 00000000..ec1219c1
--- /dev/null
+++ b/src/blackberry10/native/src/lowlatencyaudio_js.cpp
@@ -0,0 +1,488 @@
+/*
+ * Copyright (c) 2013 BlackBerry Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "lowlatencyaudio_js.hpp"
+
+using namespace std;
+
+bool isUsed = false;
+
+void *useCheck(void *x_void_ptr) {
+
+ int *x_ptr = (int *)x_void_ptr;
+ usleep(*x_ptr * 1000000);
+
+ if (isUsed == false)
+ alutExit();
+
+ return NULL;
+
+}
+
+/**
+ * Default constructor.
+ */
+LowLatencyAudio_JS::LowLatencyAudio_JS(const std::string& id) :
+ m_id(id) {
+
+ // Initialize the ALUT and creates OpenAL context on default device
+ // Input 0,0 so it grabs the native device as default and creates the context automatically
+ alutInit(0, 0);
+
+}
+
+/**
+ * LowLatencyAudio_JS destructor.
+ */
+LowLatencyAudio_JS::~LowLatencyAudio_JS() {
+
+ ALuint bufferID = 0;
+ ALuint sources = 0;
+ QString name;
+
+ // Stop and unload all files before deleting the sources and buffers
+ for (int assetIndex = 0; assetIndex < m_assetBufferHash.size(); assetIndex++) {
+ name = m_assetBufferHash.key(assetIndex);
+ unload(name);
+ }
+
+ for (int soundIndex = 0; soundIndex < m_soundBufferHash.size(); soundIndex++) {
+ name = m_soundBufferHash.key(soundIndex);
+ unload(name);
+ }
+
+ // Clear the QHash for sound buffer ID
+ m_soundIndexHash.clear();
+ m_streamIndexHash.clear();
+ m_soundBufferHash.clear();
+ m_assetBufferHash.clear();
+
+ // Exit the ALUT
+ alutExit();
+
+}
+
+/**
+ * This method returns the list of objects implemented by this native
+ * extension.
+ */
+char* onGetObjList() {
+
+ static char name[] = "LowLatencyAudio_JS";
+ return name;
+
+}
+
+/**
+ * This method is used by JNext to instantiate the LowLatencyAudio_JS object when
+ * an object is created on the JavaScript server side.
+ */
+JSExt* onCreateObject(const string& className, const string& id) {
+
+ if (className == "LowLatencyAudio_JS") {
+ return new LowLatencyAudio_JS(id);
+ }
+
+ return NULL;
+
+}
+
+/**
+ * Method used by JNext to determine if the object can be deleted.
+ */
+bool LowLatencyAudio_JS::CanDelete() {
+
+ return true;
+
+}
+
+string LowLatencyAudio_JS::preloadFX(QString id, QString assetPath) {
+
+ QString fileLocation;
+ char cwd[PATH_MAX];
+ ALuint bufferID;
+ ALuint source;
+
+ // Check to see if the file has already been preloaded
+ // Append the applications directory to the www's sound files directory.
+ if (m_soundBufferHash[id])
+ return "Already preloaded " + id.toStdString();
+
+ // First, we get the complete application directory in which we will load sounds from then
+ // we convert to QString since it is more convenient when working with directories.
+ // Append the applications directory to the www's sound files path.
+ getcwd(cwd, PATH_MAX);
+ fileLocation = QString(cwd).append("/app/native/").append(assetPath);
+
+ // Create OpenAL buffers from all files in the sound directory.
+ QFileInfo fileInfo(fileLocation);
+ const char* path = fileInfo.absoluteFilePath().toStdString().c_str();
+
+ // File existence check
+ if (!(fileInfo.isFile() && fileInfo.exists()))
+ return "Not loaded. Could not find file " + id.toStdString();
+
+ // Create the Unique Buffer ID from the path
+ bufferID = alutCreateBufferFromFile(fileLocation.toStdString().c_str());
+
+ // Create sources and buffers corresponding to each unique file name.
+ m_soundBufferHash[id] = bufferID;
+
+ // Generate the sources and store them into m_assetIndexHash, our hash, using insert hashing
+ // Also assign the bufferID to the sources
+ alGenSources(1, &source);
+ alSourcei(source, AL_BUFFER, bufferID);
+ m_soundIndexHash.insertMulti(id, source);
+
+ //this->~PGaudio(); calling destructor to kill this object, not used in this case
+ int x = 3;
+ pthread_t useCheck_thread;
+
+ // Create a thread to check if the preloaded audio file if being used or not. If not, kill the audio device channel
+ if(pthread_create(&useCheck_thread, NULL, useCheck, &x)) {
+ fprintf(stderr, "Error creating thread\n");
+ return NULL;
+ }
+
+ return "File: <" + id.toStdString() + "> is loaded";
+
+}
+
+string LowLatencyAudio_JS::preloadAudio(QString id, QString assetPath, double volume, int voices) {
+
+ QString fileLocation;
+ char cwd[PATH_MAX];
+ ALuint bufferID;
+ ALuint source;
+
+ // Check to see if the file has already been preloaded
+ // Append the applications directory to the www's sound files directory
+ if (m_assetBufferHash[id])
+ return "Already preloaded " + id.toStdString();
+
+ // First, we get the complete application directory in which we will load sounds from then
+ // we convert to QString since it is more convenient when working with directories.
+ // Append the applications directory to the www's sound files path.
+ getcwd(cwd, PATH_MAX);
+ fileLocation = QString(cwd).append("/app/native/").append(assetPath);
+
+ // Create OpenAL buffers from all files in the sound directory
+ QFileInfo fileInfo(fileLocation);
+ const char* path = fileInfo.absoluteFilePath().toStdString().c_str();
+
+ // File existence check
+ if (!(fileInfo.isFile() && fileInfo.exists()))
+ return "Not loaded. Could not find file " + id.toStdString();
+
+ // Create the Unique Buffer ID from the path
+ bufferID = alutCreateBufferFromFile(fileLocation.toStdString().c_str());
+
+ // Create sources and buffers corresponding to each unique file name.
+ m_assetBufferHash[id] = bufferID;
+
+ for (int i = 0; i < voices; i++) {
+ // Generate the sources, one by one, and store them into m_streamIndexHash, our hash, using insert hashing
+ // Also assign the bufferID to the sources
+ alGenSources(1, &source);
+ alSourcei(source, AL_BUFFER, bufferID);
+ alSourcef(source, AL_GAIN, volume);
+ m_streamIndexHash.insertMulti(id, source);
+ }
+
+ //this->~PGaudio(); calling destructor to kill this object, not used in this case
+ int x = 3;
+ pthread_t useCheck_thread;
+
+ // Create a thread to check if the preloaded audio file if being used or not. If not, kill the audio device channel
+ if(pthread_create(&useCheck_thread, NULL, useCheck, &x)) {
+ fprintf(stderr, "Error creating thread\n");
+ return NULL;
+ }
+
+ return "File: <" + id.toStdString() + "> is loaded";
+
+}
+
+string LowLatencyAudio_JS::unload(QString id) {
+
+ isUsed = true;
+
+ // Unload audio file loaded via preloadFX
+ if (m_soundBufferHash[id]) {
+
+ // Stop all sources before unloading
+ QList sources = m_soundIndexHash.values(id);
+ for (int i = 0; i < sources.size(); ++i) {
+ alSourceStop(sources.at(i));
+ alDeleteSources(1, &sources.at(i));
+ }
+
+ // Get corresponding buffers, voices and sources from the unique id
+ ALuint bufferID = m_soundBufferHash[id];
+
+ // Delete sources and buffers
+ alDeleteBuffers(1, &bufferID);
+ m_soundIndexHash.remove(id);
+
+ // Re-initialize the buffers
+ m_soundBufferHash[id] = 0;
+
+ alutExit();
+
+ return "Unloading " + id.toStdString();
+ }
+
+ // Unload audio file loaded via preloadAudio
+ if (m_assetBufferHash[id]) {
+
+ // Stop all sources before unloading
+ stop(id);
+
+ // Get corresponding buffers, voices and sources from the unique id
+ ALuint bufferID = m_assetBufferHash[id];
+
+ // Delete sources and buffers
+ alDeleteBuffers(1, &bufferID);
+ m_streamIndexHash.remove(id);
+
+ // Re-initialize the buffers
+ m_assetBufferHash[id] = 0;
+
+ alutExit();
+
+ return "Unloading " + id.toStdString();
+ }
+
+ return "Unloading Error: file not found <" + id.toStdString() + ">!";
+
+}
+
+string LowLatencyAudio_JS::stop(QString id){
+
+ isUsed = true;
+
+ // Stop audio file loaded via preloadFX
+ if (m_soundBufferHash[id]) {
+ return "Voices loaded via preloadFX are not intended to be looped or stopped.";
+ }
+
+ if (m_assetBufferHash[id]) {
+ // Loop and stop every sound with corresponding file name
+ QList sources = m_streamIndexHash.values(id);
+ for (int i = 0; i < sources.size(); ++i)
+ alSourceStop(sources.at(i));
+
+ // Stopped playing source
+ return "Stopped " + id.toStdString();
+ }
+
+ return "Stopping Error: file not found <" + id.toStdString() + ">!";
+
+}
+
+string LowLatencyAudio_JS::play(QString id){
+
+ isUsed = true;
+
+ float currentTime = 0, furthestTime = 0;
+ ALuint replayingSource = 0;
+
+ if (m_soundBufferHash[id]) {
+ // Get corresponding buffer from the unique id
+ ALuint bufferID = m_soundBufferHash[id];
+
+ // Check to see if it has been preloaded
+ if (!bufferID)
+ return "Could not find the file " + id.toStdString() + " . Maybe it hasn't been loaded.";
+
+ // Iterate through a list of sources associated with with the file and play the sound if it is not currently playing
+ QList sources = m_soundIndexHash.values(id);
+ for (int i = 0; i < sources.size(); ++i) {
+ ALenum state;
+ alGetSourcef(sources.at(i), AL_SEC_OFFSET, ¤tTime);
+ alGetSourcei(sources.at(i), AL_SOURCE_STATE, &state);
+ if (state != AL_PLAYING) {
+ alSourcePlay(sources.at(i));
+ return "Playing " + id.toStdString();
+ }
+ if (currentTime > furthestTime) {
+ furthestTime = currentTime;
+ replayingSource = sources.at(i);
+ }
+ }
+ }
+
+ if (m_assetBufferHash[id]) {
+ // Get corresponding buffer from the unique id
+ ALuint bufferID = m_assetBufferHash[id];
+
+ // Check to see if it has been preloaded
+ if (!bufferID)
+ return "Could not find the file " + id.toStdString() + " . Maybe it hasn't been loaded.";
+
+ // Iterate through a list of sources associated with with the file and play the sound if it is not currently playing
+ QList sources = m_streamIndexHash.values(id);
+ for (int i = 0; i < sources.size(); ++i) {
+ ALenum state;
+ alGetSourcef(sources.at(i), AL_SEC_OFFSET, ¤tTime);
+ alGetSourcei(sources.at(i), AL_SOURCE_STATE, &state);
+ if (state != AL_PLAYING) {
+ alSourcePlay(sources.at(i));
+ return "Playing " + id.toStdString();
+ }
+ if (currentTime > furthestTime) {
+ furthestTime = currentTime;
+ replayingSource = sources.at(i);
+ }
+ }
+ }
+
+ // Continue cycling through and overwrite the sources if all sources are currently being used
+ alSourcePlay(replayingSource);
+ return "Every single voice is currently being played, now overwriting previous ones";
+
+}
+
+string LowLatencyAudio_JS::loop(QString id){
+
+ isUsed = true;
+
+ // Loop audio file loaded via preloadFX
+ if (m_soundBufferHash[id]) {
+ return "Voices loaded via preloadFX are not intended to be looped or stopped.";
+ }
+
+ // Loop audio file loaded via preloadAudio
+ if (m_assetBufferHash[id]) {
+ // Get corresponding buffers and sources from the unique id
+ ALuint bufferID = m_assetBufferHash[id];
+
+ // If sound file has been preloaded loop sound
+ if (!bufferID)
+ return "Could not find the file " + id.toStdString() + " . Maybe it hasn't been loaded.";
+
+ // Get the source from which the sound will be played
+ ALuint source;
+ QList sources = m_streamIndexHash.values(id);
+ source = sources.at(sources.size() - 1);
+
+ if (alIsSource(source) == AL_TRUE) {
+
+ // Loop the source
+ alSourcei(source, AL_LOOPING, AL_TRUE);
+
+ // Check to see if the sound is already looping or not, if not, loop sound
+ ALenum state;
+ alGetSourcei(source, AL_SOURCE_STATE, &state);
+ if (state != AL_PLAYING) {
+ alSourcePlay(source);
+ return "Looping " + id.toStdString();
+ }
+
+ }
+ return id.toStdString() + " is already playing";
+ }
+
+ return "Could not find the file " + id.toStdString() + " . Maybe it hasn't been loaded.";
+}
+
+/**
+ * It will be called from JNext JavaScript side with passed string.
+ * This method implements the interface for the JavaScript to native binding
+ * for invoking native code. This method is triggered when JNext.invoke is
+ * called on the JavaScript side with this native objects id.
+ */
+string LowLatencyAudio_JS::InvokeMethod(const string& command) {
+
+ // parse command and args from string
+ int indexOfFirstSpace = command.find_first_of(" ");
+ string strCommand = command.substr(0, indexOfFirstSpace);
+ string strValue = command.substr(indexOfFirstSpace + 1, command.length());
+
+ // Convert input file name from string to QString
+ QString id = QString::fromStdString(strValue);
+
+ // Determine which function should be executed
+
+ // Loop with given fileName.
+ if (strCommand == "preloadFX") {
+ // parse id and path from strValue
+ int indexOfSecondSpace = strValue.find_first_of(" ");
+ string idString = strValue.substr(0, indexOfSecondSpace);
+ string pathString = strValue.substr(indexOfSecondSpace + 1, strValue.length());
+
+ QString id = QString::fromStdString(idString);
+ QString assetPath = QString::fromStdString(pathString);
+
+ return preloadFX(id, assetPath);
+ }
+
+ if (strCommand == "preloadAudio") {
+ // parse id from strValue
+ int indexOfSecondSpace = strValue.find_first_of(" ");
+ string idString = strValue.substr(0, indexOfSecondSpace);
+ string pathVolumeVoice = strValue.substr(indexOfSecondSpace + 1, strValue.length());
+
+ // parse path from pathVolumeVoice
+ int indexOfThirdSpace = pathVolumeVoice.find_first_of(" ");
+ string pathString = pathVolumeVoice.substr(0, indexOfThirdSpace);
+ string volumeVoice = pathVolumeVoice.substr(indexOfThirdSpace + 1, pathVolumeVoice.length());
+
+ // parse volume and voices from volumeVoice
+ int indexOfFourthSpace = volumeVoice.find_first_of(" ");
+ string volumeString = volumeVoice.substr(0, indexOfFourthSpace);
+ string voicesString = volumeVoice.substr(indexOfFourthSpace + 1, volumeVoice.length());
+
+ QString id = QString::fromStdString(idString);
+ QString assetPath = QString::fromStdString(pathString);
+ double volume = atof (volumeString.c_str());
+ int voices = atoi (voicesString.c_str());
+
+ return preloadAudio(id, assetPath, volume, voices);
+ }
+
+ // Play with given fileName.
+ if (strCommand == "play")
+ return play(id);
+
+ // Loops the source
+ if (strCommand == "loop")
+ return loop(id);
+
+ // Unloads the source
+ if (strCommand == "unload")
+ return unload(id);
+
+ // Stop the source.
+ if (strCommand == "stop")
+ return stop(id);
+
+ return "Command not found, choose either: load, unload, play ,loop, or stop";
+
+}
diff --git a/src/blackberry10/native/src/lowlatencyaudio_js.hpp b/src/blackberry10/native/src/lowlatencyaudio_js.hpp
new file mode 100644
index 00000000..2b9b00cf
--- /dev/null
+++ b/src/blackberry10/native/src/lowlatencyaudio_js.hpp
@@ -0,0 +1,49 @@
+/*
+* Copyright (c) 2013 BlackBerry Limited
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+#ifndef LowLatencyAudio_JS_HPP_
+#define LowLatencyAudio_JS_HPP_
+
+#include
+#include "../public/plugin.h"
+#include
+#include
+#include
+#include
+#include
+
+class LowLatencyAudio_JS: public JSExt {
+
+public:
+ explicit LowLatencyAudio_JS(const std::string& id);
+ virtual ~LowLatencyAudio_JS();
+ virtual std::string preloadFX(QString id, QString assetPath);
+ virtual std::string preloadAudio(QString id, QString assetPath, double volume, int voices);
+ virtual std::string play(QString id);
+ virtual std::string stop(QString id);
+ virtual std::string loop(QString id);
+ virtual std::string unload(QString id);
+ virtual bool CanDelete();
+ virtual std::string InvokeMethod(const std::string& command);
+private:
+ std::string m_id;
+ QHash m_soundBufferHash;
+ QHash m_soundIndexHash;
+ QHash m_assetBufferHash;
+ QHash m_streamIndexHash;
+};
+
+#endif /* LowLatencyAudio_JS_HPP_ */