浏览代码

Moved to Text namespace

Brucey 5 年之前
父节点
当前提交
9f6c46d59e

+ 0 - 628
jconv.mod/doc/intro.bbdoc

@@ -1,628 +0,0 @@
-## Serialising with JConv
-
-In the context of #BRL.JConv, serialisation is the mapping of BlitzMax objects to their JSON representation.
-
-Take the following `TUser` type to start with :
-```blitzmax
-Type TUser
-	Field name:String
-	Field email:String
-	Field age:int
-End Type
-```
-
-The `TUser` object has three Fields,
-* The user's `name` is a #String
-* The user's `email` is a #String
-* The user's `age` is an #Int
-
-An application needs to convert a 'TUser' into its JSON representation, so assuming the member names
-remained the same, we could expect a typical JSON representation to look like this :
-```json
-{
-  "name" : "bob",
-  "email" : "[email protected]",
-  "age" : 30
-}
-```
-
-To convert a `TUser` to JSON, we first construct an instance of one for the user Bob :
-```blitzmax
-Local user:TUser = New TUser("bob", "[email protected]", 30)
-```
-
-In order to do the serialisation, we need an instance of #TJConv to do the conversion :
-```blitzmax
-Local jconv:TJConv = New TJConvBuilder.Build()
-```
-The next step is to call the #ToJson method of #TJConv, passing the object we want to serialise :
-```blitzmax
-Local json:String = jconv.ToJson(user)
-```
-The `json` #String contains the following value :
-```json
-{"name": "bob", "email": "[email protected]", "age": 30}
-```
-Notice that #BRL.JConv respects the field types, wrapping Strings in quotes, but not so for numbers.
-Just a single method call is required to do the conversion of the entire object. This is useful when
-working with more complex object structures.
-
-Here's the example in full :
-```blitzmax
-SuperStrict
-
-Framework BRL.StandardIO
-Import BRL.JConv
-
-Local user:TUser = New TUser("bob", "[email protected]", 30)
-
-Local jconv:TJConv = New TJConvBuilder.Build()
-
-Local json:String = jconv.ToJson(user)
-
-Print json
-
-Type TUser
-	Field name:String
-	Field email:String
-	Field age:Int
-	
-	Method New(name:String, email:String, age:Int)
-		Self.name = name
-		Self.email = email
-		Self.age = age
-	End Method
-End Type
-```
-
-## Deserialising with JConv
-
-We'll start by creating a #String containing the JSON to convert :
-```blitzmax
-Local json:String = "{~qname~q: ~qbob~q, ~qemail~q: [email protected]~q, ~qage~q: 30}"
-```
-Again, we'll build an instance of #TJConv which will perform the conversion :
-```blitzmax
-Local jconv:TJConv = New TJConvBuilder.Build()
-```
-Finally, we need to map the JSON to a BlitzMax #Object with #FromJson :
-```blitzmax
-Local user:TUser = TUser(jconv.FromJson(json, "TUser"))
-```
-Note that the second argument specifies the name of the #Type we want the #String to map the JSON to.
-Without this *hint*, #BRL.JConv wouldn't know what #Type to create from the text.
-
-The `user` object returned from #FromJson will have its fields populated accordingly.
-
-Here's the example in full :
-```blitzmax
-SuperStrict
-
-Framework BRL.StandardIO
-Import BRL.JConv
-
-Local json:String = "{~qname~q: ~qbob~q, ~qemail~q: [email protected]~q, ~qage~q: 30}"
-
-Local jconv:TJConv = New TJConvBuilder.Build()
-
-Local user:TUser = TUser(jconv.FromJson(json, "TUser"))
-
-Print "name  = " + user.name
-Print "email = " + user.email
-Print "age   = " + user.age
-
-Type TUser
-	Field name:String
-	Field email:String
-	Field age:Int
-	
-	Method New(name:String, email:String, age:Int)
-		Self.name = name
-		Self.email = email
-		Self.age = age
-	End Method
-End Type
-```
-
-## Serialising Nested Objects
-
-#BRL.JConv can also handle the conversion of more complex objects that include the nesting of other non-primitive objects.
-To demostrate this we will extend the `TUser` type to include an address, which will be represented by the `TAddress` #Type :
-```blitzmax
-Type TUser
-	Field name:String
-	Field email:String
-	Field age:Int
-	Field address:TAddress
-End Type
-
-Type TAddress
-	Field line1:String
-	Field city:String
-	Field country:String
-End Type
-```
-In BlitzMax the two models are cleanly separated by types, and the `TAddress` reference is held in the `address` #Field of the user.
-In JSON however, the address must be nested directly within the user object, as we can see here :
-```json
-{
-  "name" : "bob",
-  "email" : "[email protected]",
-  "age" : 30,
-  "address" : {
-    "line1" : "66 Some Street",
-    "city" : "Someville",
-    "country" : "Someland"
-  }
-}
-```
-We'll initially create the required BlitzMax objects :
-```blitzmax
-Local address:TAddress = New TAddress("66 Some Street", "Someville", "Someland")
-Local user:TUser = New TUser("bob", "[email protected]", 30, address)
-```
-And then serialise the user with an instance of #TJConv :
-```blitzmax
-Local jconv:TJConv = New TJConvBuilder.Build()
-Local json:String = jconv.ToJson(user)
-```
-The resulting conversion to JSON is :
-```json
-{"name": "bob", "email": "[email protected]", "age": 30, "address": {"line1": "66 Some Street", "city": "Someville", "country": "Someland"}}
-```
-As you can see, #BRL.JConv has correctly nested the address inside the user as a JSON object.
-
-## Deserialising Nested Objects
-
-In the real world, the developer is often presented with a JSON API from which they need to construct the relevant BlitzMax
-Types in order to import the data.
-
-As we have seen previously, the structure of a JSON object maps relatively well to a BlitzMax #Object and its fields.
-In the next example, we'll start with a JSON object and construct a set of BlitzMax Types that we can use to deserialise the
-data in order to use it within our BlitzMax application.
-
-In this particular example, we will be retrieving some airport information from an online flight information resource :
-```json
-{
-  "id": "BER",
-  "code": "BER",
-  "name": "Berlin Brandenburg",
-  "slug": "berlin-brandenburg-berlin-germany",
-  "timezone": "Europe/Berlin",
-  "city": {
-	"id": "berlin_de",
-	"name": "Berlin",
-	"code": "BER",
-	"slug": "berlin-germany",
-	"country": {
-	  "id": "DE",
-	  "name": "Germany",
-	  "slug": "germany",
-	  "code": "DE"
-	},
-	"region": {
-	  "id": "central-europe",
-	  "name": "Central Europe",
-	  "slug": "central-europe"
-	},
-	"continent": {
-	  "id": "europe",
-	  "name": "Europe",
-	  "slug": "europe",
-	  "code": "EU"
-	}
-  },
-  "location": {
-	"lat": 52.366667,
-	"lon": 13.503333
-  }
-}
-```
-As you can see, there are several levels of nesting. The main airport object has a nested `city`, and within that `country`, `region` and `continent` objects.
-Also notice that many of the objects share a similar structure (`id`, `name`, `slug`, and `code`).
-We can use BlitzMax's #Type polymorphism by creating a base #Type and avoid a lot of duplication :
-```blitzmax
-Type TBase
-	Field id:String
-	Field code:String
-	Field name:String
-	Field slug:String
-End Type
-```
-
-Next, we'll define the BlitzMax types that will contain the more specific information :
-```blitzmax
-Type TAirport Extends TBase
-	Field timezone:String
-	Field city:TCity
-	Field location:TLocation
-End Type
-
-Type TCity Extends TBase
-	Field country:TCountry
-	Field region:TRegion
-	Field continent:TContinent
-End Type
-
-Type TCountry Extends TBase
-End Type
-
-Type TRegion Extends TBase
-End Type
-
-Type TContinent Extends TBase
-End Type
-
-Type TLocation
-	Field lat:Double
-	Field lon:Double
-End Type
-```
-Each #Type represents a particular JSON object from original nested JSON. `TCity` contains fields for `country`, `region` and `continent`, each of which are types
-representing that particular piece of information.
-
-Where the naming of your fields must match those of the JSON objects, how you name your types is not important for JSON mapping, but you'll generally give them a
-name that reflects the kind of information they contain.
-
-Finally, we can use these types to de-serialise a matching JSON object, as shown in this complete example :
-```blitzmax
-SuperStrict
-
-Framework BRL.StandardIO
-Import BRL.JConv
-
-Local data:String = "{~qid~q:~qBER~q,~qcode~q:~qBER~q,~qname~q:~qBerlin Brandenburg~q,~qslug~q:~qberlin-brandenburg-berlin-germany~q,~qtimezone~q:~qEurope/Berlin~q,~qcity~q:{~qid~q:~qberlin_de~q,~qname~q:~qBerlin~q,~qcode~q:~qBER~q,~qslug~q:~qberlin-germany~q,~qcountry~q:{~qid~q:~qDE~q,~qname~q:~qGermany~q,~qslug~q:~qgermany~q,~qcode~q:~qDE~q},~qregion~q:{~qid~q:~qcentral-europe~q,~qname~q:~qCentral Europe~q,~qslug~q:~qcentral-europe~q},~qcontinent~q:{~qid~q:~qeurope~q,~qname~q:~qEurope~q,~qslug~q:~qeurope~q,~qcode~q:~qEU~q}},~qlocation~q:{~qlat~q:52.366667,~qlon~q:13.503333}}"
-
-Local jconv:TJConv = New TJConvBuilder.Build()
-Local airport:TAirport = TAirport(jconv.FromJson(data, "TAirport"))
-
-Print "Airport    : " + airport.name
-Print "  City     : " + airport.city.name
-Print "  Location : " + airport.location.lat + ", " + airport.location.lon
-
-Type TBase
-	Field id:String
-	Field code:String
-	Field name:String
-	Field slug:String
-End Type
-
-Type TAirport Extends TBase
-	Field timezone:String
-	Field city:TCity
-	Field location:TLocation
-End Type
-
-Type TCity Extends TBase
-	Field country:TCountry
-	Field region:TRegion
-	Field continent:TContinent
-End Type
-
-Type TCountry Extends TBase
-End Type
-
-Type TRegion Extends TBase
-End Type
-
-Type TContinent Extends TBase
-End Type
-
-Type TLocation
-	Field lat:Double
-	Field lon:Double
-End Type
-```
-
-## Customising Field Names
-
-Occasionally, a JSON object will use a key that has the same name as a reserved keyword in BlitzMax. In that case, you are unable create a field
-using the desired name. Fortunately, #BRL.JConv allows you use metadata to specify the serialised name of a given field using the `serializedName`
-metadata property.
-
-Take the following JSON object as an example :
-```json
-{
-	"field" : "hello",
-	"for" : "ever"
-}
-```
-Neither `field` nor `for` are valid names for fields, but we can use the `serializedName` feature to create a valid BlitzMax #Type that can
-deserialise this object :
-```blitzmax
-Type TCustomFields
-	Field field_:String { serializedName="field" }
-	Field anotherField:String { serializedName = "for" }
-End Type
-```
-As this example demonstrates, when using the `serializedName` metadata property, you can give any name to your fields and the data will still be mapped from
-the JSON object correctly.
-
-Here the example in full :
-```blitzmax:
-SuperStrict
-
-Framework BRL.StandardIO
-Import BRL.JConv
-
-Local data:String = "{~qfield~q:~qhello~q,~qfor~q:~qever~q}"
-
-Local jconv:TJConv = New TJConvBuilder.Build()
-Local custom:TCustomFields = TCustomFields(jconv.FromJson(data, "TCustomFields"))
-
-Print custom.field_
-Print custom.anotherField
-
-Type TCustomFields
-	Field field_:String { serializedName="field" }
-	Field anotherField:String { serializedName = "for" }
-End Type
-```
-
-In addition to `serializedName`, another metadata property is available during deserialisation, `alternateName`. If you consider `serializedName` as being
-the default value, `alternateName` allows you to map other JSON keys to a particular field. 
-
-For example, given a `TUser` object where we are already mapping the JSON key `full_name` to the field `name` :
-```blitzmax
-Type TUser
-	Field name:String { serializedName = "full_name" }
-	Field email:String
-	Field age:int
-End Type
-```
-We decide we also want ingest similar data from another system in our application. Instead of `full_name`, the other system uses
-`username` for this value. Using the `alternateName` metadata property we can add a comma-delimited list of other names, and our #Type becomes :
-```blitzmax
-Type TUser
-	Field name:String { serializedName = "full_name", alternateName ="username" }
-	Field email:String
-	Field age:int
-End Type
-```
-`alternateName` is only available during deserialisation. #BRL.JConv will use either the #Field name or the `serializedName` when mapping a
-BlitzMax object to JSON.
-
-The following two sets of JSON would map to a `TUser` object and set the `name` #Field appropriately :
-```json
-{
-  "full_name" : "Bob",
-  "email" : "[email protected]"
-}
-```
-
-```json
-{
-  "username" : "userBob",
-  "email" : "[email protected]"
-}
-```
-
-If there are multiple fields in the JSON that match, #BRL.JConv will apply the value that is processed last. So, in the following example,
-deserialising the JSON would result in the `name` #Field containing the value `userBob` :
-```json
-{
-  "full_name" : "Bob",
-  "username" : "userBob",
-  "email" : "[email protected]"
-}
-```
-
-## Ignoring Fields
-
-If you don't want a field to be mapped to or from JSON there are some metadata properties that you can apply to your types in order to do so.
-The first, `transient`, completely disables field from mapping in either direction.
-
-If you want more finer grained control, the metadata properties `noSerialize` and `noDeserialize` can be used instead.
-The `noSerialize` property instructs #BRL.JConv not to serialize a particular field to JSON, but it allows data from a JSON object to be
-deserialized into the #Field.
-On the other hand, `noDeserialize` prevents data from a JSON object from deserializing into the #Field, but does allow it to be serialized into
-a JSON object.
-
-We'll apply some properties to the `TUser` object to demonstrate the options :
-```blitzmax
-Type TUser
-	Field name:String
-	Field email:String { noSerialize }
-	Field age:int { noDeserialize }
-	Field passwordHash:String { transient }
-End Type
-```
-Based on the above example, when serializing an instance of `TUser`, only the `name` and `age` fields would be mapped to JSON.
-Similarly, only the `name` and `email` fields would be mapped from a JSON object.
-
-The following is a complete example of these properties in action :
-```blitzmax
-SuperStrict
-
-Framework BRL.StandardIO
-Import BRL.JConv
-
-Local user:TUser = New TUser("bob", "[email protected]", 30, "xxxx")
-
-Local jconv:TJConv = New TJConvBuilder.Build()
-
-Local json:String = jconv.ToJson(user)
-
-Print "json  : " + json
-
-json = "{~qname~q: ~qbob~q, ~qemail~q: [email protected]~q, ~qage~q: 30, ~qpasswordHash~q: ~qxxxx~q}"
-
-user = TUser(jconv.FromJson(json, "TUser"))
-
-Print "name  : " + user.name
-Print "email : " + user.email
-Print "age   : " + user.age
-Print "hash  : " + user.passwordHash
-
-Type TUser
-	Field name:String
-	Field email:String { noSerialize }
-	Field age:Int { noDeserialize }
-	Field passwordHash:String { transient }
-
-	Method New(name:String, email:String, age:Int, ph:String)
-		Self.name = name
-		Self.email = email
-		Self.age = age
-		Self.passwordHash = ph
-	End Method
-End Type
-```
-
-## Configuring TJConv with the Builder
-
-You may have noticed, that by default #BRL.JConv serialises the JSON into a single line.
-You can change this behaviour with one ofthe builder's configurable options.
-
-The builder uses what is known as a fluent interface, or method chaining design, where a sequence of method calls can be used to construct the #TJConv instance.
-
-For example, the following builder creates an instance of #TJConv which will serialise objects to JSON with a decimal a precision of 2 places and compact objects :
-```blitzmax
-Local jconv:TJConv = New TJConvBuilder.WithPrecision(2).WithCompact().Build()
-```
-
-### WithIndent
-
-The #WithIndent method of #TJConvBuilder specifies the number of spaces to use for indenting of nested objects. The default of 0 (zero)
-means not to use pretty-printing.
-
-This is an example of `TUser` using the default options :
-```json
-{"name": "Bob", "email": "[email protected]", "age": 30}
-```
-And this is an example of building with #WithIndent :
-```json
-{
-  "name": "Bob",
-  "email": "[email protected]",
-  "age": 30
-}
-```
-
-### WithCompact
-
-On the other hand, JSON can be compacted further using the #WithCompact method, which works to remove extra spaces :
-```json
-{"name":"Bob","email":"[email protected]","age":30}
-```
-### WithPrecision
-The representation of decimal numbers can be controlled by the #WithPrecision method, which specifies the maximum number of decimal places to used.
-
-For example, the default representation of a #Type `TPoint` :
-```blitzmax
-Type TPoint
-	Field x:Double
-	Field y:Double
-End Type
-```
-would normally result in the following JSON with fields of the values (10.565, 15.912) :
-```json
-{"x": 10.565, "y": 15.912000000000001}
-```
-Using a maximum precision of 3 (`WithPrecision(3)`), the resulting JSON would become :
-```json
-{"x": 10.565, "y": 15.912}
-```
-
-### WithEmptyArrays
-
-By default, #Null/empty arrays are not serialised at all. That is, the field is not included in the JSON object.
-The #WithEmptyArrays option can be enabled to generate an empty array (`[]`] instead.
-
-### WithBoxing
-
-Primitive numbers, by their very nature in BlitzMax, have no concept of nullability. JSON, conversely, can represent any field as a null value,
-either by simply not including it in the object, or by having the value `null`.
-
-To support this, #BRL.JConv provides an option to use "boxed" primitives in your types. A Boxed primitive is just an instance of a #Type that has
-a value field of the appropriate numeric #Type. Using a boxed primitive then allows a field to contain a value, or be #Null.
-
-This feature is enabled by using the #WithBoxing option of the builder.
-
-As an example, suppose there is a JSON object which has a numeric field `failures`. The schema specifies that this value can either be `null` or have a value
-greater than zero :
-```json
-[
-  {
-    "jobId": "ABC123",
-    "failures": 3,
-    "lastError": "overflow"
-  },
-  {
-    "jobId": "DEF456"
-  }
-]
-```
-Deserialising this wouldn't be a problem, as our `TJob` #Type could represent no `failures` by the number zero :
-```blitzmax
-Type TJob
-	Field jobId:String
-	Field failures:Int
-	Field lastError:String
-End Type
-```
-However, were we required to serialise our #Type to JSON for use by the API, we'd potentially fail schema validation by passing zero as a value for
-the `failures` #Field.
-
-Utilising the boxing feature, we could instead define the `failures` #Field as `TInt` :
-```blitzmax
-Type TJob
-	Field jobId:String
-	Field failures:TInt
-	Field lastError:String
-End Type
-```
-Which would, for #Null values, result in the `features` #Field not being serialized to JSON.
-
-Here's a full example highlighting the use of boxing :
-```blitzmax
-SuperStrict
-
-Framework BRL.StandardIO
-Import BRL.JConv
-
-Local job1:TJob = New TJob("ABC123", 3, "overflow")
-Local job2:TBoxedJob = New TBoxedJob("DEF456", 0, Null)
-
-Local jconv:TJConv = New TJConvBuilder.WithBoxing().WithIndent(2).Build()
-
-Print jconv.ToJson(job1)
-Print jconv.ToJson(job2)
-
-Type TJob
-	Field jobId:String
-	Field failures:Int
-	Field lastError:String
-	
-	Method New(jobId:String, failures:Int, lastError:String)
-		Self.jobId = jobId
-		Self.failures = failures
-		Self.lastError = lastError
-	End Method
-End Type
-
-Type TBoxedJob
-	Field jobId:String
-	Field failures:TInt
-	Field lastError:String
-
-	Method New(jobId:String, failures:Int, lastError:String)
-		Self.jobId = jobId
-		If failures > 0 Then
-			Self.failures = New TInt(failures)
-		End If
-		Self.lastError = lastError
-	End Method
-End Type
-```
-Running the above example would result in the following output :
-```
-{
-  "jobId": "ABC123",
-  "failures": 3,
-  "lastError": "overflow"
-}
-{
-  "jobId": "DEF456"
-}
-```

+ 0 - 28
jconv.mod/doc/tjconv_fromjson.bmx

@@ -1,28 +0,0 @@
-SuperStrict
-
-Framework brl.standardio
-Import brl.jconv
-
-' a serialized object as json
-Local txt:String = "{~qposition~q:{~qx~q:100,~qy~q:50},~qspeed~q:{~qx~q:50,~qy~q:75}}"
-
-' create jconv instance
-Local jconv:TJConv = New TJConvBuilder.Build()
-
-' deserialize into a TPlayer object
-Local player:TPlayer = TPlayer(jconv.FromJson(txt, "TPlayer"))
-
-If player Then
-	Print "Position = " + player.position.x + ", " + player.position.y
-	Print "Speed    = " + player.speed.x + ", " + player.speed.y
-End If
-
-Type TPlayer
-	Field position:TVec2
-	Field speed:TVec2
-End Type
-
-Type TVec2
-	Field x:Int
-	Field y:Int
-End Type

+ 0 - 47
jconv.mod/doc/tjconv_tojson.bmx

@@ -1,47 +0,0 @@
-SuperStrict
-
-Framework brl.standardio
-Import brl.jconv
-
-
-' create a person with some data
-Local person:TPerson = New TPerson
-person.firstName = "John"
-person.lastName = "Smith"
-
-person.address = New TAddress
-person.address.line1 = "10 Somewhere Street"
-person.address.city = "SomeTown"
-person.address.state = "SomeState"
-
-person.notes = New String[2]
-person.notes[0] = "Note 1"
-person.notes[1] = "Note 2"
-
-' create jconv instance
-Local jconv:TJConv = New TJConvBuilder.Build()
-
-' serialize the person data
-Local s:String = jconv.ToJson(person)
-Print s
-Local p:TPerson = TPerson(jconv.FromJson(s, "TPerson"))
-Print jconv.ToJson(p)
-
-Type TPerson
-
-	Field firstName:String
-	Field lastName:String
-
-	Field address:TAddress
-
-	Field notes:String[]
-End Type
-
-Type TAddress
-
-	Field line1:String
-	Field line2:String
-	Field city:String
-	Field state:String
-
-End Type

+ 0 - 1131
jconv.mod/jconv.bmx

@@ -1,1131 +0,0 @@
-' Copyright (c) 2019-2020 Bruce A Henderson
-'
-' 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.
-'
-SuperStrict
-
-Rem
-bbdoc: JSON Object de/serializer.
-End Rem
-Module BRL.JConv
-
-ModuleInfo "Version: 1.06"
-ModuleInfo "Author: Bruce A Henderson"
-ModuleInfo "License: zlib/png"
-ModuleInfo "Copyright: 2019-2020 Bruce A Henderson"
-
-ModuleInfo "History: 1.06"
-ModuleInfo "History: Added support for transient, noSerialize and noDeserialize field metadata."
-ModuleInfo "History: 1.05"
-ModuleInfo "History: Added boxing for nullable primitives."
-ModuleInfo "History: 1.04"
-ModuleInfo "History: Added support for serializedName and alternateName field metadata."
-ModuleInfo "History: 1.03"
-ModuleInfo "History: Added custom deserializing."
-ModuleInfo "History: 1.02"
-ModuleInfo "History: Added custom serializer."
-ModuleInfo "History: 1.01"
-ModuleInfo "History: Added support for arrays."
-ModuleInfo "History: 1.00"
-ModuleInfo "History: Initial Release"
-
-Import brl.reflection
-Import brl.json
-Import brl.map
-
-Rem
-bbdoc: Creates an instance of #TJConv with custom settings.
-End Rem
-Type TJConvBuilder
-
-	Field options:TJConvOptions = New TJConvOptions
-
-	Rem
-	bbdoc: Builds the #TJConv instance.
-	End Rem
-	Method Build:TJConv()
-		Local jconv:TJConv = New TJConv
-		jconv.SetOptions(options)
-		
-		For Local serializer:TJConvSerializer = EachIn options.serializers.Values()
-			serializer.jconv = jconv
-		Next
-		
-		Return jconv
-	End Method
-
-	Rem
-	bbdoc: Null/Empty array fields will be output to JSON as `[]`.
-	about: The default is not to output these fields.
-	End Rem
-	Method WithEmptyArrays:TJConvBuilder()
-		options.emptyArraysAreNull = False
-		Return Self
-	End Method
-	
-	Rem
-	bbdoc: Registers a serializer for the given source type.
-	End Rem
-	Method RegisterSerializer:TJConvBuilder(sourceType:String, serializer:Object)
-		options.serializers.Insert(sourceType, serializer)
-		Return Self
-	End Method
-
-	Rem
-	bbdoc: Registers serializers for boxed primitive numbers.
-	about: Boxed primitives allow for the provision of serializing #Null primitive numbers via JSON.
-	End Rem
-	Method WithBoxing:TJConvBuilder()
-		RegisterSerializer("TBool", New TBoolSerializer)
-		RegisterSerializer("TByte", New TByteSerializer)
-		RegisterSerializer("TShort", New TShortSerializer)
-		RegisterSerializer("TInt", New TIntSerializer)
-		RegisterSerializer("TUInt", New TUIntSerializer)
-		RegisterSerializer("TSize_T", New TSizetSerializer)
-		RegisterSerializer("TLong", New TLongSerializer)
-		RegisterSerializer("TULong", New TULongSerializer)
-		RegisterSerializer("TFloat", New TFloatSerializer)
-		RegisterSerializer("TDouble", New TDoubleSerializer)
-		Return Self
-	End Method
-
-	Rem
-	bbdoc: Serialization of real numbers will have a maximum precision of @precision fractional digits.
-	End Rem
-	Method WithPrecision:TJConvBuilder(precision:Int)
-		options.precision = precision
-		Return Self
-	End Method
-
-	Rem
-	bbdoc: Enables pretty-printing of the serialized json, using @indent spaces of indentation.
-	about: The default, 0, disables pretty-printing. The maximum indent size is 31.
-	End Rem
-	Method WithIndent:TJConvBuilder(indent:Int)
-		options.indent = indent
-		Return Self
-	End Method
-
-	Rem
-	bbdoc: Enables compact representation, removing extra spacing.
-	End Rem
-	Method WithCompact:TJConvBuilder()
-		options.compact = True
-		Return Self
-	End Method
-	
-End Type
-
-Rem
-bbdoc: Serialises or deserializes objects to and from JSON.
-End Rem
-Type TJConv
-
-	Field options:TJConvOptions = New TJConvOptions
-	Field flags:Int
-	Field precision:Int = 17
-	
-	Field defaultSerializer:TJConvSerializer = New TJConvSerializer
-	
-	Method New()
-		defaultSerializer.jconv = Self
-	End Method
-
-	Rem
-	bbdoc: Deserializes the specified JSON string into an object of the specified type.
-	returns: The deserialized object.
-	End Rem
-	Method FromJson:Object(json:String, typeName:String)
-		Local typeId:TTypeId = TTypeId.ForName(typeName)
-		
-		Return FromJson(json, typeId, Null)
-	End Method
-
-	Rem
-	bbdoc: Deserializes the specified JSON string into @obj.
-	End Rem
-	Method FromJson:Object(json:String, obj:Object)
-		If Not obj Then
-			Return Null
-		End If
-		
-		Local typeId:TTypeId = TTypeId.ForObject(obj)
-		
-		Return FromJson(json, typeId, obj)
-	End Method
-
-	Rem
-	bbdoc: Deserializes the specified JSON instance into @obj.
-	End Rem
-	Method FromJsonInstance:Object(json:TJSON, obj:Object)
-		If Not obj Then
-			Return Null
-		End If
-		
-		Local typeId:TTypeId = TTypeId.ForObject(obj)
-		
-		Return FromJson(json, typeId, obj)
-	End Method
-
-	Method FromJson:Object(txt:String, typeId:TTypeId, obj:Object)
-		Local error:TJSONError
-		Local json:TJSON = TJSON.Load(txt, 0, error)
-
-		Return FromJson(json, typeId, obj)
-	End Method
-
-	Rem
-	bbdoc: 
-	End Rem
-	Method FromJson:Object(stream:TStream, typeName:String)
-		Local typeId:TTypeId = TTypeId.ForName(typeName)
-		
-		Return FromJson(stream, typeId, Null)
-	End Method
-	
-	Method FromJson:Object(stream:TStream, typeId:TTypeId, obj:Object)
-		Local error:TJSONError
-		Local json:TJSON = TJSON.Load(stream, 0, error)
-
-		Return FromJson(json, typeId, obj)
-	End Method
-
-	Method FromJson:Object(json:TJSON, typeId:TTypeId, obj:Object)
-
-		Local serializer:TJConvSerializer = TJConvSerializer(options.serializers.ValueForKey(typeId.Name()))
-		If Not serializer Then
-			serializer = defaultSerializer
-		End If
-
-		Return serializer.Deserialize(json, typeId, obj)
-	End Method
-
-	Rem
-	bbdoc: Serializes the specified object into its equivalent JSON representation.
-	returns: The JSON representation as a #String.
-	End Rem
-	Method ToJson:String(obj:Object)
-		If Not obj Then
-			If IsEmptyArray(obj) Then
-				Return "[]"
-			End If
-			
-			Return "{}"
-		End If
-		
-		Local typeId:TTypeId = TTypeId.ForObject(obj)
-		
-		If typeId.ExtendsType(ArrayTypeId) Then
-			Local json:TJSONArray = New TJSONArray.Create()
-		
-			ToJson(json, obj)
-			
-			Return json.SaveString(flags, 0, precision)
-		End If
-		
-		If typeId.ExtendsType(ObjectTypeId) Then
-
-			Local serializer:TJConvSerializer = TJConvSerializer(options.serializers.ValueForKey(typeId.Name()))
-			If Not serializer Then
-				serializer = defaultSerializer
-			End If
-
-			Local json:TJSON = serializer.Serialize(obj, typeId.Name())
-
-			Return json.SaveString(flags, 0, precision)
-		End If
-	End Method
-
-	Rem
-	bbdoc: Serializes the specified object into its equivalent JSON representation.
-	returns: A JSON instance.
-	End Rem
-	Method ToJsonInstance:TJSON(obj:Object)
-		If Not obj Then
-			Return Null
-		End If
-		
-		Local typeId:TTypeId = TTypeId.ForObject(obj)
-
-		If typeId.ExtendsType(StringTypeId) Then
-			Return New TJSONString.Create(String(obj))
-		End If
-		
-		If typeId.ExtendsType(ArrayTypeId) Then
-			Local json:TJSONArray = New TJSONArray.Create()
-		
-			ToJson(json, obj)
-			
-			Return json
-		End If
-		
-		If typeId.ExtendsType(ObjectTypeId) Then
-
-			Local serializer:TJConvSerializer = TJConvSerializer(options.serializers.ValueForKey(typeId.Name()))
-			If Not serializer Then
-				serializer = defaultSerializer
-			End If
-
-			Return serializer.Serialize(obj, typeId.Name())
-		End If
-	End Method
-	
-	Rem
-	bbdoc: Serializes the specified object into its equivalent JSON representation and outputs to a #TStream.
-	about: The stream should be open and writeable.
-	End Rem
-	Method ToJson(obj:Object, stream:TStream)
-		If Not obj Then
-			If IsEmptyArray(obj) Then
-				Local json:TJSONArray = New TJSONArray.Create()
-				json.SaveStream(stream, flags, 0, precision)
-				Return
-			End If
-			
-			Local json:TJSONObject = New TJSONObject.Create()
-			json.SaveStream(stream, flags, 0, precision)
-			Return
-		End If
-
-		Local typeId:TTypeId = TTypeId.ForObject(obj)
-		
-		If typeId.ExtendsType(ArrayTypeId) Then
-			Local json:TJSONArray = New TJSONArray.Create()
-		
-			ToJson(json, obj)
-			
-			json.SaveStream(stream, flags, 0, precision)
-			Return
-		Else If typeId.ExtendsType(ObjectTypeId) Then
-
-			Local json:TJSONObject = New TJSONObject.Create()
-
-			ToJson(json, obj)
-		
-			json.SaveStream(stream, flags, 0, precision)
-		End If
-
-	End Method
-	
-	Method ToJson(json:TJSONObject, obj:Object)
-		Local typeId:TTypeId = TTypeId.ForObject(obj)
-		
-		For Local f:TField = EachIn typeId.EnumFields()
-			Local j:TJSON
-			
-			If f.Metadata("transient") Or f.Metadata("noSerialize") Then
-				Continue
-			End If
-			
-			Local fieldType:TTypeId = f.TypeId()
-			
-			Local serializer:TJConvSerializer = TJConvSerializer(options.serializers.ValueForKey(fieldType.Name()))
-			If Not serializer Then
-				serializer = defaultSerializer
-			End If
-			
-			Select fieldType
-				Case ByteTypeId
-					j = serializer.Serialize(f.GetByte(obj), fieldType.Name())
-
-				Case ShortTypeId
-					j = serializer.Serialize(f.GetShort(obj), fieldType.Name())
-
-				Case IntTypeId
-					j = serializer.Serialize(f.GetInt(obj), fieldType.Name())
-
-				Case UIntTypeId
-					j = serializer.Serialize(f.GetUInt(obj), fieldType.Name())
-
-				Case LongTypeId
-					j = serializer.Serialize(f.GetLong(obj), fieldType.Name())
-
-				Case ULongTypeId
-					j = serializer.Serialize(f.GetULong(obj), fieldType.Name())
-
-				Case SizetTypeId
-					j = serializer.Serialize(f.GetSizeT(obj), fieldType.Name())
-					
-				Case FloatTypeId
-					j = serializer.Serialize(f.GetFloat(obj), fieldType.Name())
-
-				Case DoubleTypeId
-					j = serializer.Serialize(f.GetDouble(obj), fieldType.Name())
-					
-				Case StringTypeId
-					Local s:String = f.GetString(obj)
-					If s Then
-						j = serializer.Serialize(s, fieldType.Name())
-						
-						json.Set(FieldName(f), j)
-					End If
-					Continue
-			End Select
-			
-			If Not j And fieldType.ExtendsType(ArrayTypeId) Then
-				Local array:Object = f.Get(obj)
-
-				If array Then
-					j = New TJSONArray.Create()
-
-					ProcessArrayToJson(TJSONArray(j), fieldType, array)
-
-				Else If Not options.emptyArraysAreNull Then
-					j = New TJSONArray.Create()
-				End If
-			End If
-			
-			If Not j And fieldType.ExtendsType(ObjectTypeId) Then
-				Local o:Object = f.Get(obj)
-				If o Then
-					Local objectTypeId:TTypeId = TTypeId.ForObject(o)
-				
-					j = serializer.Serialize(o, objectTypeId.Name())
-				End If
-			End If
-			
-			If j Then
-				json.Set(FieldName(f), j)
-			End If
-		Next
-		
-	End Method
-
-	Method ToJson(json:TJSONArray, obj:Object)
-		Local typeId:TTypeId = TTypeId.ForObject(obj)
-		
-		ProcessArrayToJson(json, typeId, obj)
-	End Method
-	
-	Method ProcessArrayToJson(json:TJSONArray, typeId:TTypeId, array:Object)
-		Local dims:Int
-		Try
-			dims = typeId.ArrayDimensions(array)
-		Catch e:String
-			Return
-		End Try
-
-		Local elementType:TTypeId = typeId.ElementType()
-		Local size:Int
-
-		Try
-			size = typeId.ArrayLength(array)
-		Catch e:String
-			size = 0
-		End Try
-
-		Local serializer:TJConvSerializer = TJConvSerializer(options.serializers.ValueForKey(elementType.Name()))
-		If Not serializer Then
-			serializer = defaultSerializer
-		End If
-
-		For Local i:Int = 0 Until size
-			Local element:TJSON
-
-			Select elementType
-				Case ByteTypeId
-					element = serializer.Serialize(typeId.GetByteArrayElement(array, i), elementType.Name())
-
-				Case ShortTypeId
-					element = serializer.Serialize(typeId.GetShortArrayElement(array, i), elementType.Name())
-
-				Case IntTypeId
-					element = serializer.Serialize(typeId.GetIntArrayElement(array, i), elementType.Name())
-
-				Case UIntTypeId
-					element = serializer.Serialize(typeId.GetUIntArrayElement(array, i), elementType.Name())
-
-				Case LongTypeId
-					element = serializer.Serialize(typeId.GetLongArrayElement(array, i), elementType.Name())
-
-				Case ULongTypeId
-					element = serializer.Serialize(typeId.GetULongArrayElement(array, i), elementType.Name())
-
-				Case SizetTypeId
-					element = serializer.Serialize(typeId.GetSizeTArrayElement(array, i), elementType.Name())
-
-				Case FloatTypeId
-					element = serializer.Serialize(typeId.GetFloatArrayElement(array, i), elementType.Name())
-
-				Case DoubleTypeId
-					element = serializer.Serialize(typeId.GetDoubleArrayElement(array, i), elementType.Name())
-
-				Case StringTypeId
-					element = serializer.Serialize(typeId.GetStringArrayElement(array, i), elementType.Name())
-			End Select
-
-			If Not element And typeId.ExtendsType(ObjectTypeId) Then
-				Local o:Object = typeId.GetArrayElement(array, i)
-				If o Then
-					Local objectTypeId:TTypeId = TTypeId.ForObject(o)
-				
-					element = serializer.Serialize(o, objectTypeId.Name())
-				End If
-			End If
-			
-			If element Then
-				json.Append(element)
-			End If
-		Next
-
-	End Method
-
-	Method FieldName:String(f:TField)
-		Local meta:String = f.Metadata("serializedName")
-		If meta Then
-			Return meta
-		Else
-			Return f.Name()
-		End If
-	End Method
-
-Private
-	Method SetOptions(options:TJConvOptions)
-		Self.options = options
-		
-		flags = 0
-		
-		If options.indent Then
-			flags :| (options.indent & $1F)
-		End If
-		
-		If options.compact Then
-			flags :| JSON_COMPACT
-		End If
-		
-		If options.precision >= 0 Then
-			flags :| JSON_FRACTIONAL_DIGITS
-			precision = options.precision
-		End If
-	End Method
-Public
-End Type
-
-Type TJConvOptions
-
-	Field emptyArraysAreNull:Int = True
-
-	Field serializers:TMap = New TMap
-
-	Field precision:Int = -1
-	
-	Field indent:Int
-	
-	Field compact:Int
-	
-End Type
-
-Rem
-bbdoc: Serializes BlitzMax type to JSON.
-End Rem
-Type TJConvSerializer
-
-	Field jconv:TJConv
-
-	Method Serialize:TJSON(source:Byte, sourceType:String)
-		Return New TJSONInteger.Create(source)
-	End Method
-
-	Method Serialize:TJSON(source:Short, sourceType:String)
-		Return New TJSONInteger.Create(source)
-	End Method
-	
-	Method Serialize:TJSON(source:Int, sourceType:String)
-		Return New TJSONInteger.Create(source)
-	End Method
-
-	Method Serialize:TJSON(source:UInt, sourceType:String)
-		Return New TJSONInteger.Create(source)
-	End Method
-
-	Method Serialize:TJSON(source:Long, sourceType:String)
-		Return New TJSONInteger.Create(source)
-	End Method
-
-	Method Serialize:TJSON(source:ULong, sourceType:String)
-		Return New TJSONInteger.Create(source)
-	End Method
-
-	Method Serialize:TJSON(source:Size_T, sourceType:String)
-		Return New TJSONInteger.Create(source)
-	End Method
-					
-	Method Serialize:TJSON(source:Float, sourceType:String)
-		Return New TJSONReal.Create(source)
-	End Method
-
-	Method Serialize:TJSON(source:Double, sourceType:String)
-		Return New TJSONReal.Create(source)
-	End Method
-
-	Method Serialize:TJSON(source:String, sourceType:String)
-		Return New TJSONString.Create(source)
-	End Method
-
-	Method Serialize:TJSON(source:Object, sourceType:String)
-		Local json:TJSONObject = New TJSONObject.Create()
-		jconv.ToJson(json, source)
-		Return json
-	End Method
-	
-	Method Deserialize:Object(json:TJSON, typeId:TTypeId, obj:Object)
-		If TJSONObject(json) Then
-			If Not obj Then
-				obj = typeId.NewObject()
-			End If
-
-			For Local j:TJSON = EachIn TJSONObject(json)
-				Local f:TField = typeId.FindField(j.key)
-				
-				If Not f Then
-					For Local namedField:TField = EachIn typeId.Fields().Values()
-						Local meta:String = namedField.Metadata("serializedName")
-						If meta = j.key Then
-							f = namedField
-							Exit
-						End If
-						
-						meta = namedField.Metadata("alternateName")
-						If meta Then
-							For Local name:String = EachIn meta.Split(",")
-								If name = j.key Then
-									f = namedField
-									Exit
-								End If
-							Next
-						End If
-						If f Then
-							Exit
-						End If
-					Next
-				End If
-
-				If f Then
-					If f.Metadata("transient") Or f.Metadata("noDeserialize") Then
-						Continue
-					End If
-					
-					Local fieldType:TTypeId = f.TypeId()
-
-					If TJSONInteger(j) Then
-						Select fieldType
-							Case ByteTypeId,ShortTypeId,IntTypeId,UIntTypeId,LongTypeId,ULongTypeId,SizetTypeId,FloatTypeId,DoubleTypeId,StringTypeId
-								f.SetLong(obj, TJSONInteger(j).Value())
-						End Select
-
-						If fieldType.ExtendsType(ObjectTypeId) Then
-							Local fobj:Object = jconv.FromJson(j, fieldType, Null)
-						
-							If fobj Then
-								f.Set(obj, fobj)
-							End If
-						End If
-
-						Continue
-					End If
-
-					If TJSONBool(j) Then
-						Select fieldType
-							Case ByteTypeId,ShortTypeId,IntTypeId,UIntTypeId,LongTypeId,ULongTypeId,SizetTypeId,FloatTypeId,DoubleTypeId,StringTypeId
-								f.SetInt(obj, TJSONBool(j).isTrue)
-						End Select
-
-						If fieldType.ExtendsType(ObjectTypeId) Then
-							Local fobj:Object = jconv.FromJson(j, fieldType, Null)
-						
-							If fobj Then
-								f.Set(obj, fobj)
-							End If
-						End If
-
-						Continue
-					End If
-					
-					If TJSONReal(j) Then
-						Select fieldType
-							Case ByteTypeId,ShortTypeId,IntTypeId,UIntTypeId,LongTypeId,ULongTypeId,SizetTypeId,FloatTypeId,DoubleTypeId,StringTypeId
-								f.SetDouble(obj, TJSONReal(j).Value())
-						End Select
-
-						If fieldType.ExtendsType(ObjectTypeId) Then
-							Local fobj:Object = jconv.FromJson(j, fieldType, Null)
-						
-							If fobj Then
-								f.Set(obj, fobj)
-							End If
-						End If
-
-						Continue
-					End If
-					
-					If TJSONString(j) Then
-						Select fieldType
-							Case ByteTypeId,ShortTypeId,IntTypeId,UIntTypeId,LongTypeId,ULongTypeId,SizetTypeId,FloatTypeId,DoubleTypeId,StringTypeId
-								f.SetString(obj, TJSONString(j).Value())
-								Continue
-						End Select
-						
-						If fieldType.ExtendsType(ArrayTypeId) Or fieldType.ExtendsType(ObjectTypeId) Then
-						
-							Local fobj:Object = jconv.FromJson(j, fieldType, Null)
-						
-							If fobj Then
-								f.Set(obj, fobj)
-							End If
-						
-						End If
-
-						Continue
-					End If
-					
-					If TJSONArray(j) Then
-
-						If fieldType.ExtendsType(ArrayTypeId) Then
-
-							Local arrayObj:Object = jconv.FromJson(TJSONArray(j), fieldType, Null)
-							
-							f.Set(obj, arrayObj)
-						End If
-						Continue
-					End If
-					
-					If TJSONObject(j) Then
-					
-						If fieldType.ExtendsType(ObjectTypeId) Then
-							
-							Local o:Object = jconv.FromJson(j, fieldType, Null)
-							If o Then
-								f.Set(obj, o)
-							End If
-						End If
-					End If
-				End If
-			Next
-		Else If TJSONArray(json) Then
-			
-			obj = Deserialize(TJSONArray(json), typeId, obj)
-		
-		Else If TJSONString(json) Then
-
-			obj = TJSONString(json).Value()
-
-		End If
-				
-		Return obj
-	End Method
-
-	Method Deserialize:Object(jsonArray:TJSONArray, typeId:TTypeId, arrayObj:Object)
-
-		Local size:Int = jsonArray.Size()
-
-		If Not size Then
-			Return typeId.NullArray()
-		End If
-
-		Local elementType:TTypeId = typeId.ElementType()
-
-		' arrayObj is Null Array?
-		' We need to read the first jsonarray element and create a new array of that type
-		If Not elementType And size Then
-			
-			Local jsonElement:TJSON = jsonArray.Get(0)
-			
-			If TJSONInteger(jsonElement) Then
-				typeId = TypeIdForTag("[]l")
-			Else If TJSONReal(jsonElement) Then
-				typeId = TypeIdForTag("[]d")
-			Else If TJSONString(jsonElement) Then
-				typeId = TypeIdForTag("[]$")
-			Else If TJSONObject(jsonElement) Then
-				typeId = TypeIdForTag("[]:Object")
-			Else If TJSONBool(jsonElement) Then
-				typeId = TypeIdForTag("[]i")
-			End If
-
-			elementType = typeId.ElementType()
-			If Not elementType Then
-				Return Null
-			End If
-		End If
-
-		If Not arrayObj Then
-			arrayObj = typeId.NewArray(size)
-		Else
-			arrayObj = typeId.ArraySlice(arrayObj, 0, size)
-		End If
-
-		For Local i:Int = 0 Until size
-			Local jsonElement:TJSON = jsonArray.Get(i)
-			
-			If TJSONInteger(jsonElement) Then
-				Select elementType
-					Case ByteTypeId,ShortTypeId,IntTypeId,UIntTypeId,LongTypeId,ULongTypeId,SizetTypeId,FloatTypeId,DoubleTypeId,StringTypeId
-						typeId.SetLongArrayElement(arrayObj, i, TJSONInteger(jsonElement).Value())
-				End Select
-				Continue
-			End If
-
-			If TJSONReal(jsonElement) Then
-				Select elementType
-					Case ByteTypeId,ShortTypeId,IntTypeId,UIntTypeId,LongTypeId,ULongTypeId,SizetTypeId,FloatTypeId,DoubleTypeId,StringTypeId
-						typeId.SetDoubleArrayElement(arrayObj, i, TJSONReal(jsonElement).Value())
-				End Select
-				Continue
-			End If
-
-			If TJSONBool(jsonElement) Then
-				Select elementType
-					Case ByteTypeId,ShortTypeId,IntTypeId,UIntTypeId,LongTypeId,ULongTypeId,SizetTypeId,FloatTypeId,DoubleTypeId,StringTypeId
-						typeId.SetIntArrayElement(arrayObj, i, TJSONBool(jsonElement).isTrue)
-				End Select
-				Continue
-			End If
-			
-			If TJSONString(jsonElement) Then
-				Select elementType
-					Case ByteTypeId,ShortTypeId,IntTypeId,UIntTypeId,LongTypeId,ULongTypeId,SizetTypeId,FloatTypeId,DoubleTypeId,StringTypeId
-						typeId.SetStringArrayElement(arrayObj, i, TJSONString(jsonElement).Value())
-				End Select
-				Continue
-			End If
-			
-			If TJSONObject(jsonElement) Then
-				If elementType.ExtendsType(ObjectTypeId) Then
-					Local o:Object = jconv.FromJson(jsonElement, elementType, Null)
-					typeId.SetArrayElement(arrayObj, i, o)
-				End If
-			End If						
-		Next
-		
-		Return arrayObj
-	End Method
-
-End Type
-
-Type TBool
-
-	Field value:Int
-	
-	Method New(value:Int)
-		Self.value = value
-	End Method
-
-End Type
-
-Type TByte
-
-	Field value:Byte
-
-	Method New(value:Byte)
-		Self.value = value
-	End Method
-	
-End Type
-
-Type TShort
-
-	Field value:Short
-
-	Method New(value:Short)
-		Self.value = value
-	End Method
-
-End Type
-
-Type TInt
-
-	Field value:Int
-
-	Method New(value:Int)
-		Self.value = value
-	End Method
-
-End Type
-
-Type TUInt
-
-	Field value:UInt
-
-	Method New(value:UInt)
-		Self.value = value
-	End Method
-
-End Type
-
-Type TSize_T
-
-	Field value:Size_T
-
-	Method New(value:Size_T)
-		Self.value = value
-	End Method
-
-End Type
-
-Type TLong
-
-	Field value:Long
-
-	Method New(value:Long)
-		Self.value = value
-	End Method
-
-End Type
-
-Type TULong
-
-	Field value:ULong
-
-	Method New(value:ULong)
-		Self.value = value
-	End Method
-
-End Type
-
-Type TFloat
-
-	Field value:Float
-
-	Method New(value:Float)
-		Self.value = value
-	End Method
-
-End Type
-
-Type TDouble
-
-	Field value:Double
-
-	Method New(value:Double)
-		Self.value = value
-	End Method
-
-End Type
-
-Type TBoolSerializer Extends TJConvSerializer
-
-	Method Serialize:TJSON(source:Object, sourceType:String) Override
-
-		Local value:TBool = TBool(source)
-		If value Then
-			Return New TJSONBool.Create(value.value)
-		End If
-	End Method
-
-	Method Deserialize:Object(json:TJSON, typeId:TTypeId, obj:Object) Override
-		If TJSONBool(json) Then
-			If Not obj Then
-				obj = New TBool(TJSONBool(json).isTrue)
-			End If
-		End If
-		
-		Return obj
-	End Method
-	
-End Type
-
-Type TByteSerializer Extends TJConvSerializer
-
-	Method Serialize:TJSON(source:Object, sourceType:String) Override
-		Local value:TByte = TByte(source)
-		If value Then
-			Return New TJSONInteger.Create(value.value)
-		End If
-	End Method
-
-	Method Deserialize:Object(json:TJSON, typeId:TTypeId, obj:Object) Override
-		If TJSONInteger(json) Then
-			If Not obj Then
-				obj = New TByte(Byte(TJSONInteger(json).Value()))
-			End If
-		End If
-		
-		Return obj
-	End Method
-	
-End Type
-
-Type TShortSerializer Extends TJConvSerializer
-
-	Method Serialize:TJSON(source:Object, sourceType:String) Override
-		Local value:TShort = TShort(source)
-		If value Then
-			Return New TJSONInteger.Create(value.value)
-		End If
-	End Method
-
-	Method Deserialize:Object(json:TJSON, typeId:TTypeId, obj:Object) Override
-		If TJSONInteger(json) Then
-			If Not obj Then
-				obj = New TShort(Short(TJSONInteger(json).Value()))
-			End If
-		End If
-		
-		Return obj
-	End Method
-	
-End Type
-
-Type TIntSerializer Extends TJConvSerializer
-
-	Method Serialize:TJSON(source:Object, sourceType:String) Override
-		Local value:TInt = TInt(source)
-		If value Then
-			Return New TJSONInteger.Create(value.value)
-		End If
-	End Method
-
-	Method Deserialize:Object(json:TJSON, typeId:TTypeId, obj:Object) Override
-		If TJSONInteger(json) Then
-			If Not obj Then
-				obj = New TInt(Int(TJSONInteger(json).Value()))
-			End If
-		End If
-		
-		Return obj
-	End Method
-	
-End Type
-
-Type TUIntSerializer Extends TJConvSerializer
-
-	Method Serialize:TJSON(source:Object, sourceType:String) Override
-		Local value:TUInt = TUInt(source)
-		If value Then
-			Return New TJSONInteger.Create(value.value)
-		End If
-	End Method
-
-	Method Deserialize:Object(json:TJSON, typeId:TTypeId, obj:Object) Override
-		If TJSONInteger(json) Then
-			If Not obj Then
-				obj = New TUInt(UInt(TJSONInteger(json).Value()))
-			End If
-		End If
-		
-		Return obj
-	End Method
-	
-End Type
-
-Type TSizetSerializer Extends TJConvSerializer
-
-	Method Serialize:TJSON(source:Object, sourceType:String) Override
-		Local value:TSize_T = TSize_T(source)
-		If value Then
-			Return New TJSONInteger.Create(value.value)
-		End If
-	End Method
-
-	Method Deserialize:Object(json:TJSON, typeId:TTypeId, obj:Object) Override
-		If TJSONInteger(json) Then
-			If Not obj Then
-				obj = New TSize_T(Size_T(TJSONInteger(json).Value()))
-			End If
-		End If
-		
-		Return obj
-	End Method
-	
-End Type
-
-Type TLongSerializer Extends TJConvSerializer
-
-	Method Serialize:TJSON(source:Object, sourceType:String) Override
-		Local value:TLong = TLong(source)
-		If value Then
-			Return New TJSONInteger.Create(value.value)
-		End If
-	End Method
-
-	Method Deserialize:Object(json:TJSON, typeId:TTypeId, obj:Object) Override
-		If TJSONInteger(json) Then
-			If Not obj Then
-				obj = New TLong(Long(TJSONInteger(json).Value()))
-			End If
-		End If
-		
-		Return obj
-	End Method
-	
-End Type
-
-Type TULongSerializer Extends TJConvSerializer
-
-	Method Serialize:TJSON(source:Object, sourceType:String) Override
-		Local value:TULong = TULong(source)
-		If value Then
-			Return New TJSONInteger.Create(value.value)
-		End If
-	End Method
-
-	Method Deserialize:Object(json:TJSON, typeId:TTypeId, obj:Object) Override
-		If TJSONInteger(json) Then
-			If Not obj Then
-				obj = New TULong(ULong(TJSONInteger(json).Value()))
-			End If
-		End If
-		
-		Return obj
-	End Method
-	
-End Type
-
-Type TFloatSerializer Extends TJConvSerializer
-
-	Method Serialize:TJSON(source:Object, sourceType:String) Override
-		Local value:TFloat = TFloat(source)
-		If value Then
-			Return New TJSONReal.Create(value.value)
-		End If
-	End Method
-
-	Method Deserialize:Object(json:TJSON, typeId:TTypeId, obj:Object) Override
-		If TJSONReal(json) Then
-			If Not obj Then
-				obj = New TFloat(Float(TJSONReal(json).Value()))
-			End If
-		End If
-		
-		Return obj
-	End Method
-	
-End Type
-
-Type TDoubleSerializer Extends TJConvSerializer
-
-	Method Serialize:TJSON(source:Object, sourceType:String) Override
-		Local value:TDouble = TDouble(source)
-		If value Then
-			Return New TJSONReal.Create(value.value)
-		End If
-	End Method
-
-	Method Deserialize:Object(json:TJSON, typeId:TTypeId, obj:Object) Override
-		If TJSONReal(json) Then
-			If Not obj Then
-				obj = New TDouble(Double(TJSONReal(json).Value()))
-			End If
-		End If
-		
-		Return obj
-	End Method
-	
-End Type

+ 0 - 74
jconv.mod/tests/data.json

@@ -1,74 +0,0 @@
-[
-  {
-    "id": 1,
-    "first_name": "Florencia",
-    "last_name": "Bagg",
-    "email": "[email protected]",
-    "gender": "Female",
-    "ip_address": "111.39.46.159",
-    "language": "Dutch",
-    "locations": [
-      {
-        "lat": 33.5311408,
-        "lng": 131.3266966
-      }
-    ]
-  },
-  {
-    "id": 2,
-    "first_name": "Korey",
-    "last_name": "Baurerich",
-    "email": "[email protected]",
-    "gender": "Male",
-    "ip_address": "246.176.163.25",
-    "language": "Telugu",
-    "locations": [
-      {
-        "lat": 49.4575108,
-        "lng": 18.2598032
-      },
-      {
-        "lat": 50.4575108,
-        "lng": 18.2598032
-      },
-      {
-        "lat": 51.4575108,
-        "lng": 18.2598032
-      }
-    ]
-  },
-  {
-    "id": 3,
-    "first_name": "Stanwood",
-    "last_name": "Straffon",
-    "email": "[email protected]",
-    "gender": "Male",
-    "ip_address": "42.149.0.53",
-    "language": "Nepali"
-  },
-  {
-    "id": 4,
-    "first_name": "Washington",
-    "last_name": "Tynemouth",
-    "email": "[email protected]",
-    "gender": "Male",
-    "ip_address": "176.38.52.23",
-    "language": "Finnish",
-    "locations": []
-  },
-  {
-    "id": 5,
-    "first_name": "Sean",
-    "last_name": "Northin",
-    "email": "[email protected]",
-    "gender": "Female",
-    "ip_address": "194.75.65.15",
-    "language": "Danish",
-    "locations": [
-      {
-        "lat": 51.6256317,
-        "lng": 21.9326303
-      }
-    ]
-  }
-]

+ 0 - 582
jconv.mod/tests/test.bmx

@@ -1,582 +0,0 @@
-SuperStrict
-
-Framework brl.standardio
-Import brl.jconv
-Import BRL.MaxUnit
-
-New TTestSuite.run()
-
-Type TJConvTest Extends TTest
-
-	Field jconv:TJConv
-	
-	Method setup() { before }
-		jconv = New TJConvBuilder.WithEmptyArrays().WithBoxing().Build()
-	End Method
-
-End Type
-
-Type TArrayTest Extends TJConvTest
-
-	Const EMPTY_ARRAY:String = "[]"
-	Const EMPTY_OBJECT:String = "{}"
-	Const STRING_ARRAY:String = "[~qOne~q, ~qTwo~q, ~qThree~q]"
-	Const INT_ARRAY:String = "[1, 2, 3, 4, 5]"
-	Const JSON_TYPES:String = "{~qfByte~q: 1, ~qfShort~q: 2, ~qfInt~q: 3, ~qfUInt~q: 4, ~qfLong~q: 5, ~qfULong~q: 6, ~qfSizeT~q: 7, ~qfFloat~q: 8.0, ~qfDouble~q: 9.0, ~qfString~q: ~q10~q, ~qfObject~q: {~qx~q: 1, ~qy~q: 2, ~qz~q: 3}}"
-	Const JSON_TYPES_SER:String = "{~qfByte~q: 1, ~qfShort~q: 2, ~qfInt~q: 3, ~qfUInt~q: 4, ~qfLong~q: 5, ~qfULong~q: 6, ~qfSizeT~q: 7, ~qfFloat~q: 8.0, ~qfDouble~q: 9.0, ~qfString~q: ~q10~q, ~qfObject~q: {~qz~q: 3, ~qy~q: 2, ~qx~q: 1}}"
-	Const JSON_CONTAINER:String = "{~qbox~q: ~q10,10,100,150~q}"
-	Const JSON_SER_NAME:String = "{~qname~q: ~qone~q, ~qname1~q: ~qtwo~q, ~qc~q: ~qthree~q}"
-	Const JSON_ALT_SER_NAME:String = "{~qa~q: ~qone~q, ~qname3~q: ~qtwo~q, ~qc~q: ~qthree~q}"
-	Const JSON_WITH_BOOL_ON:String = "{~qonOff~q: true}"
-	Const JSON_WITH_BOOL_OFF:String = "{~qonOff~q: false}"
-	Const JSON_BOX_BOOL_ON:String = "{~qb1~q: true}"
-	Const JSON_BOX_BOOL_OFF:String = "{~qb1~q: false}"
-	Const JSON_BOX_BYTE:String = "{~qb2~q: 42}"
-	Const JSON_BOX_SHORT:String = "{~qb3~q: 84}"
-	Const JSON_BOX_INT:String = "{~qb4~q: -99}"
-	Const JSON_BOX_UINT:String = "{~qb5~q: 6600}"
-	Const JSON_BOX_LONG:String = "{~qb6~q: 54321}"
-	Const JSON_BOX_ULONG:String = "{~qb7~q: 96}"
-	Const JSON_BOX_SIZE_T:String = "{~qb8~q: 100}"
-	Const JSON_BOX_FLOAT:String = "{~qb9~q: 7.5}"
-	Const JSON_BOX_DOUBLE:String = "{~qb10~q: 68.418}"
-	Const JSON_PREC:String = "{~qp1~q: 5.352, ~qp2~q: 65.698}"
-	Const JSON_SER_NAME_COMPACT:String = "{~qname~q:~qone~q,~qname1~q:~qtwo~q,~qc~q:~qthree~q}"
-	Const JSON_SER_NAME_PRETTY:String = "{~n  ~qname~q: ~qone~q,~n  ~qname1~q: ~qtwo~q,~n  ~qc~q: ~qthree~q~n}"
-	Const JSON_TRANS_NO_B:String = "{~qa~q: ~qone~q, ~qc~q: ~qthree~q}"
-	Const JSON_TRANS:String = "{~qa~q: ~qone~q, ~qb~q: ~qtwo~q, ~qc~q: ~qthree~q}"
-	Const JSON_IGNORE_SER:String = "{~qa~q: ~qone~q, ~qc~q: ~qthree~q}"
-	Const JSON_IGNORE:String = "{~qa~q: ~qone~q, ~qb~q: ~qtwo~q, ~qc~q: ~qthree~q, ~qd~q: ~qfour~q}"
-
-	Method testEmptyObject() { test }
-		Local obj:Object
-		
-		assertEquals(EMPTY_OBJECT, jconv.ToJson(obj))
-	End Method
-
-	Method testEmptyArray() { test }
-		Local array:Object[]
-		
-		array = Object[](jconv.FromJson(EMPTY_ARRAY, array))
-		
-		assertEquals(0, array.length)
-
-		assertEquals(EMPTY_ARRAY, jconv.ToJson(array))
-	End Method
-
-	Method testEmptyArrayWithoutEmpties() { test }
-		Local array:Object[]
-		
-		array = Object[](jconv.FromJson(EMPTY_ARRAY, array))
-		
-		assertEquals(0, array.length)
-
-		assertEquals(EMPTY_ARRAY, New TJConvBuilder.Build().ToJson(array))
-	End Method
-
-	Method testStringsArray() { test }
-		Local array:String[1]
-		
-		array = String[](jconv.FromJson(STRING_ARRAY, array))
-		
-		assertEquals(3, array.length)
-		
-		assertEquals(STRING_ARRAY, jconv.ToJson(array))
-	End Method
-
-	Method testStringsName() { test }		
-		Local array:String[] = String[](jconv.FromJson(STRING_ARRAY, "String[]"))
-		
-		assertEquals(3, array.length)
-		
-		assertEquals(STRING_ARRAY, jconv.ToJson(array))
-	End Method
-
-	Method testIntsArray() { test }
-		Local array:Int[1]
-		
-		array = Int[](jconv.FromJson(INT_ARRAY, array))
-		
-		assertEquals(5, array.length)
-		
-		assertEquals(INT_ARRAY, jconv.ToJson(array))
-	End Method
-
-	Method testIntsName() { test }
-		Local array:Int[] = Int[](jconv.FromJson(INT_ARRAY, "Int[]"))
-		
-		assertEquals(5, array.length)
-		
-		assertEquals(INT_ARRAY, jconv.ToJson(array))
-	End Method
-
-	Method testData() { test }
-		Local stream:TStream = ReadStream("data.json")
-		
-		Local array:TData[] = TData[](jconv.FromJson(stream, "TData[]"))
-		
-		stream.Close()
-		
-		assertNotNull(array)
-		assertEquals(5, array.length)
-		assertEquals("194.75.65.15", array[4].ip_address)
-		
-		assertNotNull(array[1].locations)
-		assertNull(array[2].locations)
-		assertEquals(3, array[1].locations.length)
-		assertEquals(50.4575108:Double, array[1].locations[1].lat)
-	End Method
-	
-	Method testFieldTypes() { test }
-		Local types:TTypes = New TTypes
-		
-		assertEquals(JSON_TYPES, jconv.ToJson(types)) 
-	End Method
-
-	Method testObjectSerializer() { test }
-		jconv = New TJConvBuilder.RegisterSerializer("TEmbedded", New TEmbeddedSerializer).Build()
-
-		Local types:TTypes = New TTypes
-		assertEquals(JSON_TYPES_SER, jconv.ToJson(types)) 
-	End Method
-	
-	Method testCustomSerializer() { test }
-		Local serializer:TBoxSerializer = New TBoxSerializer
-		jconv = New TJConvBuilder.RegisterSerializer("TBox", serializer).Build()
-
-		Local container:TContainer = New TContainer(New TBox(10, 10, 100, 150))
-
-		assertEquals(JSON_CONTAINER, jconv.ToJson(container))
-
-		Local c2:TContainer = TContainer(jconv.FromJson(JSON_CONTAINER, "TContainer"))
-		
-		assertNotNull(c2)
-		assertNotNull(c2.box)
-		assertEquals(10, c2.box.x)
-		assertEquals(10, c2.box.y)
-		assertEquals(100, c2.box.w)
-		assertEquals(150, c2.box.h)
-	End Method
-
-	Method testFieldNameSerialize() { test }
-		Local name1:TSName = New TSName
-		name1.a = "one"
-		name1.b = "two"
-		name1.c = "three"
-		
-		assertEquals(JSON_SER_NAME, jconv.ToJson(name1))
-
-		Local name2:TSName = TSName(jconv.FromJson(JSON_SER_NAME, "TSName"))
-		assertNotNull(name2)
-		assertEquals(name1.a, name2.a)
-		assertEquals(name1.b, name2.b)
-		assertEquals(name1.c, name2.c)
-
-		Local name3:TSName = TSName(jconv.FromJson(JSON_ALT_SER_NAME, "TSName"))
-		assertNotNull(name3)
-		assertEquals(name1.a, name3.a)
-		assertEquals(name1.b, name3.b)
-		assertEquals(name1.c, name3.c)
-	End Method
-
-	Method testWithBool() { test }
-		Local obj:TWithBool = TWithBool(jconv.FromJson(JSON_WITH_BOOL_ON, "TWithBool"))
-		
-		assertNotNull(obj)
-		assertEquals(True, obj.onOff)
-
-		obj = TWithBool(jconv.FromJson(JSON_WITH_BOOL_OFF, "TWithBool"))
-		
-		assertNotNull(obj)
-		assertEquals(False, obj.onOff)
-	End Method
-
-	Method testBoxing() { test }
-		Local boxed:TBoxed = New TBoxed
-		
-		assertEquals(EMPTY_OBJECT, jconv.ToJson(boxed))
-		
-		boxed.b1 = New TBool(True)
-		assertEquals(JSON_BOX_BOOL_ON, jconv.ToJson(boxed))
-		boxed.b1.value = False
-		assertEquals(JSON_BOX_BOOL_OFF, jconv.ToJson(boxed))
-		boxed.b1 = Null
-
-		boxed.b2 = New TByte(42)
-		assertEquals(JSON_BOX_BYTE, jconv.ToJson(boxed))
-		boxed.b2 = Null
-
-		boxed.b3 = New TShort(84)
-		assertEquals(JSON_BOX_SHORT, jconv.ToJson(boxed))
-		boxed.b3 = Null
-
-		boxed.b4 = New TInt(-99)
-		assertEquals(JSON_BOX_INT, jconv.ToJson(boxed))
-		boxed.b4 = Null
-
-		boxed.b5 = New TUInt(6600)
-		assertEquals(JSON_BOX_UINT, jconv.ToJson(boxed))
-		boxed.b5 = Null
-
-		boxed.b6 = New TLong(54321)
-		assertEquals(JSON_BOX_LONG, jconv.ToJson(boxed))
-		boxed.b6 = Null
-
-		boxed.b7 = New TULong(96)
-		assertEquals(JSON_BOX_ULONG, jconv.ToJson(boxed))
-		boxed.b7 = Null
-
-		boxed.b8 = New TSize_T(100)
-		assertEquals(JSON_BOX_SIZE_T, jconv.ToJson(boxed))
-		boxed.b8 = Null
-
-		boxed.b9 = New TFloat(7.5)
-		assertEquals(JSON_BOX_FLOAT, jconv.ToJson(boxed), 0.01)
-		boxed.b9 = Null
-
-		boxed.b10 = New TDouble(68.484)
-		Local s:String = jconv.ToJson(boxed)
-		Local dboxed:TBoxed = TBoxed(jconv.FromJson(s, "TBoxed"))
-		assertNotNull(dboxed.b10)
-		assertEquals(68.484, dboxed.b10.value, 0.1)
-		boxed.b10 = Null
-		
-	End Method
-	
-	Method testUnboxing() { test }
-		Local boxed:TBoxed = TBoxed(jconv.FromJson(EMPTY_OBJECT, "TBoxed"))
-		
-		assertNull(boxed.b1)
-		assertNull(boxed.b2)
-		assertNull(boxed.b3)
-		assertNull(boxed.b4)
-		assertNull(boxed.b5)
-		assertNull(boxed.b6)
-		assertNull(boxed.b7)
-		assertNull(boxed.b8)
-		assertNull(boxed.b9)
-		assertNull(boxed.b10)
-
-		boxed = TBoxed(jconv.FromJson(JSON_BOX_BOOL_ON, "TBoxed"))
-		
-		assertNotNull(boxed.b1)
-		assertEquals(True, boxed.b1.value)
-
-		boxed = TBoxed(jconv.FromJson(JSON_BOX_BOOL_OFF, "TBoxed"))
-		
-		assertNotNull(boxed.b1)
-		assertEquals(False, boxed.b1.value)
-
-		boxed = TBoxed(jconv.FromJson(JSON_BOX_BYTE, "TBoxed"))
-
-		assertNotNull(boxed.b2)
-		assertEquals(42, boxed.b2.value)
-		
-		boxed = TBoxed(jconv.FromJson(JSON_BOX_SHORT, "TBoxed"))
-
-		assertNotNull(boxed.b3)
-		assertEquals(84, boxed.b3.value)
-
-		boxed = TBoxed(jconv.FromJson(JSON_BOX_INT, "TBoxed"))
-
-		assertNotNull(boxed.b4)
-		assertEquals(-99, boxed.b4.value)
-
-		boxed = TBoxed(jconv.FromJson(JSON_BOX_UINT, "TBoxed"))
-
-		assertNotNull(boxed.b5)
-		assertEquals(6600, boxed.b5.value)
-
-		boxed = TBoxed(jconv.FromJson(JSON_BOX_LONG, "TBoxed"))
-
-		assertNotNull(boxed.b6)
-		assertEquals(54321, boxed.b6.value)
-
-		boxed = TBoxed(jconv.FromJson(JSON_BOX_ULONG, "TBoxed"))
-
-		assertNotNull(boxed.b7)
-		assertEquals(96, boxed.b7.value)
-
-		boxed = TBoxed(jconv.FromJson(JSON_BOX_SIZE_T, "TBoxed"))
-
-		assertNotNull(boxed.b8)
-		assertEquals(100, boxed.b8.value)
-
-		boxed = TBoxed(jconv.FromJson(JSON_BOX_FLOAT, "TBoxed"))
-
-		assertNotNull(boxed.b9)
-		assertEquals(7.5, boxed.b9.value, 0.1)
-
-		boxed = TBoxed(jconv.FromJson(JSON_BOX_DOUBLE, "TBoxed"))
-		assertNotNull(boxed.b10)
-		assertEquals(68.484, boxed.b10.value, 0.1)
-		
-	End Method
-
-	Method testPrecision() { test }
-
-		Local prec:TPrec = New TPrec(5.3521, 65.6982902)
-
-		jconv = New TJConvBuilder.WithPrecision(3).Build()
-		
-		assertEquals(JSON_PREC, jconv.ToJson(prec))
-
-	End Method
-
-	Method testCompact() { test }
-
-		jconv = New TJConvBuilder.WithCompact().Build()
-
-		Local name1:TSName = New TSName
-		name1.a = "one"
-		name1.b = "two"
-		name1.c = "three"
-		
-		assertEquals(JSON_SER_NAME_COMPACT, jconv.ToJson(name1))
-		
-	End Method
-
-	Method testIndent() { test }
-
-		jconv = New TJConvBuilder.WithIndent(2).Build()
-
-		Local name1:TSName = New TSName
-		name1.a = "one"
-		name1.b = "two"
-		name1.c = "three"
-		
-		assertEquals(JSON_SER_NAME_PRETTY, jconv.ToJson(name1))
-		
-	End Method
-
-	Method testDepth() { test }
-	
-		Local deep:TDeep = New TDeep
-		deep.inner = New TInner
-		deep.inner.deepest = New TDeepest
-		deep.inner.deepest.option1 = New TBool(True)
-				
-	End Method
-
-	Method testTransient() { test }
-		
-		Local trans:TTransient = New TTransient
-		trans.a = "one"
-		trans.b = "two"
-		trans.c = "three"
-		
-		assertEquals(JSON_TRANS_NO_B, jconv.ToJson(trans))
-		
-		trans = TTransient(jconv.FromJson(JSON_TRANS, "TTransient"))
-		assertEquals("one", trans.a)
-		assertNull(trans.b)
-		assertEquals("three", trans.c)
-	End Method
-
-	Method testIgnored() { test }
-		
-		Local ignored:TIgnored = New TIgnored
-		ignored.a = "one"
-		ignored.b = "two"
-		ignored.c = "three"
-		ignored.d = "four"
-		
-		assertEquals(JSON_IGNORE_SER, jconv.ToJson(ignored))
-		
-		ignored = TIgnored(jconv.FromJson(JSON_IGNORE, "TIgnored"))
-		assertEquals("one", ignored.a)
-		assertEquals("two", ignored.b)
-		assertNull(ignored.c)
-		assertNull(ignored.d)
-	End Method
-
-End Type
-
-Type TData
-	Field id:Long
-	Field first_name:String
-	Field last_name:String
-	Field email:String
-	Field gender:String
-	Field ip_address:String
-	Field language:String
-	Field locations:TLocation[]
-End Type
-
-Type TLocation
-	Field lat:Double
-	Field lng:Double
-End Type
-
-Type TTypes
-
-	Field fByte:Byte = 1
-	Field fShort:Short = 2
-	Field fInt:Int = 3
-	Field fUInt:UInt = 4
-	Field fLong:Long = 5
-	Field fULong:ULong = 6
-	Field fSizeT:Size_T = 7
-	Field fFloat:Float = 8
-	Field fDouble:Double = 9
-	Field fString:String = "10"
-	
-	Field fObject:TEmbedded = New TEmbedded(1, 2, 3)
-End Type
-
-Type TEmbedded
-
-	Field x:Int
-	Field y:Int
-	Field z:Int
-	
-	Method New(x:Int, y:Int, z:Int)
-		Self.x = x
-		Self.y = y
-		Self.z = z
-	End Method
-
-End Type
-
-Type TEmbeddedSerializer Extends TJConvSerializer
-
-	Method Serialize:TJSON(source:Object, sourceType:String)
-		Local embedded:TEmbedded = TEmbedded(source)
-		
-		Local json:TJSONObject = New TJSONObject.Create()
-		
-		json.Set("z", embedded.z)
-		json.Set("y", embedded.y)
-		json.Set("x", embedded.x)
-		
-		Return json
-	End Method
-
-End Type
-
-Type TContainer
-	Field box:TBox
-	
-	Method New(box:TBox)
-		Self.box = box
-	End Method
-End Type
-
-Type TBox
-
-	Field x:Int
-	Field y:Int
-	Field w:Int
-	Field h:Int
-
-	Method New(x:Int, y:Int, w:Int, h:Int)
-		Self.x = x
-		Self.y = y
-		Self.w = w
-		Self.h = h
-	End Method
-
-End Type
-
-Type TBoxSerializer Extends TJConvSerializer
-
-	Method Serialize:TJSON(source:Object, sourceType:String)
-		Local box:TBox = TBox(source)
-
-		Local json:TJSONString = New TJSONString.Create(box.x + "," + box.y + "," + box.w + "," + box.h)
-				
-		Return json
-	End Method
-
-	Method Deserialize:Object(json:TJSON, typeId:TTypeId, obj:Object)
-
-		If TJSONString(json) Then
-			If Not obj Then
-				obj = New TBox
-			End If
-			Local box:TBox = TBox(obj)
-			
-			Local parts:String[] = TJSONString(json).Value().Split(",")
-			box.x = parts[0].ToInt()
-			box.y = parts[1].ToInt()
-			box.w = parts[2].ToInt()
-			box.h = parts[3].ToInt()
-		End If
-
-		Return obj
-	End Method
-	
-End Type
-
-Type TSName
-
-	Field a:String { serializedName="name" }
-	Field b:String { serializedName="name1" alternateName="name2,name3" }
-	Field c:String
-
-End Type
-
-Type TWithBool
-
-	Field onOff:Int
-
-End Type
-
-Type TBoxed
-
-	Field b1:TBool
-	Field b2:TByte
-	Field b3:TShort
-	Field b4:TInt
-	Field b5:TUInt
-	Field b6:TLong
-	Field b7:TULong
-	Field b8:TSize_T
-	Field b9:TFloat
-	Field b10:TDouble
-
-End Type
-
-
-Type TPrec
-
-	Field p1:Float
-	Field p2:Double
-
-	Method New(p1:Float, p2:Double)
-		Self.p1 = p1
-		Self.p2 = p2
-	End Method
-	
-End Type
-
-Type TDeep
-
-	Field inner:TInner
-
-End Type
-
-Type TInner
-
-	Field deepest:TDeepest
-
-End Type
-
-Type TDeepest
-
-	Field option1:TBool
-
-End Type
-
-Type TTransient
-	Field a:String
-	Field b:String { transient }
-	Field c:String
-End Type
-
-Type TIgnored
-	Field a:String
-	Field b:String { noSerialize }
-	Field c:String { noDeserialize }
-	Field d:String { noSerialize noDeserialize }
-End Type

+ 0 - 206
json.mod/common.bmx

@@ -1,206 +0,0 @@
-' Copyright (c) 2014-2019 Bruce A Henderson
-' 
-' Permission is hereby granted, free of charge, to any person obtaining a copy
-' of this software and associated documentation files (the "Software"), to deal
-' in the Software without restriction, including without limitation the rights
-' to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-' copies of the Software, and to permit persons to whom the Software is
-' furnished to do so, subject to the following conditions:
-' 
-' The above copyright notice and this permission notice shall be included in
-' all copies or substantial portions of the Software.
-' 
-' THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-' IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-' FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-' AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-' LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-' OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-' THE SOFTWARE.
-' 
-SuperStrict
-
-Import BRL.Stream
-Import Pub.Jansson
-
-Import "source.bmx"
-
-
-Extern
-
-	Function json_array:Byte Ptr()
-	
-	Function bmx_json_decref(handle:Byte Ptr)
-
-	Function bmx_json_string_nocheck:Byte Ptr(Text:String)
-	Function bmx_json_string_value:String(handle:Byte Ptr)
-	
-	Function bmx_json_array_get:Object(handle:Byte Ptr, index:Int)
-	Function json_array_clear:Int(handle:Byte Ptr)
-	Function json_array_remove:Int(handle:Byte Ptr, index:Int)
-	Function bmx_json_array_size:Int(handle:Byte Ptr)
-	Function bmx_json_array_set:Int(handle:Byte Ptr, index:Int, value:Byte Ptr)
-	Function bmx_json_array_append:Int(handle:Byte Ptr, value:Byte Ptr)
-	Function bmx_json_array_insert:Int(handle:Byte Ptr, index:Int, value:Byte Ptr)
-	
-	Function bmx_json_dumps:String(handle:Byte Ptr, flags:Int, indent:Int, precision:Int)
-?bmxng
-	Function bmx_json_dump_callback:Int(handle:Byte Ptr, callback:Size_T(buffer:Byte Ptr, size:Size_T, data:TStream), stream:TStream, flags:Int, indent:Int, precision:Int)
-	Function bmx_json_load_callback:Object(callback:Size_T(buffer:Byte Ptr, size:Size_T, data:TStream), Text:TStream, flags:Int)
-?Not bmxng
-	Function bmx_json_dump_callback:Int(handle:Byte Ptr, callback:Int(buffer:Byte Ptr, size:Int, data:TStream), stream:TStream, flags:Int, indent:Int, precision:Int)
-	Function bmx_json_load_callback:Object(callback:Int(buffer:Byte Ptr, size:Int, data:TStream), Text:TStream, flags:Int)
-?
-	Function bmx_json_loads:Object(Text:String, flags:Int)
-	
-	Function bmx_json_integer:Byte Ptr(v:Long)
-	Function bmx_json_integer_value(handle:Byte Ptr, v:Long Ptr)
-	Function bmx_json_integer_set:Int(handle:Byte Ptr, v:Long)
-	
-	Function json_real:Byte Ptr(v:Double)
-	Function json_real_value:Double(handle:Byte Ptr)
-	Function json_real_set:Int(handle:Byte Ptr, v:Double)
-	
-	Function json_object:Byte Ptr()
-	Function bmx_json_object_size:Int(handle:Byte Ptr)
-	Function bmx_json_object_get:Object(handle:Byte Ptr, key:String)
-	Function bmx_json_object_set_nocheck:Int(handle:Byte Ptr, key:String, value:Byte Ptr)
-	Function bmx_json_object_del:Int(handle:Byte Ptr, key:String)
-	Function json_object_clear:Int(handle:Byte Ptr)
-	Function json_object_update:Int(handle:Byte Ptr, other:Byte Ptr)
-	Function json_object_update_existing:Int(handle:Byte Ptr, other:Byte Ptr)
-	Function json_object_update_missing:Int(handle:Byte Ptr, other:Byte Ptr)
-	
-	Function json_object_iter:Byte Ptr(handle:Byte Ptr)
-	Function json_object_iter_next:Byte Ptr(handle:Byte Ptr, iter:Byte Ptr)
-	Function bmx_json_object_iter_value:Object(iter:Byte Ptr)
-
-	Function bmx_json_bool:Byte Ptr(v:Int)
-	
-End Extern
-
-
-Const JSON_TYPE_OBJECT:Int = 0
-Const JSON_TYPE_ARRAY:Int = 1
-Const JSON_TYPE_STRING:Int = 2
-Const JSON_TYPE_INTEGER:Int = 3
-Const JSON_TYPE_REAL:Int = 4
-Const JSON_TYPE_TRUE:Int = 5
-Const JSON_TYPE_FALSE:Int = 6
-Const JSON_TYPE_NULL:Int = 7
-
-
-Const JSON_MAX_INDENT:Int = $1F
-Rem
-bbdoc: Enables a compact representation, i.e. sets the separator between array and object items to "," and between object keys and values to ":".
-about: Without this flag, the corresponding separators are ", " and ": " for more readable output.
-End Rem
-Const JSON_COMPACT:Int = $20
-Rem
-bbdoc: Guarantees the output to consist only of ASCII characters.
-about: This is achived by escaping all Unicode characters outside the ASCII range.
-End Rem
-Const JSON_ENSURE_ASCII:Int = $40
-Rem
-bbdoc: All the objects in output are sorted by key.
-about: This is useful e.g. if two JSON texts are diffed or visually compared.
-End Rem
-Const JSON_SORT_KEYS:Int = $80
-Rem
-bbdoc: Object keys in the output are sorted into the same order in which they were first inserted to the object.
-about: For example, decoding a JSON text and then encoding with this flag preserves the order of object keys.
-End Rem
-Const JSON_PRESERVE_ORDER:Int = $100
-Rem
-bbdoc: Makes it possible to encode any JSON value on its own.
-about: Without it, only objects and arrays can be passed as the root value to the encoding functions.
-Note: Encoding any value may be useful in some scenarios, but it's generally discouraged as it violates strict compatiblity with
-RFC 4627. If you use this flag, don't expect interoperatibility with other JSON systems.
-End Rem
-Const JSON_ENCODE_ANY:Int = $200
-Rem
-bbdoc: Escapes the / characters in strings with \/.
-End Rem
-Const JSON_ESCAPE_SLASH:Int = $400
-Rem
-bbdoc: The opening and closing characters of the top-level array ('[', ']') or object ('{', '}') are omitted during encoding.
-about: This flag is useful when concatenating multiple arrays or objects into a stream.
-End Rem
-Const JSON_EMBED:Int = $10000
-Rem
-bbdoc: Precision becomes the number of fraction digits.
-End Rem
-Const JSON_FRACTIONAL_DIGITS:Int = $20000
-
-Rem
-bbdoc: Pretty-prints the result, using newlines between array and object items, and indenting with n spaces.
-about: The valid range for n is between 0 and 31 (inclusive), other values result in an undefined output. If JSON_INDENT is not used or n is 0,
-no newlines are inserted between array and object items.
-End Rem
-Function JSON_INDENT:Int(n:Int)
-	Return n & JSON_MAX_INDENT
-End Function
-
-Rem
-bbdoc: Outputs all real numbers with at most n digits of precision.
-about: The valid range for n is between 0 and 31 (inclusive), and other values result in an undefined behavior.
-By default, the precision is 17, to correctly and losslessly encode all IEEE 754 double precision floating point numbers.
-End Rem
-Function JSON_REAL_PRECISION:Int(n:Int)
-	Return (n & $1F) Shl 11
-End Function
-
-Rem
-bbdoc: Issues a decoding error if any JSON object in the input text contains duplicate keys.
-about: Without this flag, the value of the last occurence of each key ends up in the result.
-Key equivalence is checked byte-by-byte, without special Unicode comparison algorithms.
-End Rem
-Const JSON_REJECT_DUPLICATES:Int = $1
-Rem
-bbdoc: With this flag enabled, the decoder stops after decoding a valid JSON array or object, and thus allows extra data after the JSON text. 
-about: By default, the decoder expects that its whole input constitutes a valid JSON text, and issues an error if there's extra data after the otherwise valid JSON input.
-Normally, reading will stop when the last ] or } in the JSON input is encountered. If both JSON_DISABLE_EOF_CHECK and JSON_DECODE_ANY flags
-are used, the decoder may read one extra UTF-8 code unit (up to 4 bytes of input). For example, decoding 4true correctly decodes
-the integer 4, but also reads the t. For this reason, if reading multiple consecutive values that are not arrays or objects,
-they should be separated by at least one whitespace character.
-End Rem
-Const JSON_DISABLE_EOF_CHECK:Int = $2
-Rem
-bbdoc: With this flag enabled, the decoder accepts any valid JSON value.
-about: By default, the decoder expects an array or object as the input.
-Note: Decoding any value may be useful in some scenarios, but it's generally discouraged as it violates strict compatiblity
-with RFC 4627. If you use this flag, don't expect interoperatibility with other JSON systems.
-End Rem
-Const JSON_DECODE_ANY:Int = $4
-Rem
-bbdoc: With this flag enabled the decoder interprets all numbers as real values. 
-about: JSON defines only one number type. Jansson distinguishes between ints and reals. For more information see Real vs. Integer. Integers that do
-not have an exact double representation will silently result in a loss of precision. Integers that cause a double overflow will cause an error.
-End Rem
-Const JSON_DECODE_INT_AS_REAL:Int = $8
-Rem
-bbdoc: Allows \u0000 escape inside string values.
-about: This is a safety measure; If you know your input can contain NUL bytes, use this flag. If you don't use this flag, you don't have
-to worry about NUL bytes inside strings.
-Object keys cannot have embedded NUL bytes even if this flag is used.
-End Rem
-Const JSON_ALLOW_NUL:Int = $10
-
-Const JSON_ERROR_UNKNOWN:Int = 0
-Const JSON_ERROR_OUT_OF_MEMORY:Int = 1
-Const JSON_ERROR_STACK_OVERFLOW:Int = 2
-Const JSON_ERROR_CANNOT_OPEN_FILE:Int = 3
-Const JSON_ERROR_INVALID_ARGUMENT:Int = 4
-Const JSON_ERROR_INVALID_UTF8:Int = 5
-Const JSON_ERROR_PREMATURE_END_OF_INPUT:Int = 6
-Const JSON_ERROR_END_OF_INPUT_EXPECTED:Int = 7
-Const JSON_ERROR_INVALID_SYNTAX:Int = 8
-Const JSON_ERROR_INVALID_FORMAT:Int = 9
-Const JSON_ERROR_WRONG_TYPE:Int = 10
-Const JSON_ERROR_NULL_CHARACTER:Int = 11
-Const JSON_ERROR_NULL_VALUE:Int = 12
-Const JSON_ERROR_NULL_BYTE_IN_KEY:Int = 13
-Const JSON_ERROR_DUPLICATE_KEY:Int = 14
-Const JSON_ERROR_NUMERIC_OVERFLOW:Int = 15
-Const JSON_ERROR_ITEM_NOT_FOUND:Int = 16
-Const JSON_ERROR_INDEX_OUT_OF_RANGE:Int = 17

+ 0 - 210
json.mod/glue.c

@@ -1,210 +0,0 @@
-/*
-  Copyright (c) 2014-2019 Bruce A Henderson
- 
-  Permission is hereby granted, free of charge, to any person obtaining a copy
-  of this software and associated documentation files (the "Software"), to deal
-  in the Software without restriction, including without limitation the rights
-  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-  copies of the Software, and to permit persons to whom the Software is
-  furnished to do so, subject to the following conditions:
-  
-  The above copyright notice and this permission notice shall be included in
-  all copies or substantial portions of the Software.
-  
-  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-  THE SOFTWARE.
-*/ 
-
-#include "jansson.h"
-
-#include "brl.mod/blitz.mod/blitz.h"
-
-#ifdef BMX_NG
-#define CB_PREF(func) func
-#else
-#define CB_PREF(func) _##func
-#endif
-
-BBObject * CB_PREF(brl_json_TJSON__create)(json_t * handle, int jsonType, BBString * key);
-BBObject * CB_PREF(brl_json_TJSONError__createError)(BBString * text, BBString * source, int line, int column, int position, int errorCode);
-BBObject * CB_PREF(brl_json_TJSONError__createNoError)(BBObject * js);
-
-void bmx_json_decref(json_t * handle);
-
-json_t * bmx_json_string_nocheck(BBString * text);
-BBString * bmx_json_string_value(json_t * handle);
-
-BBObject * bmx_json_array_get(json_t * handle, int index);
-int bmx_json_array_size(json_t * handle);
-int bmx_json_array_set(json_t * handle, int index, json_t * value);
-int bmx_json_array_append(json_t * handle, json_t * value);
-int bmx_json_array_insert(json_t * handle, int index, json_t * value);
-
-BBString * bmx_json_dumps(json_t * handle, int flags, int indent, int precision);
-int bmx_json_dump_callback(json_t * handle, json_dump_callback_t callback, BBObject * stream, int flags, int indent, int precision);
-BBObject * bmx_json_loads(BBString * text, int flags);
-BBObject * bmx_json_load_callback(json_load_callback_t callback, BBObject * stream, int flags);
-
-json_t * bmx_json_integer(BBInt64 v);
-void bmx_json_integer_value(json_t * handle, BBInt64 * v);
-int bmx_json_integer_set(json_t * handle, BBInt64 v);
-
-int bmx_json_object_size(json_t * handle);
-BBObject * bmx_json_object_get(json_t * handle, BBString * key);
-int bmx_json_object_set_nocheck(json_t * handle, BBString * key, json_t * value);
-int bmx_json_object_del(json_t * handle, BBString * key);
-
-BBObject * bmx_json_object_iter_value(void * iter);
-
-json_t * bmx_json_bool(int v);
-
-
-void bmx_json_decref(json_t * handle) {
-	json_decref(handle);
-}
-
-
-json_t * bmx_json_string_nocheck(BBString * text) {
-	char * s = bbStringToUTF8String(text);
-	json_t * ref = json_string_nocheck(s);
-	bbMemFree(s);
-	return ref;
-}
-
-BBString * bmx_json_string_value(json_t * handle) {
-	return bbStringFromUTF8String(json_string_value(handle));
-}
-
-BBObject * bmx_json_array_get(json_t * handle, int index) {
-	json_t * value = json_array_get(handle, index);
-	if (value) {
-		return CB_PREF(brl_json_TJSON__create)(json_incref(value), json_typeof(value), &bbEmptyString);
-	} else {
-		return &bbNullObject;
-	}
-}
-
-int bmx_json_array_size(json_t * handle) {
-	return json_array_size(handle);
-}
-
-int bmx_json_array_set(json_t * handle, int index, json_t * value) {
-	return json_array_set(handle, index, value);
-}
-
-int bmx_json_array_append(json_t * handle, json_t * value) {
-	return json_array_append(handle, value);
-}
-
-int bmx_json_array_insert(json_t * handle, int index, json_t * value) {
-	return json_array_insert(handle, index, value);
-}
-
-
-BBString * bmx_json_dumps(json_t * handle, int flags, int indent, int precision) {
-	char * s = json_dumps(handle, flags | JSON_INDENT(indent) | JSON_REAL_PRECISION(precision));
-	if (s) {
-		BBString * st = bbStringFromUTF8String(s);
-		free(s);
-		return st;
-	} else {
-		return &bbEmptyString;
-	}
-}
-
-int bmx_json_dump_callback(json_t * handle, json_dump_callback_t callback, BBObject * stream, int flags, int indent, int precision) {
-	return json_dump_callback(handle, callback, (void *)stream, flags | JSON_INDENT(indent) | JSON_REAL_PRECISION(precision));
-}
-
-BBObject * bmx_json_loads(BBString * text, int flags) {
-	char * t = bbStringToUTF8String(text);
-	
-	json_error_t error;
-	json_t * js = json_loads(t, flags, &error);
-	
-	if (!js) {
-		int errorCode = json_error_code(&error);
-	
-		return CB_PREF(brl_json_TJSONError__createError)(bbStringFromUTF8String(error.text), bbStringFromUTF8String(error.source),
-				error.line, error.column, error.position, errorCode);
-	}
-	
-	BBObject * ref = CB_PREF(brl_json_TJSON__create)(js, json_typeof(js), &bbEmptyString);
-	return CB_PREF(brl_json_TJSONError__createNoError)(ref);	
-}
-
-BBObject * bmx_json_load_callback(json_load_callback_t callback, BBObject * stream, int flags) {
-
-	json_error_t error;
-	json_t * js = json_load_callback(callback, (void *)stream, flags, &error);
-	
-	if (!js) {
-		int errorCode = json_error_code(&error);
-		
-		return CB_PREF(brl_json_TJSONError__createError)(bbStringFromUTF8String(error.text), bbStringFromUTF8String(error.source),
-				error.line, error.column, error.position, errorCode);
-	}
-	
-	BBObject * ref = CB_PREF(brl_json_TJSON__create)(js, json_typeof(js), &bbEmptyString);
-	return CB_PREF(brl_json_TJSONError__createNoError)(ref);	
-}
-
-json_t * bmx_json_integer(BBInt64 v) {
-	return json_integer(v);
-}
-
-void bmx_json_integer_value(json_t * handle, BBInt64 * v) {
-	*v = json_integer_value(handle);
-}
-
-int bmx_json_integer_set(json_t * handle, BBInt64 v) {
-	return json_integer_set(handle, v);
-}
-
-int bmx_json_object_size(json_t * handle) {
-	return json_object_size(handle);
-}
-
-BBObject * bmx_json_object_get(json_t * handle, BBString * key) {
-	char * k = bbStringToUTF8String(key);
-	json_t * obj = json_object_get(handle, k);
-	bbMemFree(k);
-	if (obj) {
-		return CB_PREF(brl_json_TJSON__create)(json_incref(obj), json_typeof(obj), key);
-	} else {
-		return &bbNullObject;
-	}
-}
-
-int bmx_json_object_set_nocheck(json_t * handle, BBString * key, json_t * value) {
-	char * k = bbStringToUTF8String(key);
-	int res = json_object_set_nocheck(handle, k, value);
-	bbMemFree(k);
-	return res;
-}
-
-int bmx_json_object_del(json_t * handle, BBString * key) {
-	char * k = bbStringToUTF8String(key);
-	int res = json_object_del(handle, k);
-	bbMemFree(k);
-	return res;
-}
-
-BBObject * bmx_json_object_iter_value(void * iter) {
-	const char * key = json_object_iter_key(iter);
-	json_t * value = json_object_iter_value(json_object_key_to_iter(key));
-	if (value) {
-		return CB_PREF(brl_json_TJSON__create)(json_incref(value), json_typeof(value), bbStringFromUTF8String(key));
-	} else {
-		return &bbNullObject;
-	}
-}
-
-json_t * bmx_json_bool(int v) {
-	return json_boolean(v);
-}

+ 0 - 789
json.mod/json.bmx

@@ -1,789 +0,0 @@
-' Copyright (c) 2014-2019 Bruce A Henderson
-' 
-' Permission is hereby granted, free of charge, to any person obtaining a copy
-' of this software and associated documentation files (the "Software"), to deal
-' in the Software without restriction, including without limitation the rights
-' to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-' copies of the Software, and to permit persons to whom the Software is
-' furnished to do so, subject to the following conditions:
-' 
-' The above copyright notice and this permission notice shall be included in
-' all copies or substantial portions of the Software.
-' 
-' THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-' IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-' FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-' AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-' LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-' OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-' THE SOFTWARE.
-' 
-SuperStrict
-
-Rem
-bbdoc: A JSON encoder/decoder.
-End Rem
-Module BRL.Json
-
-ModuleInfo "Version: 1.04"
-ModuleInfo "Author: Bruce A Henderson"
-ModuleInfo "License: MIT"
-ModuleInfo "Copyright: 2014-2019 Bruce A Henderson"
-
-ModuleInfo "History: 1.04"
-ModuleInfo "History: Added index operator overloading to TJSONArray."
-ModuleInfo "History: Added TJSONBool Create method."
-ModuleInfo "History: 1.03"
-ModuleInfo "History: Updated to Jansson 2.12"
-ModuleInfo "History: 1.02"
-ModuleInfo "History: Updated to Jansson 2.10.009ffa3"
-ModuleInfo "History: Added errorCode field to TJSONError."
-ModuleInfo "History: 1.01"
-ModuleInfo "History: Updated to Jansson 2.10"
-ModuleInfo "History: 1.00"
-ModuleInfo "History: Initial Release"
-
-ModuleInfo "CC_OPTS: -DHAVE_CONFIG_H"
-
-Import "common.bmx"
-
-Rem
-bbdoc: Base type for JSON objects.
-End Rem
-Type TJSON
-
-	Field jsonPtr:Byte Ptr
-	
-	Field key:String
-
-	Function _create:TJSON(jsonPtr:Byte Ptr, jsonType:Int, key:String) { nomangle }
-		Local this:TJSON
-		Select jsonType
-			Case JSON_TYPE_OBJECT
-				this = New TJSONObject
-			Case JSON_TYPE_ARRAY
-				this = New TJSONArray
-			Case JSON_TYPE_STRING
-				this = New TJSONString
-			Case JSON_TYPE_INTEGER
-				this = New TJSONInteger
-			Case JSON_TYPE_REAL
-				this = New TJSONReal
-			Case JSON_TYPE_TRUE
-				this = New TJSONBool
-				TJSONBool(this).isTrue = True
-			Case JSON_TYPE_FALSE
-				this = New TJSONBool
-			Case JSON_TYPE_NULL
-				this = New TJSONNull
-			Default
-				Return Null
-		End Select
-		
-		this.jsonPtr = jsonPtr
-		this.key = key
-		
-		Return this
-	End Function
-	
-	Rem
-	bbdoc: Returns the JSON representation of the object as a String, or NULL on error. 
-	about: Valid flags include #JSON_COMPACT, #JSON_ENSURE_ASCII, #JSON_SORT_KEYS, #JSON_PRESERVE_ORDER, #JSON_ENCODE_ANY and #JSON_ESCAPE_SLASH.
-	End Rem
-	Method SaveString:String(flags:Int = 0, indent:Int = 0, precision:Int = 17)
-		Return bmx_json_dumps(jsonPtr, flags, indent, precision)
-	End Method
-	
-	Rem
-	bbdoc: Writes the JSON representation of the object to the stream output.
-	about: The stream should already be open for writing.
-	Valid flags include #JSON_COMPACT, #JSON_ENSURE_ASCII, #JSON_SORT_KEYS, #JSON_PRESERVE_ORDER, #JSON_ENCODE_ANY and #JSON_ESCAPE_SLASH.
-	End Rem
-	Method SaveStream:Int(stream:TStream, flags:Int = 0, indent:Int = 0, precision:Int = 17)
-		Return bmx_json_dump_callback(jsonPtr, _dumpCallback, stream, flags, indent, precision)
-	End Method
-	
-	Rem
-	bbdoc: Loads JSON text from a String or TStream.
-	about: The stream should already be open for reading.
-	Valid flags include #JSON_REJECT_DUPLICATES, #JSON_DISABLE_EOF_CHECK, #JSON_DECODE_ANY, #JSON_DECODE_INT_AS_REAL and #JSON_ALLOW_NUL.
-	End Rem
-	Function Load:TJSON(data:Object, flags:Int = 0, error:TJSONError Var)
-	
-		Local err:TJSONError
-		
-		If String(data) Then
-			' load as text
-			err = TJSONError(bmx_json_loads(String(data), flags))
-			
-		Else If TStream(data) Then
-			' load as stream
-			err = TJSONError(bmx_json_load_callback(_loadCallback, TStream(data), flags))
-			
-		End If
-
-		If err 
-			If err._js Then
-				Return err._js
-			End If
-			
-			error = err
-		
-		End If
-		
-		Return Null
-	End Function
-
-?bmxng
-	Function _loadCallback:Size_T(buffer:Byte Ptr, buflen:Size_T, data:TStream)
-?Not bmxng
-	Function _loadCallback:Int(buffer:Byte Ptr, buflen:Int, data:TStream)
-?
-		Return data.Read(buffer, buflen)
-	End Function
-
-?bmxng
-	Function _dumpCallback:Size_T(buffer:Byte Ptr, size:Size_T, data:TStream)
-?Not bmxng
-	Function _dumpCallback:Int(buffer:Byte Ptr, size:Int, data:TStream)
-?
-		Return data.Write(buffer, size)
-	End Function
-
-	Method Delete()
-		If jsonPtr Then
-			bmx_json_decref(jsonPtr)
-			jsonPtr = Null
-		End If
-	End Method
-	
-End Type
-
-Rem
-bbdoc: A JSON array is an ordered collection of other JSON values.
-End Rem
-Type TJSONArray Extends TJSON
-
-	Rem
-	bbdoc: Creates a new TJSONArray.
-	End Rem
-	Method Create:TJSONArray()
-		jsonPtr = json_array()
-		Return Self
-	End Method
-
-	Rem
-	bbdoc: Returns the number of elements in array, or 0 if array is NULL
-	End Rem
-	Method Size:Int()
-		Return bmx_json_array_size(jsonPtr)
-	End Method
-	
-	Rem
-	bbdoc: Returns the element in array at position index.
-	about: The valid range for index is from 0 to the return value of Size() minus 1. If index is out of range, NULL is returned.
-	End Rem
-	Method Get:TJSON(index:Int)
-		Return TJSON(bmx_json_array_get(jsonPtr, index))
-	End Method
-	
-	Rem
-	bbdoc: Replaces the element in array at position index with value.
-	returns: 0 on success and -1 on error.
-	End Rem
-	Method Set:Int(index:Int, value:TJSON)
-		Return bmx_json_array_set(jsonPtr, index, value.jsonPtr)
-	End Method
-
-	Rem
-	bbdoc: Appends value to the end of array, growing the size of array by 1.
-	returns: 0 on success and -1 on error.
-	End Rem
-	Method Append:Int(value:TJSON)
-		Return bmx_json_array_append(jsonPtr, value.jsonPtr)
-	End Method
-
-	Rem
-	bbdoc: Inserts @value to array at position @index, shifting the elements at index and after it one position towards the end of the array. 
-	returns: 0 on success and -1 on error.
-	End Rem
-	Method Insert:Int(index:Int, value:TJSON)
-		Return bmx_json_array_insert(jsonPtr, index, value.jsonPtr)
-	End Method
-
-	Rem
-	bbdoc: Removes all elements from array.
-	returns: 0 on sucess and -1 on error.
-	End Rem
-	Method Clear:Int()
-		Return json_array_clear(jsonPtr)
-	End Method
-	
-	Rem
-	bbdoc: Removes the element in array at position index, shifting the elements after index one position towards the start of the array.
-	returns: 0 on success and -1 on error.
-	End Rem
-	Method Remove:Int(index:Int)
-		Return json_array_remove(jsonPtr, index)
-	End Method
-
-	Method ObjectEnumerator:TJSONArrayEnum()
-		Local enumeration:TJSONArrayEnum =New TJSONArrayEnum
-		enumeration.array = Self
-		Return enumeration
-	End Method
-
-	Rem
-	bbdoc: Returns the element in array at position index.
-	about: The valid range for index is from 0 to the return value of Size() minus 1. If index is out of range, NULL is returned.
-	End Rem
-	Method Operator [] :TJSON(index:Int)
-		Return Get(index)
-	End Method
-
-	Rem
-	bbdoc: Replaces the element in array at position index with value.
-	End Rem
-	Method Operator []= (index:Int, value:TJSON)
-		Set(index, value)
-	End Method
-
-End Type
-
-Type TJSONArrayEnum
-
-	Field array:TJSONArray
-	Field index:Int
-
-	Method HasNext:Int()
-		Return index < array.Size()
-	End Method
-
-	Method NextObject:Object()
-		Local value:Object=array.Get(index)
-		index:+ 1
-		Return value
-	End Method
-
-End Type
-
-Rem
-bbdoc: A JSON object is a dictionary of key-value pairs, where the key is a Unicode string and the value is any JSON value.
-End Rem
-Type TJSONObject Extends TJSON
-
-	Rem
-	bbdoc: Creates a new TJSONObject.
-	End Rem
-	Method Create:TJSONObject()
-		jsonPtr = json_object()
-		Return Self
-	End Method
-	
-	Rem
-	bbdoc: Returns the number of elements in the object.
-	End Rem
-	Method Size:Int()
-		Return bmx_json_object_size(jsonPtr)
-	End Method
-	
-	Rem
-	bbdoc: Gets a value corresponding to key from the object.
-	returns: Null if key is not found or on error.
-	End Rem
-	Method Get:TJSON(key:String)
-		Return TJSON(bmx_json_object_get(jsonPtr, key))
-	End Method
-	
-	Rem
-	bbdoc: Sets the value of key to value in the object.
-	returns: 0 on success and -1 on error.
-	about: If there already is a value for key, it is replaced by the new value. 
-	End Rem
-	Method Set:Int(key:String, value:TJSON)
-		Return bmx_json_object_set_nocheck(jsonPtr, key, value.jsonPtr)
-	End Method
-	
-	Rem
-	bbdoc: Sets the value of key To the #String value.
-	returns: 0 on success and -1 on error.
-	about: If there already is a value for key, it is replaced by the new value. 
-	End Rem
-	Method Set:Int(key:String, value:String)
-		Local v:TJSONString = New TJSONString.Create(value)
-		Return bmx_json_object_set_nocheck(jsonPtr, key, v.jsonPtr)
-	End Method
-	
-	Rem
-	bbdoc: Sets the value of key to the #Int value.
-	returns: 0 on success and -1 on error.
-	about: If there already is a value for key, it is replaced by the new value. 
-	End Rem
-	Method Set:Int(key:String, value:Int)
-		Local v:TJSONInteger = New TJSONInteger.Create(value)
-		Return bmx_json_object_set_nocheck(jsonPtr, key, v.jsonPtr)
-	End Method
-
-	Rem
-	bbdoc: Sets the value of key to the #Short value.
-	returns: 0 on success and -1 on error.
-	about: If there already is a value for key, it is replaced by the new value. 
-	End Rem
-	Method Set:Int(key:String, value:Short)
-		Local v:TJSONInteger = New TJSONInteger.Create(value)
-		Return bmx_json_object_set_nocheck(jsonPtr, key, v.jsonPtr)
-	End Method
-
-	Rem
-	bbdoc: Sets the value of key to the #Byte value.
-	returns: 0 on success and -1 on error.
-	about: If there already is a value for key, it is replaced by the new value. 
-	End Rem
-	Method Set:Int(key:String, value:Byte)
-		Local v:TJSONInteger = New TJSONInteger.Create(value)
-		Return bmx_json_object_set_nocheck(jsonPtr, key, v.jsonPtr)
-	End Method
-
-	Rem
-	bbdoc: Sets the value of key to the #Long value.
-	returns: 0 on success and -1 on error.
-	about: If there already is a value for key, it is replaced by the new value. 
-	End Rem
-	Method Set:Int(key:String, value:Long)
-		Local v:TJSONInteger = New TJSONInteger.Create(value)
-		Return bmx_json_object_set_nocheck(jsonPtr, key, v.jsonPtr)
-	End Method
-
-	Rem
-	bbdoc: Sets the value of key to the #UInt value.
-	returns: 0 on success and -1 on error.
-	about: If there already is a value for key, it is replaced by the new value. 
-	End Rem
-	Method Set:Int(key:String, value:UInt)
-		Local v:TJSONInteger = New TJSONInteger.Create(value)
-		Return bmx_json_object_set_nocheck(jsonPtr, key, v.jsonPtr)
-	End Method
-
-	Rem
-	bbdoc: Sets the value of key to the #ULong value.
-	returns: 0 on success and -1 on error.
-	about: If there already is a value for key, it is replaced by the new value. 
-	End Rem
-	Method Set:Int(key:String, value:ULong)
-		Local v:TJSONInteger = New TJSONInteger.Create(Long(value))
-		Return bmx_json_object_set_nocheck(jsonPtr, key, v.jsonPtr)
-	End Method
-
-	Rem
-	bbdoc: Sets the value of key to the #Size_t value.
-	returns: 0 on success and -1 on error.
-	about: If there already is a value for key, it is replaced by the new value. 
-	End Rem
-	Method Set:Int(key:String, value:Size_T)
-		Local v:TJSONInteger = New TJSONInteger.Create(Long(value))
-		Return bmx_json_object_set_nocheck(jsonPtr, key, v.jsonPtr)
-	End Method
-
-	Rem
-	bbdoc: Sets the value of key to the #Float value.
-	returns: 0 on success and -1 on error.
-	about: If there already is a value for key, it is replaced by the new value. 
-	End Rem
-	Method Set:Int(key:String, value:Float)
-		Local v:TJSONReal = New TJSONReal.Create(value)
-		Return bmx_json_object_set_nocheck(jsonPtr, key, v.jsonPtr)
-	End Method
-
-	Rem
-	bbdoc: Sets the value of key to the #Double value.
-	returns: 0 on success and -1 on error.
-	about: If there already is a value for key, it is replaced by the new value. 
-	End Rem
-	Method Set:Int(key:String, value:Double)
-		Local v:TJSONReal = New TJSONReal.Create(value)
-		Return bmx_json_object_set_nocheck(jsonPtr, key, v.jsonPtr)
-	End Method
-	
-	Rem
-	bbdoc: Deletes key from the Object If it exists.
-	returns: 0 on success, or -1 if key was not found. 
-	End Rem
-	Method Del:Int(key:String)
-		Return bmx_json_object_del(jsonPtr, key)
-	End Method
-	
-	Rem
-	bbdoc: Removes all elements from the object.
-	returns: 0 on success, -1 otherwise.
-	End Rem
-	Method Clear:Int()
-		Return json_object_clear(jsonPtr)
-	End Method
-	
-	Rem
-	bbdoc: Updates the object with the key-value pairs from @other, overwriting existing keys.
-	returns: 0 on success or -1 on error.
-	End Rem
-	Method Update:Int(other:TJSONObject)
-		Return json_object_update(jsonPtr, other.jsonPtr)
-	End Method
-	
-	Rem
-	bbdoc: Updates the object with the key-value pairs from @other, but only the values of existing keys are updated.
-	returns: 0 on success or -1 on error.
-	about: No new keys are created.
-	End Rem
-	Method UpdateExisting:Int(other:TJSONObject)
-		Return json_object_update_existing(jsonPtr, other.jsonPtr)
-	End Method
-
-	Rem
-	bbdoc: Updates the object with the key-value pairs from @other, but only new keys are created.
-	returns: 0 on success or -1 on error.
-	about: The value of any existing key is not changed.
-	End Rem
-	Method UpdateMissing:Int(other:TJSONObject)
-		Return json_object_update_missing(jsonPtr, other.jsonPtr)
-	End Method
-
-	Method ObjectEnumerator:TJSONObjectEnum()
-		Local enumeration:TJSONObjectEnum =New TJSONObjectEnum
-		enumeration.obj = Self
-		enumeration.objectIter = json_object_iter(jsonPtr)
-		Return enumeration
-	End Method
-	
-	Rem
-	bbdoc: Gets a String value corresponding to key from the object.
-	returns: Null if key is not found, the value is not a String, or on error.
-	End Rem
-	Method GetString:String(key:String)
-		Local s:TJSONString = TJSONString(bmx_json_object_get(jsonPtr, key))
-		If s Then
-			Return s.Value()
-		End If
-	End Method
-
-	Rem
-	bbdoc: Gets an Integer (Long) value corresponding to key from the object.
-	returns: Null if key is not found, the value is not an Integer, or on error.
-	End Rem
-	Method GetInteger:Long(key:String)
-		Local i:TJSONInteger = TJSONInteger(bmx_json_object_get(jsonPtr, key))
-		If i Then
-			Return i.Value()
-		End If
-	End Method
-
-	Rem
-	bbdoc: Gets a Real (Double) value corresponding to key from the object.
-	returns: Null if key is not found, the value is not a Real, or on error.
-	End Rem
-	Method GetReal:Double(key:String)
-		Local r:TJSONInteger = TJSONInteger(bmx_json_object_get(jsonPtr, key))
-		If r Then
-			Return r.Value()
-		End If
-	End Method
-
-End Type
-
-Type TJSONObjectEnum
-
-	Field obj:TJSONObject
-	Field objectIter:Byte Ptr
-
-	Method HasNext:Int()
-		If objectIter Then
-			Return True
-		End If
-	End Method
-
-	Method NextObject:Object()
-		Local value:Object = bmx_json_object_iter_value(objectIter)
-		objectIter = json_object_iter_next(obj.jsonPtr, objectIter)
-		Return value
-	End Method
-
-End Type
-
-Rem
-bbdoc: A JSON String.
-End Rem
-Type TJSONString Extends TJSON
-
-	Rem
-	bbdoc: Creates a new TJSONString.
-	End Rem
-	Method Create:TJSONString(Text:String)
-		jsonPtr = bmx_json_string_nocheck(Text)
-		Return Self
-	End Method
-	
-	Rem
-	bbdoc: Returns the associated value of the string.
-	End Rem
-	Method Value:String()
-		Return bmx_json_string_value(jsonPtr)
-	End Method
-	
-End Type
-
-Rem
-bbdoc: Base type for JSON number types.
-End Rem
-Type TJSONNumber Extends TJSON
-
-End Type
-
-Rem
-bbdoc: a JSON integer.
-End Rem
-Type TJSONInteger Extends TJSONNumber
-
-	Rem
-	bbdoc: Creates an instance of #TJSONInteger with @v.
-	End Rem
-	Method Create:TJSONInteger(v:Long)
-		jsonPtr = bmx_json_integer(v)
-		Return Self
-	End Method
-
-	Rem
-	bbdoc: Creates an instance of #TJSONInteger with @v.
-	End Rem
-	Method Create:TJSONInteger(v:Byte)
-		jsonPtr = bmx_json_integer(v)
-		Return Self
-	End Method
-
-	Rem
-	bbdoc: Creates an instance of #TJSONInteger with @v.
-	End Rem
-	Method Create:TJSONInteger(v:Short)
-		jsonPtr = bmx_json_integer(v)
-		Return Self
-	End Method
-
-	Rem
-	bbdoc: Creates an instance of #TJSONInteger with @v.
-	End Rem
-	Method Create:TJSONInteger(v:Int)
-		jsonPtr = bmx_json_integer(v)
-		Return Self
-	End Method
-
-	Rem
-	bbdoc: Creates an instance of #TJSONInteger with @v.
-	End Rem
-	Method Create:TJSONInteger(v:UInt)
-		jsonPtr = bmx_json_integer(v)
-		Return Self
-	End Method
-
-	Rem
-	bbdoc: Creates an instance of #TJSONInteger with @v.
-	End Rem
-	Method Create:TJSONInteger(v:ULong)
-		jsonPtr = bmx_json_integer(Long(v))
-		Return Self
-	End Method
-
-	Rem
-	bbdoc: Creates an instance of #TJSONInteger with @v.
-	End Rem
-	Method Create:TJSONInteger(v:Size_T)
-		jsonPtr = bmx_json_integer(Long(v))
-		Return Self
-	End Method
-
-	Rem
-	bbdoc: Returns the associated value of the integer.
-	End Rem
-	Method Value:Long()
-		Local v:Long
-		bmx_json_integer_value(jsonPtr, Varptr v)
-		Return v
-	End Method
-	
-	Rem
-	bbdoc: Sets the associated value of integer to @v.
-	about: Returns 0 on success, -1 otherwise.
-	End Rem
-	Method Set:Int(v:Long)
-		Return bmx_json_integer_set(jsonPtr, v)
-	End Method
-
-	Rem
-	bbdoc: Sets the associated value of integer to @v.
-	about: Returns 0 on success, -1 otherwise.
-	End Rem
-	Method Set:Int(v:Byte)
-		Return bmx_json_integer_set(jsonPtr, v)
-	End Method
-
-	Rem
-	bbdoc: Sets the associated value of integer to @v.
-	about: Returns 0 on success, -1 otherwise.
-	End Rem
-	Method Set:Int(v:Short)
-		Return bmx_json_integer_set(jsonPtr, v)
-	End Method
-
-	Rem
-	bbdoc: Sets the associated value of integer to @v.
-	about: Returns 0 on success, -1 otherwise.
-	End Rem
-	Method Set:Int(v:Int)
-		Return bmx_json_integer_set(jsonPtr, v)
-	End Method
-
-	Rem
-	bbdoc: Sets the associated value of integer to @v.
-	about: Returns 0 on success, -1 otherwise.
-	End Rem
-	Method Set:Int(v:UInt)
-		Return bmx_json_integer_set(jsonPtr, v)
-	End Method
-
-	Rem
-	bbdoc: Sets the associated value of integer to @v.
-	about: Returns 0 on success, -1 otherwise.
-	End Rem
-	Method Set:Int(v:ULong)
-		Return bmx_json_integer_set(jsonPtr, Long(v))
-	End Method
-
-	Rem
-	bbdoc: Sets the associated value of integer to @v.
-	about: Returns 0 on success, -1 otherwise.
-	End Rem
-	Method Set:Int(v:Size_T)
-		Return bmx_json_integer_set(jsonPtr, Long(v))
-	End Method
-
-End Type
-
-Rem
-bbdoc: A JSON real number.
-End Rem
-Type TJSONReal Extends TJSONNumber
-
-	Rem
-	bbdoc: Creates an instance of #TJSONReal with @v.
-	End Rem
-	Method Create:TJSONReal(v:Double)
-		jsonPtr = json_real(v)
-		Return Self
-	End Method
-
-	Rem
-	bbdoc: Creates an instance of #TJSONReal with @v.
-	End Rem
-	Method Create:TJSONReal(v:Float)
-		jsonPtr = json_real(v)
-		Return Self
-	End Method
-
-	Rem
-	bbdoc: Returns the associated value of the real.
-	End Rem
-	Method Value:Double()
-		Return json_real_value(jsonPtr)
-	End Method
-
-	Rem
-	bbdoc: Sets the associated value of real to @v.
-	about: Returns 0 on success, -1 otherwise.
-	End Rem
-	Method Set:Int(v:Double)
-		Return json_real_set(jsonPtr, v)
-	End Method
-
-	Rem
-	bbdoc: Sets the associated value of real to @v.
-	about: Returns 0 on success, -1 otherwise.
-	End Rem
-	Method Set:Int(v:Float)
-		Return json_real_set(jsonPtr, v)
-	End Method
-
-End Type
-
-Rem
-bbdoc: A JSON boolean.
-End Rem
-Type TJSONBool Extends TJSON
-
-	Field isTrue:Int
-
-	Rem
-	bbdoc: Creates an instance of #TJSONBool with @v.
-	End Rem
-	Method Create:TJSONBool(v:Int)
-		jsonPtr = bmx_json_bool(v)
-		isTrue = v
-		Return Self
-	End Method
-
-End Type
-
-Rem
-bbdoc: A JSON Null.
-End Rem
-Type TJSONNull Extends TJSON
-
-End Type
-
-Rem
-bbdoc: JSON error information.
-End Rem
-Type TJSONError
-	Rem
-	bbdoc: The error message, or an empty string if a message is not available.
-	End Rem
-	Field Text:String
-	Rem
-	bbdoc: Source of the error.
-	about: This can be (a part of) the file name or a special identifier in angle brackers (e.g. &lt;string&gt;).
-	End Rem
-	Field source:String
-	Rem
-	bbdoc: The line number on which the error occurred.
-	End Rem
-	Field line:Int
-	Rem
-	bbdoc: The column on which the error occurred.
-	about:  Note that this is the character column, not the byte column, i.e. a multibyte UTF-8 character counts as one column.
-	End Rem
-	Field column:Int
-	Rem
-	bbdoc: The position in bytes from the start of the input.
-	about: This is useful for debugging Unicode encoding problems.
-	End Rem
-	Field position:Int
-	Rem
-	bbdoc: The numeric code for the error.
-	End Rem
-	Field errorCode:Int
-	
-	Field _js:TJSON
-	
-	Function _createError:TJSONError(Text:String, source:String, line:Int, column:Int, position:Int, errorCode:Int) { nomangle }
-		Local this:TJSONError = New TJSONError
-		this.Text = Text
-		this.source = source
-		this.line = line
-		this.column = column
-		this.position = position
-		this.errorCode = errorCode
-		Return this
-	End Function
-
-	Function _createNoError:TJSONError(_js:TJSON) { nomangle }
-		Local this:TJSONError = New TJSONError
-		this._js = _js
-		Return this
-	End Function
-
-End Type

+ 0 - 43
json.mod/source.bmx

@@ -1,43 +0,0 @@
-' Copyright (c) 2014-2019 Bruce A Henderson
-' 
-' Permission is hereby granted, free of charge, to any person obtaining a copy
-' of this software and associated documentation files (the "Software"), to deal
-' in the Software without restriction, including without limitation the rights
-' to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-' copies of the Software, and to permit persons to whom the Software is
-' furnished to do so, subject to the following conditions:
-' 
-' The above copyright notice and this permission notice shall be included in
-' all copies or substantial portions of the Software.
-' 
-' THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-' IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-' FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-' AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-' LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-' OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-' THE SOFTWARE.
-' 
-SuperStrict
-
-Import BRL.Blitz
-
-?linux
-Import "../../pub.mod/jansson.mod/include/linux/*.h"
-?macos
-Import "../../pub.mod/jansson.mod/include/macos/*.h"
-?win32
-Import "../../pub.mod/jansson.mod/include/win32/*.h"
-?
-
-?android
-Import "../../pub.mod/jansson.mod/config/android/*.h"
-?Not android
-Import "../../pub.mod/jansson.mod/config/all/*.h"
-?
-
-Import "../../pub.mod/jansson.mod/jansson/src/*.h"
-
-
-Import "glue.c"
-

+ 0 - 83
xml.mod/common.bmx

@@ -1,83 +0,0 @@
-' Copyright 2019 Bruce A Henderson
-'
-' 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.
-'
-SuperStrict
-
-Import Pub.mxml
-Import brl.stream
-Import brl.linkedlist
-Import brl.stringbuilder
-
-Import "glue.c"
-
-Extern
-
-	Function bmx_mxmlLoadStream:Byte Ptr(stream:TStream)
-	Function bmx_mxmlNewXML:Byte Ptr(version:String)
-	Function bmx_mxmlNewElement:Byte Ptr(parent:Byte Ptr, name:String)
-	Function bmx_mxmlDelete(handle:Byte Ptr)
-	Function bmx_mxmlLoadString:Byte Ptr(txt:String)
-
-	Function bmx_mxmlSetRootElement:Byte Ptr(handle:Byte Ptr, root:Byte Ptr)
-	Function bmx_mxmlAdd(parent:Byte Ptr, _where:Int, child:Byte Ptr, node:Byte Ptr)
-	Function bmx_mxmlGetElement:String(handle:Byte Ptr)
-	Function bmx_mxmlSetContent(handle:Byte Ptr, content:String)
-	Function bmx_mxmlElementSetAttr(handle:Byte Ptr, name:String, value:String)
-	Function bmx_mxmlElementGetAttr:String(handle:Byte Ptr, name:String)
-	Function bmx_mxmlElementDeleteAttr(handle:Byte Ptr, name:String)
-	Function bmx_mxmlElementHasAttr:Int(handle:Byte Ptr, name:String)
-	Function bmx_mxmlSetElement(handle:Byte Ptr, name:String)
-	Function bmx_mxmlElementGetAttrCount:Int(handle:Byte Ptr)
-	Function bmx_mxmlElementGetAttrByIndex:String(handle:Byte Ptr, index:Int, name:String Var)
-	Function bmx_mxmlGetRootElement:Byte Ptr(handle:Byte Ptr)
-	Function bmx_mxmlWalkNext:Byte Ptr(node:Byte Ptr, top:Byte Ptr, descend:Int)
-	Function bmx_mxmlGetType:Int(handle:Byte Ptr)
-	Function bmx_mxmlAddContent(handle:Byte Ptr, content:String)
-	Function bmx_mxmlGetParent:Byte Ptr(handle:Byte Ptr)
-	Function bmx_mxmlGetFirstChild:Byte Ptr(handle:Byte Ptr)
-	Function bmx_mxmlGetLastChild:Byte Ptr(handle:Byte Ptr)
-	Function bmx_mxmlGetNextSibling:Byte Ptr(handle:Byte Ptr)
-	Function bmx_mxmlGetPrevSibling:Byte Ptr(handle:Byte Ptr)
-	Function bmx_mxmlFindElement:Byte Ptr(handle:Byte Ptr, element:String, attr:String, value:String)
-
-	Function bmx_mxmlSaveStdout:Int(handle:Byte Ptr, format:Int)
-	Function bmx_mxmlSaveString:String(handle:Byte Ptr, format:Int)
-	Function bmx_mxmlSaveStream:Int(handle:Byte Ptr, stream:TStream, format:Int)
-	
-	Function bmx_mxmlSetWrapMargin(column:Int)
-	Function bmx_mxmlGetContent:String(handle:Byte Ptr)
-End Extern
-
-Rem
-bbdoc: Descend when finding/walking.
-End Rem
-Const MXML_DESCEND:Int = 1
-Rem
-bbdoc: Don't descend when finding/walking.
-End Rem
-Const MXML_NO_DESCEND:Int = 0
-Rem
-bbdoc: Descend for first find.
-End Rem
-Const MXML_DESCEND_FIRST:Int = -1
-
-Const MXML_IGNORE:Int = -1
-Const MXML_ELEMENT:Int = 0
-Const MXML_INTEGER:Int = 1
-Const MXML_OPAQUE:Int = 2
-Const MXML_REAL:Int = 3
-Const MXML_TEXT:Int = 4
-Const MXML_CUSTOM:Int = 5
-
-Const BOM_UTF8:String = Chr(239) + Chr(187) + Chr(191)

+ 0 - 7
xml.mod/doc/attributes.xml

@@ -1,7 +0,0 @@
-<?xml version="1.0"?>
-<notes>
-<note day="12" month="11" year="99"
-to="Tove" from="Jani" heading="Reminder"
-body="Don't forget me this weekend!">
-</note>
-</notes>

+ 0 - 14
xml.mod/doc/sample.xml

@@ -1,14 +0,0 @@
-<?xml version="1.0"?>
-<story>
-  <storyinfo>
-    <author>John Fleck</author>
-    <datewritten>June 2, 2002</datewritten>
-    <keyword>example keyword</keyword>
-  </storyinfo>
-  <body>
-    <headline>This is the headline</headline>
-    <para>This is the body text.</para>
-  </body>
-  <empty1/>
-  <empty2></empty2>
-</story>

+ 0 - 33
xml.mod/doc/txmldoc_parsefile.bmx

@@ -1,33 +0,0 @@
-SuperStrict
-
-Framework brl.xml
-Import brl.standardio
-Import brl.ramstream
-
-Incbin "sample.xml"
-
-Local doc:TxmlDoc = TxmlDoc.parseFile("sample.xml")
-
-If doc Then
-	Print "~nFilename :"
-	doc.savefile("-")
-	doc.Free()
-End If
-
-Local stream:TStream = ReadStream("sample.xml")
-doc = TxmlDoc.parseFile(stream)
-
-If doc Then
-	Print "~nStream :"
-	doc.savefile("-")
-	doc.Free()
-End If
-
-stream = ReadStream("incbin::sample.xml")
-doc = TxmlDoc.parseFile(stream)
-
-If doc Then
-	Print "~nIncbin Stream :"
-	doc.savefile("-")
-	doc.Free()
-End If

+ 0 - 13
xml.mod/doc/txmldoc_readdoc.bmx

@@ -1,13 +0,0 @@
-SuperStrict
-
-Framework brl.xml
-Import brl.standardio
-
-Local xml:String = LoadText("sample.xml")
-
-Local doc:TxmlDoc = TxmlDoc.readDoc(xml)
-
-If doc Then
-	doc.savefile("-", , True)
-	doc.Free()
-End If

+ 0 - 50
xml.mod/doc/txmldoc_savefile.bmx

@@ -1,50 +0,0 @@
-SuperStrict
-
-Framework brl.xml
-Import BRL.StandardIO
-
-' Create a new document
-Local doc:TxmlDoc = TxmlDoc.newDoc("1.0")
-
-If doc Then
-
-	' create a test stream
-	Local stream:TTestStream = TTestStream.Create()
-
-	' create a new node, initially not attached to the document
-	Local root:TxmlNode = TxmlNode.newNode("root")
-	
-	' set the node as the document root node
-	doc.setRootElement(root)
- 
-	root.addChild("things", "some stuff")
-
-	' output the document to a file
-	doc.saveFile("testfile.xml")
-	
-	' output the document to a stream
-	doc.saveFile(stream)
-	
-	' output the document to console
-	doc.saveFile("-")
-	
-	doc.Free()
-End If
-
-
-Type TTestStream Extends TStream
-
-	Function Create:TTestStream( )
-		Return New TTestStream
-	End Function
-
-	Method Write:Long( buf:Byte Ptr, count:Long )
-		
-		Print "outputing..."
-		Print String.FromBytes( buf, Int(count) )
-		
-		Return count
-	End Method
-
-	
-End Type

+ 0 - 15
xml.mod/doc/txmlnode_addchild.bmx

@@ -1,15 +0,0 @@
-SuperStrict
-
-Framework brl.xml
-
-Local doc:TxmlDoc = TxmlDoc.parseFile("attributes.xml")
-
-If doc Then
-
-	Local node:TxmlNode = TxmlNode(doc.getRootElement().getFirstChild())
-
-	node.addChild("ID", "C0122200")
-
-	doc.savefile("-")
-
-End If

+ 0 - 19
xml.mod/doc/txmlnode_addcontent.bmx

@@ -1,19 +0,0 @@
-SuperStrict
-
-Framework brl.xml
-Import brl.standardio
-
-Local doc:TxmlDoc = TxmlDoc.parseFile("attributes.xml")
-
-If doc Then
-
-	Local node:TxmlNode = TxmlNode(doc.getRootElement().getFirstChild())
-
-	Local desc:TxmlNode = node.addChild("description")
-
-	desc.addContent("Some of the songs on this CD are awesome.~n")
-	desc.addContent("Tracks 5 & 6 put this CD up there...")
-
-	doc.savefile("-")
-
-End If

+ 0 - 22
xml.mod/doc/txmlnode_addnextsibling.bmx

@@ -1,22 +0,0 @@
-SuperStrict
-
-Framework brl.xml
-
-Local doc:TxmlDoc = TxmlDoc.parseFile("attributes.xml")
-
-If doc Then
-
-	Local node:TxmlNode = TxmlNode(doc.getRootElement().getFirstChild())
-
-	' a new node for the document
-	Local newNode:TxmlNode = TxmlNode.newnode("cd")
-	newNode.addAttribute("title", "Together Alone")
-	newNode.addAttribute("artist", "Crowded House")
-	newNode.addChild("country", "NZ")
-	
-	' add new node to document as sibling of node.
-	node.addNextSibling(newNode)
-
-	' output the document to stdout
-	doc.saveFile("-")
-End If

+ 0 - 22
xml.mod/doc/txmlnode_addprevioussibling.bmx

@@ -1,22 +0,0 @@
-SuperStrict
-
-Framework brl.xml
-
-Local doc:TxmlDoc = TxmlDoc.parseFile("attributes.xml")
-
-If doc Then
-
-	Local node:TxmlNode = TxmlNode(doc.getRootElement().getFirstChild())
-	
-	' a new node for the document
-	Local newNode:TxmlNode = TxmlNode.newnode("cd")
-	newNode.addAttribute("title", "This is the Sea")
-	newNode.addAttribute("artist", "Waterboys")
-	newNode.addChild("country", "UK")
-	
-	' add new node to document as previous sibling of node.
-	node.addPreviousSibling(newNode)
-
-	' output the document to stdout
-	doc.saveFile("-")
-End If

+ 0 - 20
xml.mod/doc/txmlnode_findelement.bmx

@@ -1,20 +0,0 @@
-SuperStrict
-
-Framework brl.xml
-Import brl.standardio
-
-Local docname:String = "sample.xml"
-Local doc:TxmlDoc
-
-doc = TxmlDoc.parseFile(docname)
-If doc Then
-
-	Local root:TxmlNode = doc.getRootElement()
-	
-	Local node:TxmlNode = root.findElement("author")
-	
-	If node Then
-		Print node.ToString()
-	End If
-
-End If

+ 0 - 20
xml.mod/doc/txmlnode_getattributelist.bmx

@@ -1,20 +0,0 @@
-SuperStrict
-
-Framework brl.xml
-Import brl.standardio
-
-Local docname:String = "attributes.xml"
-Local doc:TxmlDoc = TxmlDoc.parseFile(docname)
-
-If doc Then
-	Local root:TxmlNode = doc.getRootElement()
-	For Local node:TxmlNode = EachIn root.getChildren()
-		Print node.getName() + " : "
-		
-		For Local attribute:TxmlAttribute = EachIn node.getAttributeList()
-			Print "    " + attribute.getName() + " : " + attribute.getValue()
-		Next
-		
-		Print ""
-	Next
-End If

+ 0 - 15
xml.mod/doc/txmlnode_getfirstchild.bmx

@@ -1,15 +0,0 @@
-SuperStrict
-
-Framework brl.xml
-Import brl.standardio
-
-Local docname:String = "sample.xml"
-Local doc:TxmlDoc
-
-doc = TxmlDoc.parseFile(docname)
-If doc Then
-	Local root:TxmlNode = doc.getRootElement()
-	
-	Print "First child is - " + root.getFirstChild().getName()
-
-End If

+ 0 - 15
xml.mod/doc/txmlnode_getlastchild.bmx

@@ -1,15 +0,0 @@
-SuperStrict
-
-Framework brl.xml
-Import brl.standardio
-
-Local docname:String = "sample.xml"
-Local doc:TxmlDoc
-
-doc = TxmlDoc.parseFile(docname)
-If doc Then
-	Local root:TxmlNode = doc.getRootElement()
-	
-	Print "Last child is - " + root.getLastChild().getName()
-
-End If

+ 0 - 13
xml.mod/doc/txmlnode_newdoc.bmx

@@ -1,13 +0,0 @@
-SuperStrict
-
-Framework brl.xml
-
-' Create a new document
-Local doc:TxmlDoc = TxmlDoc.newDoc("1.0")
-
-If doc Then
-
-	' output the document to stdout
-	doc.saveFile("-")
-
-End If

+ 0 - 17
xml.mod/doc/txmlnode_newnode.bmx

@@ -1,17 +0,0 @@
-Framework brl.xml
-Import brl.standardio
-
-Local doc:TxmlDoc = TxmlDoc.newDoc("1.0")
-
-If doc Then
-	
-	' create a new node, initially not attached to the document
-	Local root:TxmlNode = TxmlNode.newNode("root")
-	
-	' set the node as the document root node
-	doc.setRootElement(root)
-	
-	' output the document to stdout
-	doc.saveFile("-")
-	
-End If

+ 0 - 17
xml.mod/doc/txmlnode_nextsibling.bmx

@@ -1,17 +0,0 @@
-SuperStrict
-
-Framework brl.xml
-Import brl.standardio
-
-Local docname:String = "sample.xml"
-Local doc:TxmlDoc
-
-doc = TxmlDoc.parseFile(docname)
-If doc Then
-	Local root:TxmlNode = doc.getRootElement()
-	
-	Local node:TxmlNode = TxmlNode(root.getFirstChild())
-	
-	Print "Next sibling is - " + node.nextSibling().getName()
-
-End If

+ 0 - 17
xml.mod/doc/txmlnode_previoussibling.bmx

@@ -1,17 +0,0 @@
-SuperStrict
-
-Framework brl.xml
-Import brl.standardio
-
-Local docname:String = "sample.xml"
-Local doc:TxmlDoc
-
-doc = TxmlDoc.parseFile(docname)
-If doc Then
-	Local root:TxmlNode = doc.getRootElement()
-	
-	Local node:TxmlNode = TxmlNode(root.getLastChild())
-	
-	Print "Previous sibling is - " + node.previousSibling().getName()
-
-End If

+ 0 - 28
xml.mod/doc/txmlnode_setattribute.bmx

@@ -1,28 +0,0 @@
-SuperStrict
-
-Framework brl.xml
-Import BRL.StandardIO
-
-Local doc:TxmlDoc = TxmlDoc.newDoc("1.0")
-
-If doc Then
-	
-	Local root:TxmlNode = TxmlNode.newNode("root")
-	doc.setRootElement(root)
-	
-	' create a new empty node
-	Local node:TxmlNode = root.addChild("node")
-
-	Print node.toString()
-
-	' set an attribute
-	node.setAttribute("attr1", "a value")
-	
-	Print node.toString()
-	
-	' change the attribute value
-	node.setAttribute("attr1", "a new value")
-	
-	Print node.toString()
-	
-End If

+ 0 - 28
xml.mod/doc/txmlnode_setcontent.bmx

@@ -1,28 +0,0 @@
-SuperStrict
-
-Framework brl.xml
-Import BRL.StandardIO
-
-Local doc:TxmlDoc = TxmlDoc.newDoc("1.0")
-
-If doc Then
-	
-	Local root:TxmlNode = TxmlNode.newNode("root")
-	doc.setRootElement(root)
-	
-	' create a new empty node
-	Local node:TxmlNode = root.addChild("node")
-
-	Print node.toString()
-
-	' set the node content
-	node.setContent("Some text content for the node")
-	
-	Print node.toString()
-	
-	' change the node content
-	node.setContent("Modified content!")
-	
-	Print node.toString()
-
-End If

+ 0 - 23
xml.mod/doc/txmlnode_setname.bmx

@@ -1,23 +0,0 @@
-SuperStrict
-
-Framework brl.xml
-Import BRL.StandardIO
-
-Local doc:TxmlDoc = TxmlDoc.newDoc("1.0")
-
-If doc Then
-	
-	Local root:TxmlNode = TxmlNode.newNode("root")
-	doc.setRootElement(root)
-	
-	' create a new empty node
-	Local node:TxmlNode = root.addChild("node")
-
-	Print node.toString()
-
-	' change the node name
-	node.setName("branch")
-	
-	Print node.toString()
-	
-End If

+ 0 - 29
xml.mod/doc/txmlnode_unsetattribute.bmx

@@ -1,29 +0,0 @@
-SuperStrict
-
-Framework brl.xml
-Import BRL.StandardIO
-
-Local doc:TxmlDoc = TxmlDoc.newDoc("1.0")
-
-If doc Then
-	
-	Local root:TxmlNode = TxmlNode.newNode("root")
-	doc.setRootElement(root)
-	
-	' create a new empty node
-	Local node:TxmlNode = root.addChild("node")
-
-	Print node.toString()
-
-	' add some attributes
-	node.setAttribute("attr1", "Attribute value")
-	node.setAttribute("attr2", "Another value")
-	
-	Print node.toString()
-	
-	' remove an attribute
-	node.unsetAttribute("attr1")
-	
-	Print node.toString()
-	
-End If

+ 0 - 407
xml.mod/glue.c

@@ -1,407 +0,0 @@
-/*
-Copyright 2019 Bruce A Henderson
-
-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 "pub.mod/mxml.mod/mxml/mxml.h"
-#include "brl.mod/blitz.mod/blitz.h"
-
-extern int brl_xml__xmlstream_read(void *, void *, unsigned int);
-extern int brl_xml__xmlstream_write(void *, const void *, unsigned int);
-
-mxml_node_t * bmx_mxmlGetFirstChild(mxml_node_t * node);
-
-static int bmx_mxml_stream_read(void * ctxt, void *buf, unsigned int length) {
-	return brl_xml__xmlstream_read(ctxt, buf, length);
-}
-
-static int bmx_mxml_stream_write(void * ctxt, const void *buf, unsigned int length) {
-	return brl_xml__xmlstream_write(ctxt, buf, length);
-}
-
-struct whitespace_t {
-	char buf[4096];
-	int spaces;
-};
-
-static int bmx_mxml_getDepth(mxml_node_t * node) {
-	int count = 0;
-	while (node = mxmlGetParent(node)) {
-		count++;
-	}
-	return count;
-}
-
-static const char * bmx_mxml_whitspace_cb(mxml_node_t * node, int where, void * ctxt) {
-	struct whitespace_t * ws = (struct whitespace_t*)ctxt;
-	
-	if (ws) {
-		int depth = bmx_mxml_getDepth(node);
-
-		if (depth > 0) {
-		
-			ws->buf[0] = '\n';
-			depth--;
-			
-			if (depth > 2047) {
-				depth = 2047;
-			}
-			
-			if (ws->spaces < depth) {
-				char * q = 1 + ws->buf + ws->spaces * 2;
-				for (int i = ws->spaces; i < depth; i++) {
-					*q++ = ' ';
-					*q++ = ' ';
-				}
-			}
-			
-			ws->buf[1 + depth * 2] = 0;
-			ws->spaces = depth;
-
-			switch(where) {
-				case MXML_WS_BEFORE_OPEN:
-					return ws->buf;
-				case MXML_WS_BEFORE_CLOSE:
-					if (bmx_mxmlGetFirstChild(node) != NULL) {
-						return ws->buf;
-					}
-				break;
-				
-			}
-		}
-	}
-	
-	return NULL;
-}
-
-mxml_node_t * bmx_mxmlNewXML(BBString * version) {
-	char * v = bbStringToUTF8String(version);
-	mxml_node_t * node = mxmlNewXML(v);
-	bbMemFree(v);
-	return node;
-}
-
-mxml_node_t * bmx_mxmlNewElement(mxml_node_t * parent, BBString * name) {
-	char * n = bbStringToUTF8String(name);
-	if (!parent) {
-		parent = MXML_NO_PARENT;
-	}
-	mxml_node_t * node = mxmlNewElement(parent, n);
-	bbMemFree(n);
-	return node;
-}
-
-void bmx_mxmlDelete(mxml_node_t * node) {
-	mxmlDelete(node);
-}
-
-mxml_node_t * bmx_mxmlGetRootElement(mxml_node_t * node) {
-	mxml_node_t * n = mxmlWalkNext(node, node, MXML_DESCEND);
-	while (n && mxmlGetType(n) != MXML_ELEMENT) {
-		n = mxmlWalkNext(n, node, MXML_DESCEND);
-	}
-	return n;
-}
-
-mxml_node_t * bmx_mxmlSetRootElement(mxml_node_t * parent, mxml_node_t * root) {
-	mxml_node_t * r = bmx_mxmlGetRootElement(parent);
-	if (r) {
-		mxmlRemove(r);
-	}
-	mxmlAdd(parent, MXML_ADD_AFTER, MXML_ADD_TO_PARENT, root);
-	return r;
-}
-
-void bmx_mxmlAdd(mxml_node_t * parent, int where, mxml_node_t * child, mxml_node_t * node) {
-	if (!child) {
-		child = MXML_ADD_TO_PARENT;
-	}
-	mxmlAdd(parent, where, child, node);
-}
-
-BBString * bmx_mxmlGetElement(mxml_node_t * node) {
-	char * n = mxmlGetElement(node);
-	if (n) {
-		return bbStringFromUTF8String(n);
-	}
-	
-	return &bbEmptyString;
-}
-
-int bmx_mxmlSaveStdout(mxml_node_t * node, int format) {
-	if (!format) {
-		return mxmlSaveFile(node, stdout, MXML_NO_CALLBACK, NULL);
-	} else {
-		struct whitespace_t ws = {};
-		return mxmlSaveFile(node, stdout, bmx_mxml_whitspace_cb, &ws);
-	}
-}
-
-void bmx_mxmlSetContent(mxml_node_t * node, BBString * content) {
-	mxml_node_t * child = mxmlGetFirstChild(node);
-	while (child != NULL) {
-		mxml_node_t * txt = NULL;
-		if (mxmlGetType(child) == MXML_TEXT) {
-			txt = child;
-		}
-		child = mxmlGetNextSibling(child);
-		if (txt) {
-			mxmlDelete(txt);
-		}
-	}
-	char * c = bbStringToUTF8String(content);
-	mxmlNewText(node, 0, c);
-	bbMemFree(c);
-}
-
-BBString * bmx_mxmlSaveString(mxml_node_t * node, int format) {
-	mxml_save_cb_t cb = MXML_NO_CALLBACK;
-	if (format) {
-		cb = bmx_mxml_whitspace_cb;
-	}
-	struct whitespace_t ws = {};
-	char tmp[1];
-	int size = mxmlSaveString(node, tmp, 1, cb, &ws);
-	char * buf = bbMemAlloc(size);
-	mxmlSaveString(node, buf, size, cb, &ws);
-	buf[size-1] = 0;
-	BBString * s = bbStringFromUTF8String(buf);
-	bbMemFree(buf);
-	return s;
-}
-
-void bmx_mxmlElementSetAttr(mxml_node_t * node, BBString * name, BBString * value) {
-	char * n = bbStringToUTF8String(name);
-	char * v = bbStringToUTF8String(value);
-	mxmlElementSetAttr(node, n, v);
-	bbMemFree(v);
-	bbMemFree(n);
-}
-
-BBString * bmx_mxmlElementGetAttr(mxml_node_t * node, BBString * name) {
-	char * n = bbStringToUTF8String(name);
-	char * v = mxmlElementGetAttr(node, n);
-	bbMemFree(n);
-	if (v) {
-		return bbStringFromUTF8String(v);
-	}
-	return &bbEmptyString;
-}
-
-void bmx_mxmlElementDeleteAttr(mxml_node_t * node, BBString * name) {
-	char * n = bbStringToUTF8String(name);
-	mxmlElementDeleteAttr(node, n);
-	bbMemFree(n);
-}
-
-int bmx_mxmlElementHasAttr(mxml_node_t * node, BBString * name) {
-	char * n = bbStringToUTF8String(name);
-	char * v = mxmlElementGetAttr(node, n);
-	bbMemFree(n);
-	return v != NULL;
-}
-
-void bmx_mxmlSetElement(mxml_node_t * node, BBString * name) {
-	char * n = bbStringToUTF8String(name);
-	mxmlSetElement(node, n);
-	bbMemFree(n);
-}
-
-int bmx_mxmlElementGetAttrCount(mxml_node_t * node) {
-	return mxmlElementGetAttrCount(node);
-}
-
-BBString * bmx_mxmlElementGetAttrByIndex(mxml_node_t * node, int index, BBString ** name) {
-	char * n;
-	char * v = mxmlElementGetAttrByIndex(node, index, &n);
-	if (v) {
-		*name = bbStringFromUTF8String(n);
-		return bbStringFromUTF8String(v);
-	} else {
-		*name = &bbEmptyString;
-		return &bbEmptyString;
-	}
-}
-
-mxml_node_t * bmx_mxmlLoadStream(BBObject * stream) {
-	return mxmlLoadStream(NULL, bmx_mxml_stream_read, stream, MXML_OPAQUE_CALLBACK);
-}
-
-mxml_node_t * bmx_mxmlWalkNext(mxml_node_t * node, mxml_node_t * top, int descend) {
-	return mxmlWalkNext(node, top, descend);
-}
-
-int bmx_mxmlGetType(mxml_node_t * node) {
-	return mxmlGetType(node);
-}
-
-void bmx_mxmlAddContent(mxml_node_t * node, BBString * content) {
-	char * c = bbStringToUTF8String(content);
-	mxmlNewText(node, 0, c);
-	bbMemFree(c);
-}
-
-mxml_node_t * bmx_mxmlGetParent(mxml_node_t * node) {
-	return mxmlGetParent(node);
-}
-
-mxml_node_t * bmx_mxmlGetFirstChild(mxml_node_t * node) {
-	mxml_node_t * n = mxmlGetFirstChild(node);
-	while (n && mxmlGetType(n) != MXML_ELEMENT) {
-		n = mxmlGetNextSibling(n);
-	}
-	return n;
-}
-
-mxml_node_t * bmx_mxmlGetLastChild(mxml_node_t * node) {
-	mxml_node_t * n = mxmlGetLastChild(node);
-	while (n && mxmlGetType(n) != MXML_ELEMENT) {
-		n = mxmlGetPrevSibling(n);
-	}
-	return n;
-}
-
-mxml_node_t * bmx_mxmlGetNextSibling(mxml_node_t * node) {
-	mxml_node_t * n = mxmlGetNextSibling(node);
-	while (n && mxmlGetType(n) != MXML_ELEMENT) {
-		n = mxmlGetNextSibling(n);
-	}
-	return n;
-}
-
-mxml_node_t * bmx_mxmlGetPrevSibling(mxml_node_t * node) {
-	mxml_node_t * n = mxmlGetPrevSibling(node);
-	while (n && mxmlGetType(n) != MXML_ELEMENT) {
-		n = mxmlGetPrevSibling(n);
-	}
-	return n;
-}
-
-int bmx_mxmlSaveStream(mxml_node_t * node, BBObject * stream, int format) {
-	if (!format) {
-		return mxmlSaveStream(node, bmx_mxml_stream_write, stream, NULL, NULL);
-	} else {
-		struct whitespace_t ws = {};
-		return mxmlSaveStream(node, bmx_mxml_stream_write, stream, bmx_mxml_whitspace_cb, &ws);
-	}
-}
-
-struct _string_buf {
-	BBString * txt;
-	int txtOffset;
-	char padding[2];
-	int padCount;
-};
-
-// direct string to utf-8 stream
-static int bmx_mxml_string_read(void * ctxt, void *buf, unsigned int length) {
-	struct _string_buf * data = (struct _string_buf*)ctxt;
-
-	int txtLength = data->txt->length;
-	int count = 0;
-	
-	unsigned short *p = data->txt->buf + data->txtOffset;
-	char *q = buf;
-	char *a = data->padding;
-	
-	while (data->txtOffset < txtLength && count < length) {
-		
-		while (data->padCount > 0) {
-			*q++ = a[--data->padCount];
-			count++;
-		}
-		
-		unsigned int c=*p++;
-		if( c<0x80 ){
-			*q++ = c;
-			count++;
-		}else if( c<0x800 ){
-			*q++ = 0xc0|(c>>6);
-			if (++count < length) {
-				*q++ = 0x80|(c&0x3f);
-				count++;
-			} else {
-				data->padding[data->padCount++] = 0x80|(c&0x3f);
-				continue;
-			}
-		}else{
-			*q++ = 0xe0|(c>>12);
-			if (++count < length) {
-				*q++ = 0x80|((c>>6)&0x3f);
-				
-				if (++count < length) {
-					*q++ = 0x80|(c&0x3f);
-					count++;
-				} else {
-					data->padding[data->padCount++] = 0x80|(c&0x3f);
-					continue;
-				}
-			} else {
-				data->padding[1] = 0x80|((c>>6)&0x3f);
-				data->padding[0] = 0x80|(c&0x3f);
-				data->padCount = 2;
-				continue;
-			}
-		}
-		data->txtOffset++;
-	}
-	return count;
-}
-
-mxml_node_t * bmx_mxmlLoadString(BBString * txt) {
-	if (txt == &bbEmptyString) {
-		return NULL;
-	}
-	
-	struct _string_buf buf = {txt = txt};
-
-	return mxmlLoadStream(NULL, bmx_mxml_string_read, &buf, MXML_OPAQUE_CALLBACK);
-}
-
-void bmx_mxmlSetWrapMargin(int column) {
-	mxmlSetWrapMargin(column);
-}
-
-BBString * bmx_mxmlGetContent(mxml_node_t * node) {
-	const char * txt = mxmlGetOpaque(node);
-
-	if (!txt || strlen(txt) == 0) {
-		return &bbEmptyString;
-	}
-	return bbStringFromUTF8String(txt);
-}
-
-mxml_node_t * bmx_mxmlFindElement(mxml_node_t * node, BBString * element, BBString * attr, BBString * value) {
-	char * e = 0;
-	char * a = 0;
-	char * v = 0;
-	
-	if (element != &bbEmptyString) {
-		e = bbStringToUTF8String(element);
-	}
-	if (attr != &bbEmptyString) {
-		a = bbStringToUTF8String(attr);
-	}
-	if (value != &bbEmptyString) {
-		v = bbStringToUTF8String(value);
-	}
-	
-	mxml_node_t * result = mxmlFindElement(node, node, e, a, v, MXML_DESCEND);
-	
-	bbMemFree(v);
-	bbMemFree(a);
-	bbMemFree(e);
-	
-	return result;
-}

+ 0 - 447
xml.mod/xml.bmx

@@ -1,447 +0,0 @@
-' Copyright 2019 Bruce A Henderson
-'
-' 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.
-'
-SuperStrict
-
-Rem
-bbdoc: XML
-End Rem
-Module BRL.XML
-
-ModuleInfo "Version: 1.00"
-ModuleInfo "License: Apache 2.0"
-ModuleInfo "Copyright: 2019 Bruce A Henderson"
-
-ModuleInfo "History: 1.00"
-ModuleInfo "History: Initial Release."
-
-Import "common.bmx"
-
-' disable wrapping
-bmx_mxmlSetWrapMargin(0)
-
-Rem
-bbdoc: 
-End Rem
-Type TxmlBase Abstract
-
-	Field nodePtr:Byte Ptr
-
-	Rem
-	bbdoc: Returns the element name.
-	End Rem
-	Method getName:String()
-		Return bmx_mxmlGetElement(nodePtr)
-	End Method
-	
-	Rem
-	bbdoc: Returns a string representation of the element.
-	End Rem
-	Method ToString:String() Override
-		Return bmx_mxmlSaveString(nodePtr, False)
-	End Method
-
-	Rem
-	bbdoc: Returns a string representation of the element, optionally formatting the output.
-	End Rem
-	Method ToStringFormat:String(format:Int = False)
-		Return bmx_mxmlSaveString(nodePtr, format)
-	End Method
-
-End Type
-
-Rem
-bbdoc: An XML Node.
-End Rem
-Type TxmlNode Extends TxmlBase
-
-	Function _create:TxmlNode(nodePtr:Byte Ptr)
-		If nodePtr Then
-			Local this:TxmlNode = New TxmlNode
-			this.nodePtr = nodePtr
-			Return this
-		End If
-	End Function
-
-	Rem
-	bbdoc: Creates a new node element.
-	End Rem
-	Function newNode:TxmlNode(name:String)
-		Return _create(bmx_mxmlNewElement(Null, name))
-	End Function
-
-	Rem
-	bbdoc: Gets the parent.
-	returns: The parent to this object.
-	End Rem
-	Method GetParent:TxmlNode()
-		Return TxmlNode._create(bmx_mxmlGetParent(nodePtr))
-	End Method
-
-	Rem
-	bbdoc: Creates a new child element.
-	about: Added at the end of child nodes list.
-	End Rem
-	Method addChild:TxmlNode(name:String, content:String = Null)
-		Local n:TxmlNode = _create(bmx_mxmlNewElement(nodePtr, name))
-		If content And n Then
-			n.setContent(content)
-		End If
-		Return n
-	End Method
-
-	Rem
-	Rem
-	bbdoc: Adds a new node @node as the next sibling.
-	End Rem
-	Method addNextSibling(node:TxmlNode)
-		Local parent:TxmlBase = GetParent()
-		If parent Then
-			bmx_mxmlAdd(parent.nodePtr, MXML_ADD_AFTER, nodePtr, node.nodePtr)
-		End If
-	End Method
-
-	Rem
-	bbdoc: Adds a new node @node as the previous sibling.
-	End Rem
-	Method addPreviousSibling(node:TxmlNode)
-		Local parent:TxmlBase = GetParent()
-		If parent Then
-			bmx_mxmlAdd(parent.nodePtr, MXML_ADD_BEFORE, nodePtr, node.nodePtr)
-		End If
-	End Method
-
-	Rem
-	bbdoc: Appends the extra substring to the node content.
-	End Rem
-	Method addContent(content:String)
-		bmx_mxmlAddContent(nodePtr, content)
-	End Method
-	
-	Rem
-	bbdoc: Replaces the content of a node.
-	End Rem
-	Method setContent(content:String)
-		bmx_mxmlSetContent(nodePtr, content)
-	End Method
-	
-	Rem
-	bbdoc: Sets (or resets) the name of the node.
-	End Rem
-	Method setName(name:String)
-		bmx_mxmlSetElement(nodePtr, name)
-	End Method
-	
-	Rem
-	bbdoc: Creates a new attribute.
-	End Rem
-	Method addAttribute(name:String, value:String = "")
-		setAttribute(name, value)
-	End Method
-	
-	Rem
-	bbdoc: Sets (or resets) an attribute carried by the node.
-	End Rem
-	Method setAttribute(name:String, value:String = "")
-		bmx_mxmlElementSetAttr(nodePtr, name, value)
-	End Method
-	
-	Rem
-	bbdoc: Provides the value of the attribute with the specified qualified name.
-	End Rem
-	Method getAttribute:String(name:String)
-		Return bmx_mxmlElementGetAttr(nodePtr, name)
-	End Method
-	
-	Rem
-	bbdoc: Returns the list of node attributes.
-	returns: The list of attributes.
-	End Rem
-	Method getAttributeList:TList()
-		Local list:TList = New TList
-		Local count:Int = bmx_mxmlElementGetAttrCount(nodePtr)
-		If count Then
-			For Local i:Int = 0 Until count
-				Local name:String
-				Local value:String = bmx_mxmlElementGetAttrByIndex(nodePtr, i, name)
-				list.AddLast(New TxmlAttribute(name, value))
-			Next
-		End If
-		Return list
-	End Method
-	
-	Rem
-	bbdoc: Remove an attribute carried by the node.
-	End Rem
-	Method unsetAttribute(name:String)
-		bmx_mxmlElementDeleteAttr(nodePtr, name)
-	End Method
-	
-	Rem
-	bbdoc: Search an attribute associated to the node
-	returns: the attribute or Null if not found.
-	End Rem
-	Method hasAttribute:Int(name:String)
-		Return bmx_mxmlElementHasAttr(nodePtr, name)
-	End Method
-	
-	Rem
-	bbdoc: Returns a list of child nodes.
-	End Rem
-	Method getChildren:TList()
-		Local list:TList = New TList
-		
-		Local n:Byte Ptr = bmx_mxmlWalkNext(nodePtr, nodePtr, MXML_DESCEND)
-		
-		While n
-			If bmx_mxmlGetType(n) = MXML_ELEMENT Then
-				list.AddLast(TxmlNode._create(n))
-			End If
-			n = bmx_mxmlWalkNext(n, nodePtr, MXML_NO_DESCEND)
-		Wend
-		
-		Return list
-	End Method
-
-	Rem
-	bbdoc: Gets the first child.
-	returns: The first child or Null if none.
-	End Rem
-	Method getFirstChild:TxmlBase()
-		Return TxmlNode._create(bmx_mxmlGetFirstChild(nodePtr))
-	End Method
-
-	Rem
-	bbdoc: Gets the last child.
-	returns: The last child or Null if none.
-	End Rem
-	Method getLastChild:TxmlBase()
-		Return TxmlNode._create(bmx_mxmlGetLastChild(nodePtr))
-	End Method
-
-	Rem
-	bbdoc: Get the next sibling node
-	returns: The next node or Null if there are none.
-	End Rem
-	Method nextSibling:TxmlNode()
-		Return TxmlNode._create(bmx_mxmlGetNextSibling(nodePtr))
-	End Method
-	
-	Rem
-	bbdoc: Get the previous sibling node
-	returns: The previous node or Null if there are none.
-	End Rem
-	Method previousSibling:TxmlNode()
-		Return TxmlNode._create(bmx_mxmlGetPrevSibling(nodePtr))
-	End Method
-	
-	Rem
-	bbdoc: Reads the value of a node.
-	returns: The node content.
-	End Rem
-	Method getContent:String()
-		Local sb:TStringBuilder = New TStringBuilder()
-		
-		Local n:Byte Ptr = bmx_mxmlWalkNext(nodePtr, nodePtr, MXML_DESCEND)
-		While n
-			If bmx_mxmlGetType(n) = MXML_OPAQUE Then
-				sb.Append(bmx_mxmlGetContent(n))
-			End If
-			n = bmx_mxmlWalkNext(n, nodePtr, MXML_DESCEND)
-		Wend
-		
-		Return sb.ToString()
-	End Method
-	
-	Rem
-	bbdoc: Finds an element of the given @element name, attribute or attribute/value.
-	returns: A node or Null if no match was found.
-	End Rem
-	Method findElement:TxmlNode(element:String = "", attr:String = "", value:String = "")
-		Return TxmlNode._create(bmx_mxmlFindElement(nodePtr, element, attr, value))
-	End Method
-
-	Rem
-	bbdoc: Frees a node and all of its children.
-	End Rem
-	Method Free()
-		If nodePtr Then
-			bmx_mxmlDelete(nodePtr)
-			nodePtr = Null
-		End If
-	End Method
-	
-End Type
-
-Rem
-bbdoc: An XML Document.
-End Rem
-Type TxmlDoc Extends TxmlBase
-
-	Function _create:TxmlDoc(nodePtr:Byte Ptr)
-		If nodePtr Then
-			Local this:TxmlDoc = New TxmlDoc
-			this.nodePtr = nodePtr
-			Return this
-		End If
-	End Function
-
-	Rem
-	bbdoc: Creates a new XML document.
-	End Rem
-	Function newDoc:TxmlDoc(version:String)
-		Local this:TxmlDoc = New TxmlDoc
-		this.nodePtr = bmx_mxmlNewXML(version)
-		If this.nodePtr Then
-			Return this
-		End If
-	End Function
-
-	Rem
-	bbdoc: Parses an XML document from a String or TStream and builds a tree.
-	returns: The resulting document tree.
-	End Rem
-	Function readDoc:TxmlDoc(doc:Object)
-		If String(doc) Then
-			Local txt:String = String(doc)
-	
-			' strip utf8 BOM		
-			If txt[..3] = BOM_UTF8 Then
-				txt = txt[3..]
-			End If
-			
-			Return TxmlDoc._create(bmx_mxmlLoadString(txt))
-		
-		Else If TStream(doc) Then
-			Return parseFile(doc)
-		End If
-	End Function
-	
-	Rem
-	bbdoc: Sets the root element of the document.
-	returns: The old root element if any was found.
-	End Rem
-	Method setRootElement:TxmlNode(root:TxmlNode)
-		Return TxmlNode._create(bmx_mxmlSetRootElement(nodePtr, root.nodePtr))
-	End Method
-	
-	Rem
-	bbdoc: Returns the root element of the document.
-	End Rem
-	Method getRootElement:TxmlNode()
-		Return TxmlNode._create(bmx_mxmlGetRootElement(nodePtr))
-	End Method
-	
-	Rem
-	bbdoc: Dumps an XML document to a file.
-	returns: True on success, or Fales otherwise.
-	End Rem
-	Method saveFile:Int(file:Object, autoClose:Int = True, format:Int = False)
-
-		Local filename:String = String(file)
-		Local created:Int
-		
-		If filename Then
-			If filename = "-" Then
-				Return bmx_mxmlSaveStdout(nodePtr, format)
-			Else
-				file = WriteStream(filename)
-				created = True
-			End If		
-		End If
-		
-		If TStream(file) Then
-			Try
-				Return bmx_mxmlSaveStream(nodePtr, TStream(file), format) = 0
-			Finally
-				If created Or autoClose Then
-					TStream(file).Close()
-				End If
-			End Try
-		End If
-		
-		Return False
-	End Method
-
-	Rem
-	bbdoc: Parses an XML file and build a tree.
-	returns: The resulting document tree or Null if error.
-	End Rem
-	Function parseFile:TxmlDoc(file:Object)
-		
-		Local filename:String = String(file)
-		Local opened:Int
-		
-		If filename Then
-			file = ReadStream(filename)
-			opened = True
-		End If
-		
-		If TStream(file) Then
-			Local doc:TxmlDoc
-			Try
-				doc = _create(bmx_mxmlLoadStream(TStream(file)))
-			Finally
-				If opened Then
-					TStream(file).close()
-				End If
-			End Try
-			Return doc
-		End If
-		
-		Return Null
-	End Function
-
-	Rem
-	bbdoc: Frees the document.
-	End Rem
-	Method Free()
-		If nodePtr Then
-			bmx_mxmlDelete(nodePtr)
-			nodePtr = Null
-		End If
-	End Method
-	
-End Type
-
-Private
-Function _xmlstream_read:Int(stream:TStream, buf:Byte Ptr, count:UInt) { nomangle }
-	Return stream.Read(buf, count)
-End Function
-Function _xmlstream_write:Int(stream:TStream, buf:Byte Ptr, count:UInt) { nomangle }
-	Return stream.Write(buf, count)
-End Function
-Public
-
-Rem
-bbdoc: An xml element attribute name/value pair. (read only)
-End Rem
-Type TxmlAttribute
-	Private
-	Field name:String
-	Field value:String
-	Public
-	Method New(name:String, value:String)
-		Self.name = name
-		Self.value = value
-	End Method
-	
-	Method getName:String()
-		Return name
-	End Method
-	
-	Method getValue:String()
-		Return value
-	End Method
-End Type