diff --git a/README.md b/README.md index 20f20e71..c32d508b 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,7 @@ project, add the following to the `dependencies` section in your `pom.xml` file: com.upokecenter cbor - 4.1.1 + 4.1.3 ``` diff --git a/api/Home.md b/api/Home.md index 7f75f95c..a6047b6c 100644 --- a/api/Home.md +++ b/api/Home.md @@ -8,7 +8,8 @@ Interface implemented by classes that convert objects of arbitrary types to Classes that implement this interface can support conversions from CBOR objects to a custom type and back. -* [com.upokecenter.cbor.CBORDataUtilities](com.upokecenter.cbor.CBORDataUtilities.md) -   +* [com.upokecenter.cbor.CBORDataUtilities](com.upokecenter.cbor.CBORDataUtilities.md) - +Contains methods useful for reading and writing data, with a focus on CBOR. * [com.upokecenter.cbor.CBOREncodeOptions](com.upokecenter.cbor.CBOREncodeOptions.md) - Specifies options for encoding and decoding CBOR objects. @@ -41,7 +42,8 @@ Represents a type that a CBOR object can have. * [com.upokecenter.cbor.JSONOptions.ConversionMode](com.upokecenter.cbor.JSONOptions.ConversionMode.md) - Specifies how JSON numbers are converted to CBOR when decoding JSON. -* [com.upokecenter.cbor.CBORException](com.upokecenter.cbor.CBORException.md) -   +* [com.upokecenter.cbor.CBORException](com.upokecenter.cbor.CBORException.md) - +Exception thrown for errors involving CBOR data. * [com.upokecenter.util.DataUtilities](com.upokecenter.util.DataUtilities.md) - Contains methods useful for reading and writing text strings. diff --git a/api/com.upokecenter.cbor.CBORDataUtilities.md b/api/com.upokecenter.cbor.CBORDataUtilities.md index e63bec27..a0c9e61f 100644 --- a/api/com.upokecenter.cbor.CBORDataUtilities.md +++ b/api/com.upokecenter.cbor.CBORDataUtilities.md @@ -2,9 +2,12 @@ public final class CBORDataUtilities extends java.lang.Object +Contains methods useful for reading and writing data, with a focus on CBOR. + ## Methods * `static CBORObject ParseJSONNumber​(java.lang.String str)`
+ Parses a number whose format follows the JSON specification. * `static CBORObject ParseJSONNumber​(java.lang.String str, boolean integersOnly, boolean positiveOnly)`
@@ -25,17 +28,39 @@ Instead, call ParseJSONNumber(str, jsonoptions) with a JSONOptions that * `static CBORObject ParseJSONNumber​(java.lang.String str, int offset, int count)`
+ Parses a number whose format follows the JSON specification (RFC 8259) from + a portion of a text string, and converts that number to a CBOR + object. * `static CBORObject ParseJSONNumber​(java.lang.String str, int offset, int count, JSONOptions options)`
+ Parses a number whose format follows the JSON specification (RFC 8259) and + converts that number to a CBOR object. * `static CBORObject ParseJSONNumber​(java.lang.String str, JSONOptions options)`
+ Parses a number whose format follows the JSON specification (RFC 8259) and + converts that number to a CBOR object. ## Method Details ### ParseJSONNumber public static CBORObject ParseJSONNumber​(java.lang.String str) +Parses a number whose format follows the JSON specification. The method uses + a JSONOptions with all default properties except for a + PreserveNegativeZero property of false. + +**Parameters:** + +* str - A text string to parse as a JSON string. + +**Returns:** + +* A CBOR object that represents the parsed number. Returns positive + zero if the number is a zero that starts with a minus sign (such as + "-0" or "-0.0"). Returns null if the parsing fails, including if the + string is null or empty. + ### ParseJSONNumber @Deprecated public static CBORObject ParseJSONNumber​(java.lang.String str, boolean integersOnly, boolean positiveOnly) Deprecated. @@ -45,6 +70,23 @@ Call the one-argument version of this method instead. If this method call used integersOnly = true, check that the String does not contain '.', 'E', or 'e' before calling that version. +**Parameters:** + +* str - A text string to parse as a JSON number. + +* integersOnly - If true, no decimal points or exponents are allowed in + the string. The default is false. + +* positiveOnly - If true, only positive numbers are allowed (the leading + minus is disallowed). The default is false. + +**Returns:** + +* A CBOR object that represents the parsed number. Returns positive + zero if the number is a zero that starts with a minus sign (such as + "-0" or "-0.0"). Returns null if the parsing fails, including if the + string is null or empty. + ### ParseJSONNumber @Deprecated public static CBORObject ParseJSONNumber​(java.lang.String str, boolean integersOnly, boolean positiveOnly, boolean preserveNegativeZero) Deprecated. @@ -56,9 +98,120 @@ Instead, call ParseJSONNumber(str, jsonoptions) with a JSONOptions that that the String does not contain '.', 'E', or 'e' before calling that version. +**Parameters:** + +* str - A text string to parse as a JSON number. + +* integersOnly - If true, no decimal points or exponents are allowed in + the string. The default is false. + +* positiveOnly - If true, the leading minus is disallowed in the string. + The default is false. + +* preserveNegativeZero - If true, returns positive zero if the number is + a zero that starts with a minus sign (such as "-0" or "-0.0"). + Otherwise, returns negative zero in this case. The default is false. + +**Returns:** + +* A CBOR object that represents the parsed number. Returns null if the + parsing fails, including if the string is null or empty. + ### ParseJSONNumber public static CBORObject ParseJSONNumber​(java.lang.String str, JSONOptions options) +Parses a number whose format follows the JSON specification (RFC 8259) and + converts that number to a CBOR object.

Roughly speaking, a valid + JSON number consists of an optional minus sign, one or more basic + digits (starting with 1 to 9 unless there is only one digit and that + digit is 0), an optional decimal point (".", full stop) with one or + more basic digits, and an optional letter E or e with an optional + plus or minus sign and one or more basic digits (the exponent). A + string representing a valid JSON number is not allowed to contain + white space characters, including spaces.

+ +**Parameters:** + +* str - A text string to parse as a JSON number. + +* options - An object containing options to control how JSON numbers are + decoded to CBOR objects. Can be null, in which case a JSONOptions + object with all default properties is used instead. + +**Returns:** + +* A CBOR object that represents the parsed number. Returns null if the + parsing fails, including if the string is null or empty. + ### ParseJSONNumber public static CBORObject ParseJSONNumber​(java.lang.String str, int offset, int count) +Parses a number whose format follows the JSON specification (RFC 8259) from + a portion of a text string, and converts that number to a CBOR + object.

Roughly speaking, a valid JSON number consists of an + optional minus sign, one or more basic digits (starting with 1 to 9 + unless there is only one digit and that digit is 0), an optional + decimal point (".", full stop) with one or more basic digits, and an + optional letter E or e with an optional plus or minus sign and one + or more basic digits (the exponent). A string representing a valid + JSON number is not allowed to contain white space characters, + including spaces.

+ +**Parameters:** + +* str - A text string containing the portion to parse as a JSON number. + +* offset - An index, starting at 0, showing where the desired portion of + str begins. + +* count - The length, in code units, of the desired portion of + str (but not more than str 's length). + +**Returns:** + +* A CBOR object that represents the parsed number. Returns null if the + parsing fails, including if the string is null or empty. + +**Throws:** + +* java.lang.IllegalArgumentException - Either offset or count is less + than 0 or greater than str 's length, or str 's + length minus offset is less than count. + +* java.lang.NullPointerException - The parameter str is null. + ### ParseJSONNumber public static CBORObject ParseJSONNumber​(java.lang.String str, int offset, int count, JSONOptions options) +Parses a number whose format follows the JSON specification (RFC 8259) and + converts that number to a CBOR object.

Roughly speaking, a valid + JSON number consists of an optional minus sign, one or more basic + digits (starting with 1 to 9 unless there is only one digit and that + digit is 0), an optional decimal point (".", full stop) with one or + more basic digits, and an optional letter E or e with an optional + plus or minus sign and one or more basic digits (the exponent). A + string representing a valid JSON number is not allowed to contain + white space characters, including spaces.

+ +**Parameters:** + +* str - A text string to parse as a JSON number. + +* offset - An index, starting at 0, showing where the desired portion of + str begins. + +* count - The length, in code units, of the desired portion of + str (but not more than str 's length). + +* options - An object containing options to control how JSON numbers are + decoded to CBOR objects. Can be null, in which case a JSONOptions + object with all default properties is used instead. + +**Returns:** + +* A CBOR object that represents the parsed number. Returns null if the + parsing fails, including if the string is null or empty or + count is 0 or less. + +**Throws:** + +* java.lang.NullPointerException - The parameter str is null. + +* java.lang.IllegalArgumentException - Unsupported conversion kind. diff --git a/api/com.upokecenter.cbor.CBORException.md b/api/com.upokecenter.cbor.CBORException.md index 5084c10e..2e35162f 100644 --- a/api/com.upokecenter.cbor.CBORException.md +++ b/api/com.upokecenter.cbor.CBORException.md @@ -2,16 +2,38 @@ public final class CBORException extends java.lang.RuntimeException +Exception thrown for errors involving CBOR data.

This library may throw + exceptions of this type in certain cases, notably when errors occur, + and may supply messages to those exceptions (the message can be + accessed through the Message property in.NET or the + getMessage() method in Java). These messages are intended to be + read by humans to help diagnose the error (or other cause of the + exception); they are not intended to be parsed by computer programs, + and the exact text of the messages may change at any time between + versions of this library.

+ ## Methods -* `CBORException()`
-* `CBORException​(java.lang.String message)`
+* `CBORException() CBORException`
+ Initializes a new instance of the CBORException + class. +* `CBORException​(java.lang.String message) CBORException`
+ Initializes a new instance of the CBORException + class. * `CBORException​(java.lang.String message, - java.lang.Throwable innerException)`
+ java.lang.Throwable innerException) CBORException`
+ Initializes a new instance of the CBORException + class. ## Constructors -* `CBORException()`
-* `CBORException​(java.lang.String message)`
+* `CBORException() CBORException`
+ Initializes a new instance of the CBORException + class. +* `CBORException​(java.lang.String message) CBORException`
+ Initializes a new instance of the CBORException + class. * `CBORException​(java.lang.String message, - java.lang.Throwable innerException)`
+ java.lang.Throwable innerException) CBORException`
+ Initializes a new instance of the CBORException + class. diff --git a/api/com.upokecenter.cbor.CBORObject.md b/api/com.upokecenter.cbor.CBORObject.md index f2db24a3..d3fa37ca 100644 --- a/api/com.upokecenter.cbor.CBORObject.md +++ b/api/com.upokecenter.cbor.CBORObject.md @@ -143,10 +143,10 @@ Instead, use.getToObject()<PeterO.Numbers.EDecimal>() in Java. * `com.upokecenter.numbers.EFloat AsEFloat()`
Deprecated. -Instead, use.getToObject()<PeterO.Numbers.EFloat>() in.getNET() +Instead, use.getToObject()<PeterO.Numbers.EFloat>() in.NET or .getToObject()(com.upokecenter.numbers.EFloat.class) in Java. - Instead, use.getToObject()<PeterO.Numbers.EFloat>() in.getNET() + Instead, use.getToObject()<PeterO.Numbers.EFloat>() in.NET or .getToObject()(com.upokecenter.numbers.EFloat.class) in Java. * `com.upokecenter.numbers.EInteger AsEInteger()`
@@ -172,10 +172,10 @@ Instead, use.getToObject()<PeterO.Numbers.ERational>() in in Java. * `short AsInt16()`
Deprecated. -Instead, use the following: (cbor.AsNumber().ToInt16Checked()), - or .getToObject()<short>() in .getNET(). - Instead, use the following: (cbor.AsNumber().ToInt16Checked()), - or .getToObject()<short>() in .getNET(). +Instead, use the following: (cbor.AsNumber().ToInt16Checked()), or +.ToObject<short>() in .NET. + Instead, use the following: (cbor.AsNumber().ToInt16Checked()), or +.ToObject<short>() in .NET. * `int AsInt32()`
Converts this object to a 32-bit signed integer. * `int AsInt32Value()`
@@ -184,9 +184,9 @@ Instead, use the following: (cbor.AsNumber().ToInt16Checked()), * `long AsInt64()`
Deprecated. Instead, use the following: (cbor.AsNumber().ToInt64Checked()), or -.ToObject<long>() in.getNET(). +.ToObject<long>() in.NET. Instead, use the following: (cbor.AsNumber().ToInt64Checked()), or -.ToObject<long>() in.getNET(). +.ToObject<long>() in.NET. * `long AsInt64Value()`
Converts this object to a 64-bit signed integer if this CBOR object's type is Integer. @@ -982,8 +982,8 @@ Gets the outermost tag for this CBOR data item, or -1 if the item is @Deprecated public final int signum() Deprecated. Instead, convert this object to a number with.AsNumber(), and use the - Sign property in.NET or the signum method in Java. Either will - treat not-a-number (NaN) values differently than here. + Sign property in.NET or the signum method in Java. Either will treat + not-a-number (NaN) values differently than here. **Returns:** @@ -1411,7 +1411,7 @@ Generates a list of CBOR objects from an array of bytes in JavaScript object public static CBORObject DecodeFromBytes​(byte[] data, CBOREncodeOptions options) Generates a CBOR object from an array of CBOR-encoded bytes, using the given CBOREncodeOptions object to control the decoding process.

-

The following example (originally written in C# for the.getNET() +

The following example (originally written in C# for the.NET version) implements a method that decodes a text string from a CBOR byte array. It's successful only if the CBOR object contains an untagged text string.

private static string DecodeTextString(byte[] bytes) { if (bytes == null) { throw new NullPointerException("mapObj");} if (bytes.length == 0 || bytes[0]<0x60 || bytes[0]>0x7f) {throw new CBORException();} return CBORObject.DecodeFromBytes(bytes, CBOREncodeOptions.Default).AsString(); }
. @@ -1781,7 +1781,7 @@ Converts this CBOR object to an object of an arbitrary type. See the the same rules as for long are used, but the range is from 0 through 2^63-1 and the return type is ulong .
  • If the type is int or a primitive floating-point type (float - , double , as well as decimal in.getNET()), returns the + , double , as well as decimal in.NET), returns the result of the corresponding As* method.
  • If the type is string , returns the result of AsString.
  • If the type is EFloat , EDecimal , EInteger , or @@ -1965,11 +1965,10 @@ Generates a CBOR object from a CBOR object. public long CalcEncodedSize() Calculates the number of bytes this CBOR object takes when serialized as a byte array using the EncodeToBytes() method. This calculation - assumes that integers, lengths of maps and arrays, lengths of text - and byte strings, and tag numbers are encoded in their shortest - form; that floating-point numbers are encoded in their shortest - value-preserving form; and that no indefinite-length encodings are - used. + assumes that integers, lengths of maps and arrays, lengths of text and + byte strings, and tag numbers are encoded in their shortest form; that + floating-point numbers are encoded in their shortest value-preserving + form; and that no indefinite-length encodings are used. **Returns:** @@ -1979,8 +1978,8 @@ Calculates the number of bytes this CBOR object takes when serialized as a **Throws:** * CBORException - The CBOR object has an extremely - deep level of nesting, including if the CBOR object is or has an - array or map that includes itself. + deep level of nesting, including if the CBOR object is or has an array + or map that includes itself. ### FromObject public static CBORObject FromObject​(com.upokecenter.numbers.EInteger bigintValue) @@ -2311,9 +2310,9 @@ Generates a CBORObject from an arbitrary object. See the overload of this byte is converted to a CBOR integer from 0 through 255.
  • A primitive integer type (int, short, long, as well as sbyte, ushort, uint , - and ulong in.getNET()) is converted to the corresponding CBOR + and ulong in.NET) is converted to the corresponding CBOR integer.
  • A primitive floating-point type (float, - double, as well as decimal in.getNET()) is converted to the + double, as well as decimal in.NET) is converted to the corresponding CBOR number.
  • A string is converted to a CBOR text string. To create a CBOR byte string object from string, see the example given in .
  • @@ -3571,7 +3570,7 @@ Instead, use.getToObject()&lt;PeterO.Numbers.EDecimal&gt;() ### AsEFloat @Deprecated public com.upokecenter.numbers.EFloat AsEFloat() Deprecated. -Instead, use.getToObject()&lt;PeterO.Numbers.EFloat&gt;() in.getNET() +Instead, use.getToObject()&lt;PeterO.Numbers.EFloat&gt;() in.NET or .getToObject()(com.upokecenter.numbers.EFloat.class) in Java. @@ -3606,8 +3605,8 @@ Instead, use.getToObject()&lt;PeterO.Numbers.ERational&gt;() in ### AsInt16 @Deprecated public short AsInt16() Deprecated. -Instead, use the following: (cbor.AsNumber().ToInt16Checked()), - or .getToObject()&lt;short&gt;() in .getNET(). +Instead, use the following: (cbor.AsNumber().ToInt16Checked()), or +.ToObject&lt;short&gt;() in .NET. **Returns:** @@ -3785,7 +3784,7 @@ Converts this object to a 32-bit signed integer. Non-integer number values @Deprecated public long AsInt64() Deprecated. Instead, use the following: (cbor.AsNumber().ToInt64Checked()), or -.ToObject&lt;long&gt;() in.getNET(). +.ToObject&lt;long&gt;() in.NET. **Returns:** diff --git a/api/com.upokecenter.cbor.JSONOptions.ConversionMode.md b/api/com.upokecenter.cbor.JSONOptions.ConversionMode.md index 0042f1cc..ce505a65 100644 --- a/api/com.upokecenter.cbor.JSONOptions.ConversionMode.md +++ b/api/com.upokecenter.cbor.JSONOptions.ConversionMode.md @@ -57,15 +57,9 @@ the order they are declared. ### Full public static final JSONOptions.ConversionMode Full JSON numbers are decoded to CBOR using the full precision given in the JSON - text. The number will be converted to a CBOR object as follows: - If the number's exponent is 0 (after shifting the decimal point - to the end of the number without changing its value), using the - rules given in the CBORObject.FromObject(EInteger) method; - otherwise, using the rules given in the - CBORObject.FromObject(EDecimal) method. An exception in - version 4.x involves negative zeros; if the negative zero's - exponent is 0, it's written as a CBOR floating-point number; - otherwise the negative zero is written as an EDecimal. + text. This may involve numbers being converted to + arbitrary-precision integers or decimal numbers, where + appropriate. ### Double public static final JSONOptions.ConversionMode Double JSON numbers are decoded to CBOR as their closest-rounded approximation as diff --git a/api/com.upokecenter.util.DataUtilities.md b/api/com.upokecenter.util.DataUtilities.md index 466a912f..c65ea6d8 100644 --- a/api/com.upokecenter.util.DataUtilities.md +++ b/api/com.upokecenter.util.DataUtilities.md @@ -181,7 +181,7 @@ Generates a text string from a portion of a UTF-8 byte array.

    Encodes a string in UTF-8 as a byte array. This method does not insert a byte-order mark (U+FEFF) at the beginning of the encoded byte array.

    REMARK: It is not recommended to use - Encoding.UTF8.GetBytes in.getNET(), or the getBytes() + Encoding.UTF8.GetBytes in.NET, or the getBytes() method in Java to do this. For instance, getBytes() encodes text strings in a default (so not fixed) character encoding, which can be undesirable.

    @@ -210,7 +210,7 @@ Generates a text string from a portion of a UTF-8 byte array.

    Encodes a string in UTF-8 as a byte array. This method does not insert a byte-order mark (U+FEFF) at the beginning of the encoded byte array.

    REMARK: It is not recommended to use - Encoding.UTF8.GetBytes in.getNET(), or the getBytes() + Encoding.UTF8.GetBytes in.NET, or the getBytes() method in Java to do this. For instance, getBytes() encodes text strings in a default (so not fixed) character encoding, which can be undesirable.

    diff --git a/pom.xml b/pom.xml index dc427523..b68b2d7a 100644 --- a/pom.xml +++ b/pom.xml @@ -4,10 +4,66 @@ com.upokecenter cbor jar - 4.1.0-SNAPSHOT + 4.1.3 CBOR (Concise Binary Object Representation) - A Java implementation of Concise Binary Object Representation (CBOR), a general-purpose binary data format defined in RFC 7049. + A Java implementation of Concise Binary Object Representation (CBOR), a general-purpose binary data format defined in RFC 7049. https://github.com/peteroupc/CBOR-Java + + + release + + + + org.apache.maven.plugins + maven-gpg-plugin + 1.5 + + + sign-artifacts + verify + + sign + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + 3.0.1 + + CBOR for Java documentation, generated in {currentYear}. + + -html5 + + + + + + attach-javadocs + + jar + + + + + + org.apache.maven.plugins + maven-source-plugin + 2.2.1 + + + attach-sources + + jar-no-fork + + + + + + + + scm:git:https://github.com/peteroupc/CBOR-Java scm:git:https://github.com/peteroupc/CBOR-Java.git @@ -26,8 +82,8 @@ UTF-8 - 8 - 1.8 + 6 + 1.6 @@ -44,15 +100,21 @@ 3.7.0 - -Xlint:deprecation + -Xlint:all - - edu.berkeley.cs.jqf - jqf-maven-plugin - 1.4 - + + org.sonatype.plugins + nexus-staging-maven-plugin + true + 1.6.1 + + ossrh + true + https://oss.sonatype.org/ + + @@ -62,16 +124,6 @@ - - edu.berkeley.cs.jqf - jqf-fuzz - 1.4 - - - com.alibaba - fastjson - 1.2.25 - junit junit diff --git a/src/main/java/com/upokecenter/cbor/CBORDataUtilities.java b/src/main/java/com/upokecenter/cbor/CBORDataUtilities.java index b9c9676a..044c33a8 100644 --- a/src/main/java/com/upokecenter/cbor/CBORDataUtilities.java +++ b/src/main/java/com/upokecenter/cbor/CBORDataUtilities.java @@ -12,6 +12,9 @@ import com.upokecenter.util.*; import com.upokecenter.numbers.*; + /** + * Contains methods useful for reading and writing data, with a focus on CBOR. + */ public final class CBORDataUtilities { private CBORDataUtilities() { } @@ -176,13 +179,42 @@ static String ToStringHelper(CBORObject obj, int depth) { private static final JSONOptions PreserveNegZeroYes = new JSONOptions("preservenegativezero=1"); + /** + * Parses a number whose format follows the JSON specification. The method uses + * a JSONOptions with all default properties except for a + * PreserveNegativeZero property of false. + * @param str A text string to parse as a JSON string. + * @return A CBOR object that represents the parsed number. Returns positive + * zero if the number is a zero that starts with a minus sign (such as + * "-0" or "-0.0"). Returns null if the parsing fails, including if the + * string is null or empty. + */ public static CBORObject ParseJSONNumber(String str) { // TODO: Preserve negative zeros in next major version return ParseJSONNumber(str, PreserveNegZeroNo); } -/** - * @deprecated Call the one-argument version of this method instead. If this\u0020method + /** + * Parses a number whose format follows the JSON specification (RFC 8259). The + * method uses a JSONOptions with all default properties except for a + * PreserveNegativeZero property of false.

    Roughly speaking, a valid + * JSON number consists of an optional minus sign, one or more basic + * digits (starting with 1 to 9 unless there is only one digit and that + * digit is 0), an optional decimal point (".", full stop) with one or + * more basic digits, and an optional letter E or e with an optional + * plus or minus sign and one or more basic digits (the exponent). A + * string representing a valid JSON number is not allowed to contain + * white space characters, including spaces.

    + * @param str A text string to parse as a JSON number. + * @param integersOnly If true, no decimal points or exponents are allowed in + * the string. The default is false. + * @param positiveOnly If true, only positive numbers are allowed (the leading + * minus is disallowed). The default is false. + * @return A CBOR object that represents the parsed number. Returns positive + * zero if the number is a zero that starts with a minus sign (such as + * "-0" or "-0.0"). Returns null if the parsing fails, including if the + * string is null or empty. + * @deprecated Call the one-argument version of this method instead. If this\u0020method * call used positiveOnly = true, check that the String\u0020does * not\u0020begin\u0020with '-' before calling that version. If this method * call used\u0020integersOnly\u0020 = true, check that the String does not @@ -211,8 +243,27 @@ public static CBORObject ParseJSONNumber( PreserveNegZeroNo); } -/** - * @deprecated Instead, call ParseJSONNumber(str, jsonoptions) with\u0020a JSONOptions that + /** + * Parses a number whose format follows the JSON specification (RFC + * 8259).

    Roughly speaking, a valid JSON number consists of an + * optional minus sign, one or more basic digits (starting with 1 to 9 + * unless there is only one digit and that digit is 0), an optional + * decimal point (".", full stop) with one or more basic digits, and an + * optional letter E or e with an optional plus or minus sign and one + * or more basic digits (the exponent). A string representing a valid + * JSON number is not allowed to contain white space characters, + * including spaces.

    + * @param str A text string to parse as a JSON number. + * @param integersOnly If true, no decimal points or exponents are allowed in + * the string. The default is false. + * @param positiveOnly If true, the leading minus is disallowed in the string. + * The default is false. + * @param preserveNegativeZero If true, returns positive zero if the number is + * a zero that starts with a minus sign (such as "-0" or "-0.0"). + * Otherwise, returns negative zero in this case. The default is false. + * @return A CBOR object that represents the parsed number. Returns null if the + * parsing fails, including if the string is null or empty. + * @deprecated Instead, call ParseJSONNumber(str, jsonoptions) with\u0020a JSONOptions that * sets preserveNegativeZero to the\u0020desired value, either true or * false. If this\u0020method call used positiveOnly = true, check that the * String\u0020does not\u0020begin\u0020with '-' before calling that @@ -245,6 +296,23 @@ public static CBORObject ParseJSONNumber( jo); } + /** + * Parses a number whose format follows the JSON specification (RFC 8259) and + * converts that number to a CBOR object.

    Roughly speaking, a valid + * JSON number consists of an optional minus sign, one or more basic + * digits (starting with 1 to 9 unless there is only one digit and that + * digit is 0), an optional decimal point (".", full stop) with one or + * more basic digits, and an optional letter E or e with an optional + * plus or minus sign and one or more basic digits (the exponent). A + * string representing a valid JSON number is not allowed to contain + * white space characters, including spaces.

    + * @param str A text string to parse as a JSON number. + * @param options An object containing options to control how JSON numbers are + * decoded to CBOR objects. Can be null, in which case a JSONOptions + * object with all default properties is used instead. + * @return A CBOR object that represents the parsed number. Returns null if the + * parsing fails, including if the string is null or empty. + */ public static CBORObject ParseJSONNumber( String str, JSONOptions options) { @@ -255,6 +323,29 @@ public static CBORObject ParseJSONNumber( options); } + /** + * Parses a number whose format follows the JSON specification (RFC 8259) from + * a portion of a text string, and converts that number to a CBOR + * object.

    Roughly speaking, a valid JSON number consists of an + * optional minus sign, one or more basic digits (starting with 1 to 9 + * unless there is only one digit and that digit is 0), an optional + * decimal point (".", full stop) with one or more basic digits, and an + * optional letter E or e with an optional plus or minus sign and one + * or more basic digits (the exponent). A string representing a valid + * JSON number is not allowed to contain white space characters, + * including spaces.

    + * @param str A text string containing the portion to parse as a JSON number. + * @param offset An index, starting at 0, showing where the desired portion of + * {@code str} begins. + * @param count The length, in code units, of the desired portion of {@code + * str} (but not more than {@code str} 's length). + * @return A CBOR object that represents the parsed number. Returns null if the + * parsing fails, including if the string is null or empty. + * @throws IllegalArgumentException Either {@code offset} or {@code count} is less + * than 0 or greater than {@code str} 's length, or {@code str} 's + * length minus {@code offset} is less than {@code count}. + * @throws NullPointerException The parameter {@code str} is null. + */ public static CBORObject ParseJSONNumber( String str, int offset, @@ -272,6 +363,9 @@ static CBORObject ParseSmallNumberAsNegative( if (options != null && options.getNumberConversion() == JSONOptions.ConversionMode.Double) { return CBORObject.FromObject((double)(-digit)); + } else if (options != null && options.getNumberConversion() == + JSONOptions.ConversionMode.Decimal128) { + return CBORObject.FromObject(EDecimal.FromInt32(-digit)); } else { // NOTE: Assumes digit is greater than zero, so PreserveNegativeZeros is // irrelevant @@ -284,12 +378,39 @@ static CBORObject ParseSmallNumber(int digit, JSONOptions if (options != null && options.getNumberConversion() == JSONOptions.ConversionMode.Double) { return CBORObject.FromObject((double)digit); + } else if (options != null && options.getNumberConversion() == + JSONOptions.ConversionMode.Decimal128) { + return CBORObject.FromObject(EDecimal.FromInt32(digit)); } else { // NOTE: Assumes digit is nonnegative, so PreserveNegativeZeros is irrelevant return CBORObject.FromObject(digit); } } + /** + * Parses a number whose format follows the JSON specification (RFC 8259) and + * converts that number to a CBOR object.

    Roughly speaking, a valid + * JSON number consists of an optional minus sign, one or more basic + * digits (starting with 1 to 9 unless there is only one digit and that + * digit is 0), an optional decimal point (".", full stop) with one or + * more basic digits, and an optional letter E or e with an optional + * plus or minus sign and one or more basic digits (the exponent). A + * string representing a valid JSON number is not allowed to contain + * white space characters, including spaces.

    + * @param str A text string to parse as a JSON number. + * @param offset An index, starting at 0, showing where the desired portion of + * {@code str} begins. + * @param count The length, in code units, of the desired portion of {@code + * str} (but not more than {@code str} 's length). + * @param options An object containing options to control how JSON numbers are + * decoded to CBOR objects. Can be null, in which case a JSONOptions + * object with all default properties is used instead. + * @return A CBOR object that represents the parsed number. Returns null if the + * parsing fails, including if the string is null or empty or {@code + * count} is 0 or less. + * @throws NullPointerException The parameter {@code str} is null. + * @throws IllegalArgumentException Unsupported conversion kind. + */ public static CBORObject ParseJSONNumber( String str, int offset, diff --git a/src/main/java/com/upokecenter/cbor/CBORDateConverter.java b/src/main/java/com/upokecenter/cbor/CBORDateConverter.java index 21f2369f..e645667a 100644 --- a/src/main/java/com/upokecenter/cbor/CBORDateConverter.java +++ b/src/main/java/com/upokecenter/cbor/CBORDateConverter.java @@ -17,13 +17,6 @@ private static String DateTimeToString(java.util.Date bi) { return CBORUtilities.ToAtomDateTimeString(year[0], lesserFields); } - public CBORObject ValidateObject(CBORObject obj) { - if (obj.getType() != CBORType.TextString) { - throw new CBORException("Not a text String"); - } - return obj; - } - public java.util.Date FromCBORObject(CBORObject obj) { if (obj.HasMostOuterTag(0)) { try { diff --git a/src/main/java/com/upokecenter/cbor/CBORException.java b/src/main/java/com/upokecenter/cbor/CBORException.java index 7bd4c731..779fa09b 100644 --- a/src/main/java/com/upokecenter/cbor/CBORException.java +++ b/src/main/java/com/upokecenter/cbor/CBORException.java @@ -6,16 +6,43 @@ at: http://peteroupc.github.io/ */ + /** + * Exception thrown for errors involving CBOR data.

    This library may throw + * exceptions of this type in certain cases, notably when errors occur, + * and may supply messages to those exceptions (the message can be + * accessed through the Message property in.NET or the + * getMessage() method in Java). These messages are intended to be + * read by humans to help diagnose the error (or other cause of the + * exception); they are not intended to be parsed by computer programs, + * and the exact text of the messages may change at any time between + * versions of this library.

    + */ + public final class CBORException extends RuntimeException { private static final long serialVersionUID = 1L; - + /** + * Initializes a new instance of the {@link com.upokecenter.cbor.CBORException} + * class. + */ public CBORException() { } + /** + * Initializes a new instance of the {@link com.upokecenter.cbor.CBORException} + * class. + * @param message The parameter {@code message} is a text string. + */ public CBORException(String message) { super(message); } + /** + * Initializes a new instance of the {@link com.upokecenter.cbor.CBORException} + * class. Uses the given message and inner exception. + * @param message The parameter {@code message} is a text string. + * @param innerException The parameter {@code innerException} is an Exception + * object. + */ public CBORException(String message, Throwable innerException) { super(message); initCause(innerException);; diff --git a/src/main/java/com/upokecenter/cbor/CBORJson.java b/src/main/java/com/upokecenter/cbor/CBORJson.java index 24b1c2c9..b1ba0124 100644 --- a/src/main/java/com/upokecenter/cbor/CBORJson.java +++ b/src/main/java/com/upokecenter/cbor/CBORJson.java @@ -565,7 +565,7 @@ private CBORObject ParseJSONObject(int depth) { CBORObject obj; int[] nextChar = new int[1]; boolean seenComma = false; - TreeMap myHashMap = new TreeMap(); + HashMap myHashMap = new HashMap(); while (true) { c = this.SkipWhitespaceJSON(); switch (c) { diff --git a/src/main/java/com/upokecenter/cbor/CBORJson2.java b/src/main/java/com/upokecenter/cbor/CBORJson2.java index 3657a9e8..64f95db7 100644 --- a/src/main/java/com/upokecenter/cbor/CBORJson2.java +++ b/src/main/java/com/upokecenter/cbor/CBORJson2.java @@ -8,7 +8,6 @@ */ import java.util.*; -import java.io.*; import com.upokecenter.util.*; import com.upokecenter.numbers.*; @@ -32,280 +31,166 @@ void RaiseError(String str) { private final byte[] bytes; private final JSONOptions options; + private StringBuilder sb; private int index; private int endPos; - private static byte[] valueEmptyBytes = new byte[0]; - private byte[] NextJSONString() { + private String NextJSONString() { int c; - int startIndex = this.index; - int batchIndex = startIndex; - int batchEnd = startIndex; - byte[] jbytes = this.bytes; + this.sb = (this.sb == null) ? (new StringBuilder()) : this.sb; + this.sb.delete(0, this.sb.length()); while (true) { - if (this.index >= this.endPos) { + c = this.index < this.endPos ? ((int)this.bytes[this.index++]) & + 0xff : -1; + if (c == -1 || c < 0x20) { this.RaiseError("Unterminated String"); } - c = ((int)jbytes[this.index++]) & 0xff; - if (c < 0x20) { - this.RaiseError("Invalid character in String literal"); - } - if (c == '\\') { - batchEnd = this.index - 1; - break; - } else if (c == 0x22) { - int isize = (this.index - startIndex) - 1; - if (isize == 0) { - return valueEmptyBytes; - } - byte[] buf = new byte[isize]; - System.arraycopy(jbytes, startIndex, buf, 0, isize); - return buf; - } else if (c < 0x80) { - continue; - } else if (c >= 0xc2 && c <= 0xdf) { - int c1 = this.index < this.endPos ? - ((int)this.bytes[this.index++]) & 0xff : -1; - if (c1 < 0x80 || c1 > 0xbf) { - this.RaiseError("Invalid encoding"); - } - } else if (c >= 0xe0 && c <= 0xef) { - int c1 = this.index < this.endPos ? - ((int)this.bytes[this.index++]) & 0xff : -1; - int c2 = this.index < this.endPos ? - ((int)this.bytes[this.index++]) & 0xff : -1; - int lower = (c == 0xe0) ? 0xa0 : 0x80; - int upper = (c == 0xed) ? 0x9f : 0xbf; - if (c1 < lower || c1 > upper || c2 < 0x80 || c2 > 0xbf) { - this.RaiseError("Invalid encoding"); - } - } else if (c >= 0xf0 && c <= 0xf4) { - int c1 = this.index < this.endPos ? - ((int)this.bytes[this.index++]) & 0xff : -1; - int c2 = this.index < this.endPos ? - ((int)this.bytes[this.index++]) & 0xff : -1; - int c3 = this.index < this.endPos ? - ((int)this.bytes[this.index++]) & 0xff : -1; - int lower = (c == 0xf0) ? 0x90 : 0x80; - int upper = (c == 0xf4) ? 0x8f : 0xbf; - if (c1 < lower || c1 > upper || c2 < 0x80 || c2 > 0xbf || - c3 < 0x80 || c3 > 0xbf) { - this.RaiseError("Invalid encoding"); - } - } else { - this.RaiseError("Invalid encoding"); - } - } - { - java.io.ByteArrayOutputStream ms = null; -try { -ms = new java.io.ByteArrayOutputStream(); - - if (batchEnd > batchIndex) { - ms.write(jbytes, batchIndex, batchEnd - batchIndex); - this.index = batchEnd; - batchIndex = batchEnd; - } else { - this.index = startIndex; - batchIndex = startIndex; - } - while (true) { - batchEnd = this.index; - c = this.index < this.endPos ? ((int)jbytes[this.index++]) & - 0xff : -1; - if (c == -1) { - this.RaiseError("Unterminated String"); - } - if (c < 0x20) { - this.RaiseError("Invalid character in String literal"); - } - switch (c) { - case '\\': - c = this.index < this.endPos ? ((int)jbytes[this.index++]) & - 0xff : -1; - switch (c) { - case '\\': - case '/': - case '\"': - // Slash is now allowed to be escaped under RFC 8259 - if (batchEnd > batchIndex) { - ms.write(jbytes, batchIndex, batchEnd - batchIndex); - } - batchIndex = this.index; - ms.write((byte)c); - break; - case 'b': - if (batchEnd > batchIndex) { - ms.write(jbytes, batchIndex, batchEnd - batchIndex); - } - batchIndex = this.index; - ms.write((byte)'\b'); - break; - case 'f': - if (batchEnd > batchIndex) { - ms.write(jbytes, batchIndex, batchEnd - batchIndex); - } - batchIndex = this.index; - ms.write((byte)'\f'); - break; - case 'n': - if (batchEnd > batchIndex) { - ms.write(jbytes, batchIndex, batchEnd - batchIndex); - } - batchIndex = this.index; - ms.write((byte)'\n'); - break; - case 'r': - if (batchEnd > batchIndex) { - ms.write(jbytes, batchIndex, batchEnd - batchIndex); + switch (c) { + case '\\': + c = this.index < this.endPos ? ((int)this.bytes[this.index++]) & + 0xff : -1; + switch (c) { + case '\\': + case '/': + case '\"': + // Slash is now allowed to be escaped under RFC 8259 + this.sb.append((char)c); + break; + case 'b': + this.sb.append('\b'); + break; + case 'f': + this.sb.append('\f'); + break; + case 'n': + this.sb.append('\n'); + break; + case 'r': + this.sb.append('\r'); + break; + case 't': + this.sb.append('\t'); + break; + case 'u': { // Unicode escape + c = 0; + // Consists of 4 hex digits + for (int i = 0; i < 4; ++i) { + int ch = this.index < this.endPos ? + ((int)this.bytes[this.index++]) & 0xff : -1; + if (ch >= '0' && ch <= '9') { + c <<= 4; + c |= ch - '0'; + } else if (ch >= 'A' && ch <= 'F') { + c <<= 4; + c |= ch + 10 - 'A'; + } else if (ch >= 'a' && ch <= 'f') { + c <<= 4; + c |= ch + 10 - 'a'; + } else { + this.RaiseError( + "Invalid Unicode escaped character"); } - batchIndex = this.index; - ms.write((byte)'\r'); - break; - case 't': - if (batchEnd > batchIndex) { - ms.write(jbytes, batchIndex, batchEnd - batchIndex); + } + if ((c & 0xf800) != 0xd800) { + // Non-surrogate + this.sb.append((char)c); + } else if ((c & 0xfc00) == 0xd800) { + int ch = this.index < this.endPos ? + ((int)this.bytes[this.index++]) & 0xff : -1; + if (ch != '\\' || (this.index < this.endPos ? + ((int)this.bytes[this.index++]) & 0xff : -1) != 'u') { + this.RaiseError("Invalid escaped character"); } - batchIndex = this.index; - ms.write((byte)'\t'); - break; - case 'u': { // Unicode escape - c = 0; - // Consists of 4 hex digits + int c2 = 0; for (int i = 0; i < 4; ++i) { - int ch = this.index < this.endPos ? - (int)jbytes[this.index++] : -1; + ch = this.index < this.endPos ? + ((int)this.bytes[this.index++]) & 0xff : -1; if (ch >= '0' && ch <= '9') { - c <<= 4; - c |= ch - '0'; + c2 <<= 4; + c2 |= ch - '0'; } else if (ch >= 'A' && ch <= 'F') { - c <<= 4; - c |= ch + 10 - 'A'; + c2 <<= 4; + c2 |= ch + 10 - 'A'; } else if (ch >= 'a' && ch <= 'f') { - c <<= 4; - c |= ch + 10 - 'a'; + c2 <<= 4; + c2 |= ch + 10 - 'a'; } else { this.RaiseError( "Invalid Unicode escaped character"); } } - if ((c & 0xf800) != 0xd800) { - // Non-surrogate - if (batchEnd > batchIndex) { - ms.write(jbytes, batchIndex, batchEnd - batchIndex); - } - batchIndex = this.index; - int ic = c; - if (c >= 0x800) { - ms.write((byte)(0xe0 | ((ic >> 12) & 0x0f))); - ms.write((byte)(0x80 | ((ic >> 6) & 0x3f))); - ms.write((byte)(0x80 | (ic & 0x3f))); - } else if (c >= 0x80) { - ms.write((byte)(0xc0 | ((ic >> 6) & 0x1f))); - ms.write((byte)(0x80 | (ic & 0x3f))); - } else { - ms.write((byte)ic); - } - } else if ((c & 0xfc00) == 0xd800) { - int ch; - if (this.index >= this.endPos - 1 || - jbytes[this.index] != (byte)'\\' || - jbytes[this.index + 1] != (byte)0x75) { - this.RaiseError("Invalid escaped character"); - } - this.index += 2; - int c2 = 0; - for (int i = 0; i < 4; ++i) { - ch = this.index < this.endPos ? - ((int)jbytes[this.index++]) & 0xff : -1; - if (ch >= '0' && ch <= '9') { - c2 <<= 4; - c2 |= ch - '0'; - } else if (ch >= 'A' && ch <= 'F') { - c2 <<= 4; - c2 |= ch + 10 - 'A'; - } else if (ch >= 'a' && ch <= 'f') { - c2 <<= 4; - c2 |= ch + 10 - 'a'; - } else { - this.RaiseError( - "Invalid Unicode escaped character"); - } - } - if ((c2 & 0xfc00) != 0xdc00) { - this.RaiseError("Unpaired surrogate code point"); - } else { - if (batchEnd > batchIndex) { - ms.write(jbytes, batchIndex, batchEnd - batchIndex); - } - batchIndex = this.index; - int ic = 0x10000 + (((int)c & 0x3ff) << 10) + - ((int)c2 & 0x3ff); - ms.write((byte)(0xf0 | ((ic >> 18) & 0x07))); - ms.write((byte)(0x80 | ((ic >> 12) & 0x3f))); - ms.write((byte)(0x80 | ((ic >> 6) & 0x3f))); - ms.write((byte)(0x80 | (ic & 0x3f))); - } - } else { + if ((c2 & 0xfc00) != 0xdc00) { this.RaiseError("Unpaired surrogate code point"); + } else { + this.sb.append((char)c); + this.sb.append((char)c2); } - break; - } - default: { - this.RaiseError("Invalid escaped character"); - break; + } else { + this.RaiseError("Unpaired surrogate code point"); } + break; } - break; - case 0x22: // double quote - if (batchEnd > batchIndex) { - ms.write(jbytes, batchIndex, batchEnd - batchIndex); + default: { + this.RaiseError("Invalid escaped character"); + break; } - return ms.toByteArray(); - default: { - if (c <= 0x7f) { - // Deliberately empty - } else if (c >= 0xc2 && c <= 0xdf) { - int c1 = this.index < this.endPos ? - ((int)jbytes[this.index++]) & 0xff : -1; - if (c1 < 0x80 || c1 > 0xbf) { - this.RaiseError("Invalid encoding"); - } - } else if (c >= 0xe0 && c <= 0xef) { - int c1 = this.index < this.endPos ? - ((int)jbytes[this.index++]) & 0xff : -1; - int c2 = this.index < this.endPos ? - ((int)jbytes[this.index++]) & 0xff : -1; - int lower = (c == 0xe0) ? 0xa0 : 0x80; - int upper = (c == 0xed) ? 0x9f : 0xbf; - if (c1 < lower || c1 > upper || c2 < 0x80 || c2 > 0xbf) { - this.RaiseError("Invalid encoding"); - } - } else if (c >= 0xf0 && c <= 0xf4) { - int c1 = this.index < this.endPos ? - ((int)jbytes[this.index++]) & 0xff : -1; - int c2 = this.index < this.endPos ? - ((int)jbytes[this.index++]) & 0xff : -1; - int c3 = this.index < this.endPos ? - ((int)jbytes[this.index++]) & 0xff : -1; - int lower = (c == 0xf0) ? 0x90 : 0x80; - int upper = (c == 0xf4) ? 0x8f : 0xbf; - if (c1 < lower || c1 > upper || c2 < 0x80 || c2 > 0xbf || - c3 < 0x80 || c3 > 0xbf) { - this.RaiseError("Invalid encoding"); - } - } else { + } + break; + case 0x22: // double quote + return this.sb.toString(); + default: { + if (c <= 0x7f) { + this.sb.append((char)c); + } else if (c >= 0xc2 && c <= 0xdf) { + int c1 = this.index < this.endPos ? + ((int)this.bytes[this.index++]) & 0xff : -1; + if (c1 < 0x80 || c1 > 0xbf) { this.RaiseError("Invalid encoding"); } - break; + c = ((c - 0xc0) << 6) | (c1 - 0x80); + this.sb.append((char)c); + } else if (c >= 0xe0 && c <= 0xef) { + int c1 = this.index < this.endPos ? + ((int)this.bytes[this.index++]) & 0xff : -1; + int c2 = this.index < this.endPos ? + ((int)this.bytes[this.index++]) & 0xff : -1; + int lower = (c == 0xe0) ? 0xa0 : 0x80; + int upper = (c == 0xed) ? 0x9f : 0xbf; + if (c1 < lower || c1 > upper || c2 < 0x80 || c2 > 0xbf) { + this.RaiseError("Invalid encoding"); + } + c = ((c - 0xe0) << 12) | ((c1 - 0x80) << 6) | (c2 - 0x80); + this.sb.append((char)c); + } else if (c >= 0xf0 && c <= 0xf4) { + int c1 = this.index < this.endPos ? + ((int)this.bytes[this.index++]) & 0xff : -1; + int c2 = this.index < this.endPos ? + ((int)this.bytes[this.index++]) & 0xff : -1; + int c3 = this.index < this.endPos ? + ((int)this.bytes[this.index++]) & 0xff : -1; + int lower = (c == 0xf0) ? 0x90 : 0x80; + int upper = (c == 0xf4) ? 0x8f : 0xbf; + if (c1 < lower || c1 > upper || c2 < 0x80 || c2 > 0xbf || + c3 < 0x80 || c3 > 0xbf) { + this.RaiseError("Invalid encoding"); + } + c = ((c - 0xf0) << 18) | ((c1 - 0x80) << 12) | ((c2 - 0x80) << + 6) | (c3 - 0x80); + if (c <= 0xffff) { + { this.sb.append((char)c); + } + } else if (c <= 0x10ffff) { + this.sb.append((char)((((c - 0x10000) >> 10) & 0x3ff) | +0xd800)); + this.sb.append((char)(((c - 0x10000) & 0x3ff) | 0xdc00)); + } + } else { + this.RaiseError("Invalid encoding"); } + break; } } -} -finally { -try { if (ms != null) { ms.close(); } } catch (java.io.IOException ex) {} -} -} + } } private CBORObject NextJSONNegativeNumber( @@ -452,7 +337,7 @@ private CBORObject NextJSONValue( // The tokenizer already checked the String for invalid // surrogate pairs, so just call the CBORObject // constructor directly - obj = CBORObject.FromRawUtf8(this.NextJSONString()); + obj = CBORObject.FromRaw(this.NextJSONString()); nextChar[0] = this.SkipWhitespaceJSON(); return obj; } @@ -471,9 +356,9 @@ private CBORObject NextJSONValue( case 't': { // Parse true if (this.endPos - this.index <= 2 || - this.bytes[this.index] != (byte)0x72 || - this.bytes[this.index + 1] != (byte)0x75 || - this.bytes[this.index + 2] != (byte)0x65) { + (((int)this.bytes[this.index]) & 0xFF) != 'r' || + (((int)this.bytes[this.index + 1]) & 0xFF) != 'u' || + (((int)this.bytes[this.index + 2]) & 0xFF) != 'e') { this.RaiseError("Value can't be parsed."); } this.index += 3; @@ -483,10 +368,10 @@ private CBORObject NextJSONValue( case 'f': { // Parse false if (this.endPos - this.index <= 3 || - this.bytes[this.index] != (byte)0x61 || - this.bytes[this.index + 1] != (byte)0x6c || - this.bytes[this.index + 2] != (byte)0x73 || - this.bytes[this.index + 3] != (byte)0x65) { + (((int)this.bytes[this.index]) & 0xFF) != 'a' || + (((int)this.bytes[this.index + 1]) & 0xFF) != 'l' || + (((int)this.bytes[this.index + 2]) & 0xFF) != 's' || + (((int)this.bytes[this.index + 3]) & 0xFF) != 'e') { this.RaiseError("Value can't be parsed."); } this.index += 4; @@ -496,9 +381,9 @@ private CBORObject NextJSONValue( case 'n': { // Parse null if (this.endPos - this.index <= 2 || - this.bytes[this.index] != (byte)0x75 || - this.bytes[this.index + 1] != (byte)0x6c || - this.bytes[this.index + 2] != (byte)0x6c) { + (((int)this.bytes[this.index]) & 0xFF) != 'u' || + (((int)this.bytes[this.index + 1]) & 0xFF) != 'l' || + (((int)this.bytes[this.index + 2]) & 0xFF) != 'l') { this.RaiseError("Value can't be parsed."); } this.index += 3; @@ -530,7 +415,8 @@ private CBORObject NextJSONValue( } public CBORJson2(byte[] bytes, int index, int endPos, JSONOptions - options) { +options) { + this.sb = null; this.bytes = bytes; this.index = index; this.endPos = endPos; @@ -588,7 +474,7 @@ private CBORObject ParseJSONObject(int depth) { CBORObject obj; int[] nextchar = new int[1]; boolean seenComma = false; - TreeMap myHashMap = new TreeMap(); + HashMap myHashMap = new HashMap(); while (true) { c = this.SkipWhitespaceJSON(); switch (c) { @@ -616,7 +502,7 @@ private CBORObject ParseJSONObject(int depth) { // The tokenizer already checked the String for invalid // surrogate pairs, so just call the CBORObject // constructor directly - obj = CBORObject.FromRawUtf8(this.NextJSONString()); + obj = CBORObject.FromRaw(this.NextJSONString()); key = obj; if (!this.options.getAllowDuplicateKeys() && myHashMap.containsKey(obj)) { diff --git a/src/main/java/com/upokecenter/cbor/CBORJson3.java b/src/main/java/com/upokecenter/cbor/CBORJson3.java index 430b81b7..157a71be 100644 --- a/src/main/java/com/upokecenter/cbor/CBORJson3.java +++ b/src/main/java/com/upokecenter/cbor/CBORJson3.java @@ -40,41 +40,17 @@ void RaiseError(String str) { private String NextJSONString() { int c; - int startIndex = this.index; - int endIndex = -1; - int ep = this.endPos; - String js = this.jstring; - int idx = this.index; - while (true) { - c = idx < ep ? ((int)js.charAt(idx++)) & 0xffff : -1; - if (c == -1 || c < 0x20) { - this.index = idx; - this.RaiseError("Unterminated String"); - } else if (c == '"') { - int iend = idx - 1; - this.index = idx; - return js.substring( - startIndex, ( - startIndex)+(iend - startIndex)); - } else if (c == '\\' || (c & 0xf800) == 0xd800) { - this.index = idx - 1; - endIndex = this.index; - break; - } - } this.sb = (this.sb == null) ? (new StringBuilder()) : this.sb; this.sb.delete(0, this.sb.length()); - this.sb.append(js, startIndex, (startIndex)+(endIndex - startIndex)); while (true) { - c = this.index < ep ? ((int)js.charAt(this.index++)) & + c = this.index < this.endPos ? ((int)this.jstring.charAt(this.index++)) & 0xffff : -1; if (c == -1 || c < 0x20) { this.RaiseError("Unterminated String"); } switch (c) { case '\\': - endIndex = this.index - 1; - c = this.index < ep ? ((int)js.charAt(this.index++)) & + c = this.index < this.endPos ? ((int)this.jstring.charAt(this.index++)) & 0xffff : -1; switch (c) { case '\\': @@ -102,8 +78,8 @@ private String NextJSONString() { c = 0; // Consists of 4 hex digits for (int i = 0; i < 4; ++i) { - int ch = this.index < ep ? - ((int)js.charAt(this.index++)) : -1; + int ch = this.index < this.endPos ? + ((int)this.jstring.charAt(this.index++)) : -1; if (ch >= '0' && ch <= '9') { c <<= 4; c |= ch - '0'; @@ -122,15 +98,16 @@ private String NextJSONString() { // Non-surrogate this.sb.append((char)c); } else if ((c & 0xfc00) == 0xd800) { - int ch = this.index < ep ? ((int)js.charAt(this.index++)) : -1; - if (ch != '\\' || (this.index < ep ? - ((int)js.charAt(this.index++)) : -1) != 'u') { + int ch = this.index < this.endPos ? + ((int)this.jstring.charAt(this.index++)) : -1; + if (ch != '\\' || (this.index < this.endPos ? + ((int)this.jstring.charAt(this.index++)) : -1) != 'u') { this.RaiseError("Invalid escaped character"); } int c2 = 0; for (int i = 0; i < 4; ++i) { - ch = this.index < ep ? - ((int)js.charAt(this.index++)) : -1; + ch = this.index < this.endPos ? + ((int)this.jstring.charAt(this.index++)) : -1; if (ch >= '0' && ch <= '9') { c2 <<= 4; c2 |= ch - '0'; @@ -169,11 +146,11 @@ private String NextJSONString() { if ((c & 0xf800) != 0xd800) { // Non-surrogate this.sb.append((char)c); - } else if ((c & 0xfc00) == 0xd800 && this.index < ep && - (js.charAt(this.index) & 0xfc00) == 0xdc00) { + } else if ((c & 0xfc00) == 0xd800 && this.index < this.endPos && + (this.jstring.charAt(this.index) & 0xfc00) == 0xdc00) { // Surrogate pair this.sb.append((char)c); - this.sb.append(js.charAt(this.index)); + this.sb.append(this.jstring.charAt(this.index)); ++this.index; } else { this.RaiseError("Unpaired surrogate code point"); @@ -201,15 +178,15 @@ private CBORObject NextJSONNegativeNumber( if (c2 == ',' || c2 == ']' || c2 == '}') { ++this.index; obj = CBORDataUtilities.ParseSmallNumberAsNegative( - c - '0', - this.options); + c - '0', + this.options); nextChar[0] = c2; return obj; } else if (c2 == 0x20 || c2 == 0x0a || c2 == 0x0d || c2 == 0x09) { ++this.index; obj = CBORDataUtilities.ParseSmallNumberAsNegative( - c - '0', - this.options); + c - '0', + this.options); nextChar[0] = this.SkipWhitespaceJSON(); return obj; } @@ -220,14 +197,14 @@ private CBORObject NextJSONNegativeNumber( int[] endIndex = new int[1]; endIndex[0] = numberStartIndex; obj = CBORDataUtilities.ParseJSONNumber( - this.jstring, - numberStartIndex, - this.endPos - numberStartIndex, - this.options, - endIndex); + this.jstring, + numberStartIndex, + this.endPos - numberStartIndex, + this.options, + endIndex); int numberEndIndex = endIndex[0]; this.index = numberEndIndex >= this.endPos ? this.endPos : - (numberEndIndex + 1); + (numberEndIndex + 1); if (obj == null) { int strlen = numberEndIndex - numberStartIndex; String errstr = this.jstring.substring(numberStartIndex, (numberStartIndex)+(Math.min(100, strlen))); @@ -237,10 +214,11 @@ private CBORObject NextJSONNegativeNumber( this.RaiseError("JSON number can't be parsed. " + errstr); } - c = numberEndIndex >= this.endPos ? -1 : this.jstring.charAt(numberEndIndex); + c = numberEndIndex >= this.endPos ? -1 : +this.jstring.charAt(numberEndIndex); // check if character can validly appear after a JSON number if (c != ',' && c != ']' && c != '}' && c != -1 && - c != 0x20 && c != 0x0a && c != 0x0d && c != 0x09) { + c != 0x20 && c != 0x0a && c != 0x0d && c != 0x09) { this.RaiseError("Invalid character after JSON number"); } // System.out.println("endIndex="+endIndex[0]+", "+ @@ -307,14 +285,14 @@ private CBORObject NextJSONNonnegativeNumber(int c, int[] nextChar) { int[] endIndex = new int[1]; endIndex[0] = numberStartIndex; obj = CBORDataUtilities.ParseJSONNumber( - this.jstring, - numberStartIndex, - this.endPos - numberStartIndex, - this.options, - endIndex); + this.jstring, + numberStartIndex, + this.endPos - numberStartIndex, + this.options, + endIndex); int numberEndIndex = endIndex[0]; this.index = numberEndIndex >= this.endPos ? this.endPos : - (numberEndIndex + 1); + (numberEndIndex + 1); if (obj == null) { int strlen = numberEndIndex - numberStartIndex; String errstr = this.jstring.substring(numberStartIndex, (numberStartIndex)+(Math.min(100, strlen))); @@ -324,7 +302,8 @@ private CBORObject NextJSONNonnegativeNumber(int c, int[] nextChar) { this.RaiseError("JSON number can't be parsed. " + errstr); } - c = numberEndIndex >= this.endPos ? -1 : this.jstring.charAt(numberEndIndex); + c = numberEndIndex >= this.endPos ? -1 : +this.jstring.charAt(numberEndIndex); // check if character can validly appear after a JSON number if (c != ',' && c != ']' && c != '}' && c != -1 && c != 0x20 && c != 0x0a && c != 0x0d && c != 0x09) { @@ -493,7 +472,7 @@ private CBORObject ParseJSONObject(int depth) { CBORObject obj; int[] nextchar = new int[1]; boolean seenComma = false; - TreeMap myHashMap = new TreeMap(); + HashMap myHashMap = new HashMap(); while (true) { c = this.SkipWhitespaceJSON(); switch (c) { diff --git a/src/main/java/com/upokecenter/cbor/CBORJsonWriter.java b/src/main/java/com/upokecenter/cbor/CBORJsonWriter.java index ffab4138..79d2b8b1 100644 --- a/src/main/java/com/upokecenter/cbor/CBORJsonWriter.java +++ b/src/main/java/com/upokecenter/cbor/CBORJsonWriter.java @@ -13,21 +13,14 @@ static void WriteJSONStringUnquoted( String str, StringOutput sb, JSONOptions options) throws java.io.IOException { - int i = 0; - for (; i < str.length(); ++i) { - char c = str.charAt(i); - if (c < 0x20 || c >= 0x7f || c == '\\' || c == '"') { - sb.WriteString(str, 0, i); - break; - } - } - if (i == str.length()) { - sb.WriteString(str, 0, i); - return; - } - for (; i < str.length(); ++i) { + boolean first = true; + for (int i = 0; i < str.length(); ++i) { char c = str.charAt(i); if (c == '\\' || c == '"') { + if (first) { + first = false; + sb.WriteString(str, 0, i); + } sb.WriteCodePoint((int)'\\'); sb.WriteCodePoint((int)c); } else if (c < 0x20 || (c >= 0x7f && (c == 0x2028 || c == 0x2029 || @@ -36,6 +29,10 @@ static void WriteJSONStringUnquoted( // Control characters, and also the line and paragraph separators // which apparently can't appear in JavaScript (as opposed to // JSON) strings + if (first) { + first = false; + sb.WriteString(str, 0, i); + } if (c == 0x0d) { sb.WriteString("\\r"); } else if (c == 0x0a) { @@ -59,25 +56,37 @@ static void WriteJSONStringUnquoted( sb.WriteCodePoint((int)Hex16.charAt((int)(c >> 4))); sb.WriteCodePoint((int)Hex16.charAt((int)(c & 15))); } - } else if ((c & 0xfc00) == 0xd800) { + } else { + if ((c & 0xfc00) == 0xd800) { if (i >= str.length() - 1 || (str.charAt(i + 1) & 0xfc00) != 0xdc00) { // NOTE: RFC 8259 doesn't prohibit any particular // error-handling behavior when a writer of JSON // receives a String with an unpaired surrogate. if (options.getReplaceSurrogates()) { + if (first) { + first = false; + sb.WriteString(str, 0, i); + } // Replace unpaired surrogate with U+FFFD - sb.WriteCodePoint(0xfffd); + c = (char)0xfffd; } else { throw new CBORException("Unpaired surrogate in String"); } - } else { + } + } + if (!first) { + if ((c & 0xfc00) == 0xd800) { sb.WriteString(str, i, 2); ++i; + } else { + sb.WriteCodePoint((int)c); } - } else { - sb.WriteCodePoint((int)c); + } } } + if (first) { + sb.WriteString(str); + } } static void WriteJSONToInternal( diff --git a/src/main/java/com/upokecenter/cbor/CBORObject.java b/src/main/java/com/upokecenter/cbor/CBORObject.java index 67077e51..61ffdc0a 100644 --- a/src/main/java/com/upokecenter/cbor/CBORObject.java +++ b/src/main/java/com/upokecenter/cbor/CBORObject.java @@ -105,7 +105,8 @@ private static CBORObject ConstructIntegerValue(int v) { /** * A not-a-number value. */ - public static final CBORObject NaN = CBORObject.FromObject(Double.NaN); + public static final CBORObject NaN = +CBORObject.FromObject(Double.NaN); /** * The value negative infinity. @@ -155,7 +156,6 @@ private static CBORObject ConstructIntegerValue(int v) { private static final int CBORObjectTypeTagged = 6; private static final int CBORObjectTypeSimpleValue = 7; private static final int CBORObjectTypeDouble = 8; - private static final int CBORObjectTypeTextStringUtf8 = 9; private static final int StreamedStringBufferLength = 4096; @@ -249,8 +249,8 @@ public final EInteger getMostInnerTag() { return EInteger.FromInt64(previtem.tagLow); } return LowHighToEInteger( - previtem.tagLow, - previtem.tagHigh); + previtem.tagLow, + previtem.tagHigh); } /** @@ -397,8 +397,8 @@ public final EInteger getMostOuterTag() { return EInteger.FromInt32(this.tagLow); } return LowHighToEInteger( - this.tagLow, - this.tagHigh); + this.tagLow, + this.tagHigh); } /** @@ -408,8 +408,8 @@ public final EInteger getMostOuterTag() { * @throws IllegalStateException This object does not represent a number, or * this object is a not-a-number (NaN) value. * @deprecated Instead, convert this object to a number with.AsNumber(), \u0020 and use the - * Sign property in.NET or the signum method in\u0020Java. Either will - * treat not-a-number (NaN) values differently than here. + * Sign property in.NET or the signum method in Java. Either will treat + * not-a-number (NaN) values differently than here. */ @Deprecated public final int signum() { @@ -467,9 +467,9 @@ public final CBORType getType() { case CBORObjectTypeByteString: return CBORType.ByteString; case CBORObjectTypeTextString: - case CBORObjectTypeTextStringUtf8: return CBORType.TextString; - default: throw new IllegalStateException("Unexpected data type"); + default: + throw new IllegalStateException("Unexpected data type"); } } @@ -1001,7 +1001,7 @@ public static CBORObject[] FromJSONSequenceBytes(byte[] data, /** * Generates a CBOR object from an array of CBOR-encoded bytes, using the given * CBOREncodeOptions object to control the decoding process.

    - *

    The following example (originally written in C# for the.getNET() + *

    The following example (originally written in C# for the.NET * version) implements a method that decodes a text string from a CBOR * byte array. It's successful only if the CBOR object contains an * untagged text string.

    private static string DecodeTextString(byte[] bytes) { if (bytes == null) { throw new NullPointerException("mapObj");} if (bytes.length == 0 || bytes[0]<0x60 || bytes[0]>0x7f) {throw new CBORException();} return CBORObject.DecodeFromBytes(bytes, CBOREncodeOptions.Default).AsString(); }
    .

    @@ -1166,7 +1166,7 @@ public static CBORObject FromJSONString( throw new NullPointerException("jsonoptions"); } return FromJSONString(str, 0, str.length(), jsonoptions); - } + } /** *

    Generates a CBOR object from a text string in JavaScript object Notation @@ -1414,7 +1414,7 @@ public T ToObject(java.lang.reflect.Type t, PODOptions options) { * the same rules as for long are used, but the range is from 0 * through 2^63-1 and the return type is ulong .

  • If the * type is int or a primitive floating-point type (float - * , double , as well as decimal in.getNET()), returns the + * , double , as well as decimal in.NET), returns the * result of the corresponding As* method.
  • If the type is * string , returns the result of AsString.
  • If the type * is EFloat , EDecimal , EInteger , or @@ -1643,11 +1643,11 @@ T ToObject(java.lang.reflect.Type t, * @return A CBOR object. */ public static CBORObject FromObject(long value) { - if (value >= 0L && value < 24L) { - return FixedObjects[(int)value]; - } else { - return (value >= -24L && value < 0L) ? FixedObjects[0x20 - (int)(value + - 1L)] : new CBORObject(CBORObjectTypeInteger, value); +if (value >= 0L && value < 24L) { + return FixedObjects[(int)value]; +} else { + return (value >= -24L && value < 0L) ? FixedObjects[0x20 - (int)(value + +1L)] : new CBORObject(CBORObjectTypeInteger, value); } } @@ -1689,22 +1689,21 @@ private static int IntegerByteLength(long longValue) { } } - /** - * Calculates the number of bytes this CBOR object takes when serialized as a - * byte array using the EncodeToBytes() method. This calculation - * assumes that integers, lengths of maps and arrays, lengths of text - * and byte strings, and tag numbers are encoded in their shortest - * form; that floating-point numbers are encoded in their shortest - * value-preserving form; and that no indefinite-length encodings are - * used. - * @return The number of bytes this CBOR object takes when serialized as a byte - * array using the {@code EncodeToBytes()} method. - * @throws com.upokecenter.cbor.CBORException The CBOR object has an extremely - * deep level of nesting, including if the CBOR object is or has an - * array or map that includes itself. - */ + /** + * Calculates the number of bytes this CBOR object takes when serialized as a + * byte array using the EncodeToBytes() method. This calculation + * assumes that integers, lengths of maps and arrays, lengths of text and + * byte strings, and tag numbers are encoded in their shortest form; that + * floating-point numbers are encoded in their shortest value-preserving + * form; and that no indefinite-length encodings are used. + * @return The number of bytes this CBOR object takes when serialized as a byte + * array using the {@code EncodeToBytes()} method. + * @throws com.upokecenter.cbor.CBORException The CBOR object has an extremely + * deep level of nesting, including if the CBOR object is or has an array + * or map that includes itself. + */ public long CalcEncodedSize() { - return this.CalcEncodedSize(0); + return this.CalcEncodedSize(0); } private long CalcEncodedSize(int depth) { @@ -1723,11 +1722,6 @@ private long CalcEncodedSize(int depth) { } cbor = cbor.UntagOne(); } - if (cbor.getItemType() == CBORObjectTypeTextStringUtf8) { - byte[] bytes = (byte[])this.getThisItem(); - size = (size + IntegerByteLength(bytes.length)); - return size + bytes.length; - } switch (cbor.getType()) { case Integer: { if (cbor.CanValueFitInInt64()) { @@ -1745,7 +1739,7 @@ private long CalcEncodedSize(int depth) { return size + 3; } return CBORUtilities.DoubleRetainsSameValueInSingle(valueBits) ? - (size + 5) : (size + 9); +(size + 5) : (size + 9); } case Array: size = (size + IntegerByteLength(cbor.size())); @@ -1756,7 +1750,7 @@ private long CalcEncodedSize(int depth) { return size; case Map: { Collection> entries = - this.getEntries(); + this.getEntries(); size = (size + IntegerByteLength(entries.size())); for (Map.Entry entry : entries) { CBORObject key = entry.getKey(); @@ -1850,27 +1844,23 @@ public static CBORObject FromObject(EFloat bigValue) { if (bigValue.IsSignalingNaN()) { options += 6; } - cbor = CBORObject.NewArray( - CBORObject.FromObject(bigValue.getExponent()), - CBORObject.FromObject(bigValue.getUnsignedMantissa()), - CBORObject.FromObject(options)); + cbor = CBORObject.NewArray().Add(bigValue.getExponent()) + .Add(bigValue.getUnsignedMantissa()).Add(options); tag = 269; } else { EInteger exponent = bigValue.getExponent(); if (exponent.CanFitInInt64()) { tag = 5; - cbor = CBORObject.NewArray( - CBORObject.FromObject(exponent.ToInt64Checked()), - CBORObject.FromObject(bigValue.getMantissa())); - } else { - tag = (exponent.GetSignedBitLengthAsInt64() > 64) ? + cbor = CBORObject.NewArray() + .Add(exponent.ToInt64Checked()).Add(bigValue.getMantissa()); + } else { + tag = (exponent.GetSignedBitLengthAsEInteger().compareTo(64) > 0) ? 265 : 5; - cbor = CBORObject.NewArray( - CBORObject.FromObject(exponent), - CBORObject.FromObject(bigValue.getMantissa())); + cbor = CBORObject.NewArray() + .Add(exponent).Add(bigValue.getMantissa()); } } - return cbor.WithTag(tag); + return CBORObject.FromObjectAndTag(cbor, tag); } /** @@ -1904,18 +1894,15 @@ public static CBORObject FromObject(ERational bigValue) { options += 6; } - cbor = CBORObject.NewArray( - FromObject(bigValue.getUnsignedNumerator()), - FromObject(bigValue.getDenominator()), - FromObject(options)); + cbor = CBORObject.NewArray().Add(bigValue.getUnsignedNumerator()) + .Add(bigValue.getDenominator()).Add(options); tag = 270; } else { tag = 30; - cbor = CBORObject.NewArray( - CBORObject.FromObject(bigValue.getNumerator()), - CBORObject.FromObject(bigValue.getDenominator())); + cbor = CBORObject.NewArray() + .Add(bigValue.getNumerator()).Add(bigValue.getDenominator()); } - return cbor.WithTag(tag); + return CBORObject.FromObjectAndTag(cbor, tag); } /** @@ -1950,27 +1937,23 @@ public static CBORObject FromObject(EDecimal bigValue) { if (bigValue.IsSignalingNaN()) { options += 6; } - cbor = CBORObject.NewArray( - FromObject(bigValue.getExponent()), - FromObject(bigValue.getUnsignedMantissa()), - FromObject(options)); + cbor = CBORObject.NewArray().Add(bigValue.getExponent()) + .Add(bigValue.getUnsignedMantissa()).Add(options); tag = 268; } else { EInteger exponent = bigValue.getExponent(); if (exponent.CanFitInInt64()) { tag = 4; - cbor = CBORObject.NewArray( - CBORObject.FromObject(exponent.ToInt64Checked()), - CBORObject.FromObject(bigValue.getMantissa())); - } else { - tag = (exponent.GetSignedBitLengthAsInt64() > 64) ? + cbor = CBORObject.NewArray() + .Add(exponent.ToInt64Checked()).Add(bigValue.getMantissa()); + } else { + tag = (exponent.GetSignedBitLengthAsEInteger().compareTo(64) > 0) ? 264 : 4; - cbor = CBORObject.NewArray( - CBORObject.FromObject(exponent), - CBORObject.FromObject(bigValue.getMantissa())); + cbor = CBORObject.NewArray() + .Add(exponent).Add(bigValue.getMantissa()); } } - return cbor.WithTag(tag); + return CBORObject.FromObjectAndTag(cbor, tag); } /** @@ -1985,9 +1968,6 @@ public static CBORObject FromObject(String strValue) { if (strValue == null) { return CBORObject.Null; } - if (strValue.length() == 0) { - return GetFixedObject(0x60); - } if (DataUtilities.GetUtf8Length(strValue, false) < 0) { throw new IllegalArgumentException("String contains an unpaired " + "surrogate code point."); @@ -2001,12 +1981,12 @@ public static CBORObject FromObject(String strValue) { * @return A CBOR object. */ public static CBORObject FromObject(int value) { - if (value >= 0 && value < 24) { - return FixedObjects[value]; - } else { - return (value >= -24 && value < 0) ? FixedObjects[0x20 - (value + 1)] : - FromObject((long)value); - } +if (value >= 0 && value < 24) { + return FixedObjects[value]; +} else { + return (value >= -24 && value < 0) ? FixedObjects[0x20 - (value + 1)] : +FromObject((long)value); +} } /** @@ -2015,12 +1995,12 @@ public static CBORObject FromObject(int value) { * @return A CBOR object generated from the given integer. */ public static CBORObject FromObject(short value) { - if (value >= 0 && value < 24) { - return FixedObjects[value]; - } else { - return (value >= -24 && value < 0) ? FixedObjects[0x20 - (value + 1)] : - FromObject((long)value); - } +if (value >= 0 && value < 24) { + return FixedObjects[value]; +} else { + return (value >= -24 && value < 0) ? FixedObjects[0x20 - (value + 1)] : +FromObject((long)value); +} } /** @@ -2090,12 +2070,11 @@ public static CBORObject FromObject(CBORObject[] array) { if (array == null) { return CBORObject.Null; } - List list = new ArrayList(array.length == - Integer.MAX_VALUE ? array.length : (array.length + 1)); - for (CBORObject cbor : array) { - list.add(cbor); + CBORObject cbor = CBORObject.NewArray(); + for (CBORObject i : array) { + cbor.Add(i); } - return new CBORObject(CBORObjectTypeArray, list); + return cbor; } /** @@ -2108,8 +2087,7 @@ public static CBORObject FromObject(int[] array) { if (array == null) { return CBORObject.Null; } - List list = new ArrayList(array.length == - Integer.MAX_VALUE ? array.length : (array.length + 1)); + List list = new ArrayList(); for (int i : array) { list.add(FromObject(i)); } @@ -2126,8 +2104,7 @@ public static CBORObject FromObject(long[] array) { if (array == null) { return CBORObject.Null; } - List list = new ArrayList(array.length == - Integer.MAX_VALUE ? array.length : (array.length + 1)); + List list = new ArrayList(); for (long i : array) { list.add(FromObject(i)); } @@ -2225,9 +2202,9 @@ public static CBORObject FromObject( * byte is converted to a CBOR integer from 0 through 255.
  • *
  • A primitive integer type (int, short, * long, as well as sbyte, ushort, uint , - * and ulong in.getNET()) is converted to the corresponding CBOR + * and ulong in.NET) is converted to the corresponding CBOR * integer.
  • A primitive floating-point type (float, - * double, as well as decimal in.getNET()) is converted to the + * double, as well as decimal in.NET) is converted to the * corresponding CBOR number.
  • A string is converted to * a CBOR text string. To create a CBOR byte string object from * string, see the example given in kvp = (Map.Entry)keyPair; CBORObject objKey = CBORObject.FromObject( - kvp.getKey(), - options, - mapper, - depth + 1); + kvp.getKey(), + options, + mapper, + depth + 1); objret.set(objKey, CBORObject.FromObject( - kvp.getValue(), - options, - mapper, - depth + 1)); + kvp.getValue(), + options, + mapper, + depth + 1)); } return objret; } @@ -2450,10 +2427,10 @@ static CBORObject FromObject( obj, options.getUseCamelCase())) { objret.set(key.getKey(), CBORObject.FromObject( - key.getValue(), - options, - mapper, - depth + 1)); + key.getValue(), + options, + mapper, + depth + 1)); } return objret; } @@ -2475,34 +2452,7 @@ static CBORObject FromObject( * @throws NullPointerException The parameter {@code bigintTag} is null. */ public CBORObject WithTag(EInteger bigintTag) { - if (bigintTag == null) { - throw new NullPointerException("bigintTag"); - } - if (bigintTag.signum() < 0) { - throw new IllegalArgumentException("tagEInt's sign(" + bigintTag.signum() + - ") is less than 0"); - } - if (bigintTag.CanFitInInt32()) { - // Low-numbered, commonly used tags - return this.WithTag(bigintTag.ToInt32Checked()); - } else { - if (bigintTag.compareTo(UInt64MaxValue) > 0) { - throw new IllegalArgumentException( - "tag more than 18446744073709551615 (" + bigintTag + ")"); - } - int tagLow = 0; - int tagHigh = 0; - byte[] bytes = bigintTag.ToBytes(true); - for (int i = 0; i < Math.min(4, bytes.length); ++i) { - int b = ((int)bytes[i]) & 0xff; - tagLow = (tagLow | (((int)b) << (i * 8))); - } - for (int i = 4; i < Math.min(8, bytes.length); ++i) { - int b = ((int)bytes[i]) & 0xff; - tagHigh = (tagHigh | (((int)b) << (i * 8))); - } - return new CBORObject(this, tagLow, tagHigh); - } + return FromObjectAndTag(this, bigintTag); } /** @@ -2544,7 +2494,25 @@ public static CBORObject FromObjectAndTag( throw new IllegalArgumentException( "tag more than 18446744073709551615 (" + bigintTag + ")"); } - return FromObject(valueOb).WithTag(bigintTag); + CBORObject c = FromObject(valueOb); + if (bigintTag.CanFitInInt32()) { + // Low-numbered, commonly used tags + return FromObjectAndTag(c, bigintTag.ToInt32Checked()); + } else { + int tagLow = 0; + int tagHigh = 0; + byte[] bytes = bigintTag.ToBytes(true); + for (int i = 0; i < Math.min(4, bytes.length); ++i) { + int b = ((int)bytes[i]) & 0xff; + tagLow = (tagLow | (((int)b) << (i * 8))); + } + for (int i = 4; i < Math.min(8, bytes.length); ++i) { + int b = ((int)bytes[i]) & 0xff; + tagHigh = (tagHigh | (((int)b) << (i * 8))); + } + CBORObject c2 = new CBORObject(c, tagLow, tagHigh); + return c2; + } } /** @@ -2563,11 +2531,7 @@ public static CBORObject FromObjectAndTag( * @throws IllegalArgumentException The parameter {@code smallTag} is less than 0. */ public CBORObject WithTag(int smallTag) { - if (smallTag < 0) { - throw new IllegalArgumentException("smallTag(" + smallTag + - ") is less than 0"); - } - return new CBORObject(this, smallTag, 0); + return FromObjectAndTag(this, smallTag); } /** @@ -2601,7 +2565,9 @@ public static CBORObject FromObjectAndTag( throw new IllegalArgumentException("smallTag(" + smallTag + ") is less than 0"); } - return FromObject(valueObValue).WithTag(smallTag); + CBORObject c = FromObject(valueObValue); + c = new CBORObject(c, smallTag, 0); + return c; } /** @@ -2629,8 +2595,8 @@ public static CBORObject FromSimpleValue(int simpleValue) { return FixedObjects[0xe0 + simpleValue]; } return new CBORObject( - CBORObjectTypeSimpleValue, - simpleValue); + CBORObjectTypeSimpleValue, + simpleValue); } /** @@ -2674,24 +2640,6 @@ public static CBORObject NewArray() { return new CBORObject(CBORObjectTypeArray, new ArrayList()); } - static CBORObject NewArray(CBORObject o1, CBORObject o2) { - ArrayList list = new ArrayList(2); - list.add(o1); - list.add(o2); - return new CBORObject(CBORObjectTypeArray, list); - } - - static CBORObject NewArray( - CBORObject o1, - CBORObject o2, - CBORObject o3) { - ArrayList list = new ArrayList(2); - list.add(o1); - list.add(o2); - list.add(o3); - return new CBORObject(CBORObjectTypeArray, list); - } - /** * Creates a new empty CBOR map. * @return A new CBOR map. @@ -2699,7 +2647,7 @@ static CBORObject NewArray( public static CBORObject NewMap() { return new CBORObject( CBORObjectTypeMap, - new TreeMap()); + new HashMap()); } /** @@ -2927,7 +2875,7 @@ public static CBORObject ReadJSON( * does not begin with a record separator byte (0x1e). */ public static CBORObject[] ReadJSONSequence(InputStream stream, JSONOptions - jsonoptions) throws java.io.IOException { +jsonoptions) throws java.io.IOException { if (stream == null) { throw new NullPointerException("stream"); } @@ -2940,9 +2888,9 @@ public static CBORObject[] ReadJSONSequence(InputStream stream, JSONOptions try { int[] nextchar = new int[1]; CBORObject[] objlist = CBORJson.ParseJSONSequence( - reader, - jsonoptions, - nextchar); + reader, + jsonoptions, + nextchar); if (nextchar[0] != -1) { reader.RaiseError("End of data stream not reached"); } @@ -2991,9 +2939,9 @@ public static CBORObject ReadJSON( try { int[] nextchar = new int[1]; CBORObject obj = CBORJson.ParseJSONValue( - reader, - jsonoptions, - nextchar); + reader, + jsonoptions, + nextchar); if (nextchar[0] != -1) { reader.RaiseError("End of data stream not reached"); } @@ -3097,7 +3045,7 @@ public static CBORObject FromJSONBytes( * length minus {@code offset} is less than {@code count}. */ public static CBORObject FromJSONBytes(byte[] bytes, int offset, int - count) { +count) { return FromJSONBytes(bytes, offset, count, JSONOptions.Default); } @@ -3147,35 +3095,35 @@ public static CBORObject FromJSONBytes( } if (offset < 0) { throw new IllegalArgumentException("offset (" + offset + ") is not greater" + - "\u0020or equal to 0"); +"\u0020or equal to 0"); } if (offset > bytes.length) { throw new IllegalArgumentException("offset (" + offset + ") is not less or" + - "\u0020equal to " + bytes.length); +"\u0020equal to " + bytes.length); } if (count < 0) { throw new IllegalArgumentException("count (" + count + ") is not greater or" + - "\u0020equal to 0"); +"\u0020equal to 0"); } if (count > bytes.length) { throw new IllegalArgumentException("count (" + count + ") is not less or" + - "\u0020equal to " + bytes.length); +"\u0020equal to " + bytes.length); } if (bytes.length - offset < count) { throw new IllegalArgumentException("bytes's length minus " + offset + " (" + - (bytes.length - offset) + ") is not greater or equal to " + count); +(bytes.length - offset) + ") is not greater or equal to " + count); } if (count == 0) { throw new CBORException("Byte array is empty"); } if (bytes[offset] >= 0x01 && bytes[offset] <= 0x7f && count >= 2 && - bytes[offset + 1] != 0) { +bytes[offset + 1] != 0) { // UTF-8 JSON bytes return CBORJson2.ParseJSONValue( - bytes, - offset, - offset + count, - jsonoptions); + bytes, + offset, + offset + count, + jsonoptions); } else { // Other than UTF-8 without byte order mark try { @@ -3334,7 +3282,7 @@ public static void Write(EFloat bignum, OutputStream stream) throws java.io.IOEx if (exponent.CanFitInInt64()) { stream.write(0xc5); // tag 5 stream.write(0x82); // array, length 2 - } else if (exponent.GetSignedBitLengthAsInt64() > 64) { + } else if (exponent.GetSignedBitLengthAsEInteger().compareTo(64) > 0) { stream.write(0xd9); // tag 265 stream.write(0x01); stream.write(0x09); @@ -3404,7 +3352,7 @@ public static void Write(EDecimal bignum, OutputStream stream) throws java.io.IO if (exponent.CanFitInInt64()) { stream.write(0xc4); // tag 4 stream.write(0x82); // array, length 2 - } else if (exponent.GetSignedBitLengthAsInt64() > 64) { + } else if (exponent.GetSignedBitLengthAsEInteger().compareTo(64) > 0) { stream.write(0xd9); // tag 264 stream.write(0x01); stream.write(0x08); @@ -4037,7 +3985,7 @@ public EDecimal AsEDecimal() { * @throws IllegalStateException This object does not represent a number (for * the purposes of this method, infinity and not-a-number values, but * not {@code CBORObject.Null}, are considered numbers). - * @deprecated Instead, use.getToObject()&lt;PeterO.Numbers.EFloat&gt;\u0028) in.getNET() + * @deprecated Instead, use.getToObject()&lt;PeterO.Numbers.EFloat&gt;\u0028) in.NET * or \u0020.getToObject()\u0028com.upokecenter.numbers.EFloat.class) * in\u0020Java. */ @@ -4071,8 +4019,8 @@ public ERational AsERational() { * CBORObject.Null, are considered numbers). * @throws ArithmeticException This object's value exceeds the range of a 16-bit * signed integer. - * @deprecated Instead, use the following:\u0020\u0028cbor.AsNumber().ToInt16Checked()), - * or\u0020.getToObject()&lt;short&gt;() in\u0020.getNET(). + * @deprecated Instead, use the following:\u0020\u0028cbor.AsNumber().ToInt16Checked()), or + *.ToObject&lt;short&gt;() in\u0020.NET. */ @Deprecated public short AsInt16() { @@ -4291,7 +4239,7 @@ public int AsInt32() { * @throws ArithmeticException This object's value exceeds the range of a 64-bit * signed integer. * @deprecated Instead, use the following:\u0020\u0028cbor.AsNumber().ToInt64Checked()), or - *.ToObject&lt;long&gt;()\u0020in.getNET(). + *.ToObject&lt;long&gt;() in.NET. */ @Deprecated public long AsInt64() { @@ -4329,11 +4277,7 @@ public String AsString() { case CBORObjectTypeTextString: { return (String)this.getThisItem(); } - case CBORObjectTypeTextStringUtf8: { - return DataUtilities.GetUtf8String((byte[])this.getThisItem(), false); - } - default: - throw new IllegalStateException("Not a text String type"); + default: throw new IllegalStateException("Not a text String type"); } } @@ -4419,7 +4363,7 @@ public boolean CanFitInSingle() { * discarding its fractional part, would be -(2^31) or greater, and * less than 2^31; otherwise, {@code false}. * @deprecated Instead, use the following: \u0028cbor.CanValueFitInInt32()\u0020if only - * integers of any tag are allowed, or\u0020\u0028cbor.isNumber() + * integers of any tag are allowed, or \u0028cbor.isNumber() * &&\u0020cbor.AsNumber().CanTruncatedIntFitInInt32()). */ @Deprecated @@ -4437,7 +4381,7 @@ public boolean CanTruncatedIntFitInInt32() { * discarding its fractional part, would be -(2^63) or greater, and * less than 2^63; otherwise, {@code false}. * @deprecated Instead, use the following: \u0028cbor.CanValueFitInInt64()\u0020if only - * integers of any tag are allowed, or\u0020\u0028cbor.isNumber() + * integers of any tag are allowed, or \u0028cbor.isNumber() * &&\u0020cbor.AsNumber().CanTruncatedIntFitInInt64()). */ @Deprecated @@ -4517,8 +4461,7 @@ public int compareTo(CBORObject other) { other.EncodeToBytes()); break; } - case CBORObjectTypeByteString: - case CBORObjectTypeTextStringUtf8: { + case CBORObjectTypeByteString: { cmp = CBORUtilities.ByteArrayCompareLengthFirst((byte[])objA, (byte[])objB); break; @@ -4529,6 +4472,11 @@ public int compareTo(CBORObject other) { cmp = CBORUtilities.CompareStringsAsUtf8LengthFirst( strA, strB); + if (cmp < -1) { + cmp = CBORUtilities.ByteArrayCompare( + this.EncodeToBytes(), + other.EncodeToBytes()); + } break; } case CBORObjectTypeArray: { @@ -4569,21 +4517,10 @@ public int compareTo(CBORObject other) { cmp = CBORUtilities.ByteArrayCompare( this.EncodeToBytes(), other.EncodeToBytes()); - } else if (typeB == CBORObjectTypeTextString && typeA == - CBORObjectTypeTextStringUtf8) { - cmp = -CBORUtilities.CompareUtf16Utf8LengthFirst( - (String)objB, - (byte[])objA); - } else if (typeA == CBORObjectTypeTextString && typeB == - CBORObjectTypeTextStringUtf8) { - cmp = CBORUtilities.CompareUtf16Utf8LengthFirst( - (String)objA, - (byte[])objB); } else { /* NOTE: itemtypeValue numbers are ordered such that they // correspond to the lexicographical order of their CBOR encodings - // (with the exception of Integer and EInteger together, - // and TextString and TextStringUtf8 together which + // (with the exception of Integer and EInteger together, which // are handled above) */ cmp = (typeA < typeB) ? -1 : 1; } @@ -4762,13 +4699,6 @@ public byte[] EncodeToBytes(CBOREncodeOptions options) { } break; } - case CBORObjectTypeTextStringUtf8: { - if (!tagged && !options.getUseIndefLengthStrings()) { - byte[] bytes = (byte[])this.getThisItem(); - return SerializeUtf8(bytes); - } - break; - } case CBORObjectTypeSimpleValue: { if (tagged) { byte[] simpleBytes = new byte[] { tagbyte, (byte)0xf4 }; @@ -4877,24 +4807,11 @@ public boolean equals(CBORObject other) { if (this == otherValue) { return true; } - if (this.itemtypeValue == CBORObjectTypeTextString && - otherValue.itemtypeValue == CBORObjectTypeTextStringUtf8) { - return CBORUtilities.StringEqualsUtf8( - (String)this.itemValue, - (byte[])otherValue.itemValue); - } - if (otherValue.itemtypeValue == CBORObjectTypeTextString && - this.itemtypeValue == CBORObjectTypeTextStringUtf8) { - return CBORUtilities.StringEqualsUtf8( - (String)otherValue.itemValue, - (byte[])this.itemValue); - } if (this.itemtypeValue != otherValue.itemtypeValue) { return false; } switch (this.itemtypeValue) { case CBORObjectTypeByteString: - case CBORObjectTypeTextStringUtf8: return CBORUtilities.ByteArrayEquals( (byte[])this.itemValue, ((otherValue.itemValue instanceof byte[]) ? (byte[])otherValue.itemValue : null)); @@ -4950,10 +4867,6 @@ public byte[] GetByteString() { itemHashCode = CBORUtilities.ByteArrayHashCode(this.GetByteString()); break; - case CBORObjectTypeTextStringUtf8: - itemHashCode = CBORUtilities.Utf8HashCode( - (byte[])this.itemValue); - break; case CBORObjectTypeMap: itemHashCode = CBORMapHashCode(this.AsMap()); break; @@ -4961,8 +4874,7 @@ public byte[] GetByteString() { itemHashCode = CBORArrayHashCode(this.AsList()); break; case CBORObjectTypeTextString: - itemHashCode = CBORUtilities.StringHashCode( - (String)this.itemValue); + itemHashCode = StringHashCode((String)this.itemValue); break; case CBORObjectTypeSimpleValue: itemHashCode = ((Integer)this.itemValue).intValue(); @@ -5097,7 +5009,8 @@ public boolean HasMostInnerTag(EInteger bigTagValue) { throw new IllegalArgumentException("bigTagValue(" + bigTagValue + ") is less than 0"); } - return (!this.isTagged()) ? false : this.getMostInnerTag().equals(bigTagValue); + return (!this.isTagged()) ? false : +this.getMostInnerTag().equals(bigTagValue); } /** @@ -5133,7 +5046,8 @@ public boolean HasMostOuterTag(EInteger bigTagValue) { throw new IllegalArgumentException("bigTagValue(" + bigTagValue + ") is less than 0"); } - return (!this.isTagged()) ? false : this.getMostOuterTag().equals(bigTagValue); + return (!this.isTagged()) ? false : +this.getMostOuterTag().equals(bigTagValue); } /** @@ -6008,7 +5922,8 @@ public static int WriteValue( return 1; } else if (value < 32) { throw new IllegalArgumentException("value is from 24 to 31 and major" + - "\u0020type" + "\u0020is 7"); +"\u0020type" + + "\u0020is 7"); } else { outputStream.write((byte)0xf8); outputStream.write((byte)value); @@ -6192,9 +6107,8 @@ public void WriteTo(OutputStream stream, CBOREncodeOptions options) throws java. Write((EInteger)this.getThisItem(), stream); break; } - case CBORObjectTypeByteString: - case CBORObjectTypeTextStringUtf8: { - byte[] arr = (byte[])this.getThisItem(); + case CBORObjectTypeByteString: { + byte[] arr = this.GetByteString(); WritePositiveInt( (this.getType() == CBORType.ByteString) ? 2 : 3, arr.length, @@ -6240,10 +6154,6 @@ static CBORObject FromRaw(byte[] bytes) { return new CBORObject(CBORObjectTypeByteString, bytes); } - static CBORObject FromRawUtf8(byte[] bytes) { - return new CBORObject(CBORObjectTypeTextStringUtf8, bytes); - } - static CBORObject FromRaw(String str) { return new CBORObject(CBORObjectTypeTextString, str); } @@ -6272,6 +6182,13 @@ static CBORObject GetFixedLengthObject( return fixedObj; } int majortype = firstbyte >> 5; + if (firstbyte >= 0x61 && firstbyte < 0x78) { + // text String length 1 to 23 + String s = GetOptimizedStringIfShortAscii(data, 0); + if (s != null) { + return new CBORObject(CBORObjectTypeTextString, s); + } + } if ((firstbyte & 0x1c) == 0x18) { // contains 1 to 8 extra bytes of additional information long uadditional = 0; @@ -6339,8 +6256,8 @@ static CBORObject GetFixedLengthObject( ((int)uadditional)); } return new CBORObject( - CBORObjectTypeDouble, - dblbits); + CBORObjectTypeDouble, + dblbits); } if (firstbyte == 0xf8) { if ((int)uadditional < 32) { @@ -6360,12 +6277,14 @@ static CBORObject GetFixedLengthObject( return new CBORObject(CBORObjectTypeByteString, ret); } if (majortype == 3) { // short text String - byte[] ret = new byte[firstbyte - 0x60]; - System.arraycopy(data, 1, ret, 0, firstbyte - 0x60); - if (!CBORUtilities.CheckUtf8(ret)) { - throw new CBORException("Invalid encoding"); - } - return new CBORObject(CBORObjectTypeTextStringUtf8, ret); + StringBuilder ret = new StringBuilder(firstbyte - 0x60); + DataUtilities.ReadUtf8FromBytes( + data, + 1, + firstbyte - 0x60, + ret, + false); + return new CBORObject(CBORObjectTypeTextString, ret.toString()); } if (firstbyte == 0x80) { // empty array @@ -6431,6 +6350,21 @@ private static int CBORArrayHashCode(List list) { return ret; } + private static int StringHashCode(String str) { + if (str == null) { + return 0; + } + int ret = 19; + int count = str.length(); + { + ret = (ret * 31) + count; + for (int i = 0; i < count; ++i) { + ret = (ret * 31) + (int)str.charAt(i); + } + } + return ret; + } + private static boolean StringEquals(String str, String str2) { if (str == str2) { return true; @@ -6480,11 +6414,10 @@ private static int CBORMapHashCode(Map a) { // To simplify matters, we use just the count of // the map as the basis for the hash code. More complicated - // hash code calculation would involve the sum of the hash codes of - // the map's key-value pairs (an approach that works regardless of the order - // in which map keys are iterated, because wraparound addition - // is commutative and associative), but this could take much more time - // to calculate, especially if the keys and values are very big. + // hash code calculation would generally involve defining + // how CBORObjects ought to be compared (since a stable + // sort order is necessary for two equal maps to have the + // same hash code), which is much too difficult to do. return a.size() * 19; } @@ -6593,36 +6526,6 @@ private static String GetOptimizedStringIfShortAscii( return null; } - private static byte[] SerializeUtf8(byte[] utf8) { - byte[] bytes; - if (utf8.length < 24) { - bytes = new byte[utf8.length + 1]; - bytes[0] = (byte)(utf8.length | 0x60); - System.arraycopy(utf8, 0, bytes, 1, utf8.length); - return bytes; - } - if (utf8.length <= 0xffL) { - bytes = new byte[utf8.length + 2]; - bytes[0] = (byte)0x78; - bytes[1] = (byte)utf8.length; - System.arraycopy(utf8, 0, bytes, 2, utf8.length); - return bytes; - } - if (utf8.length <= 0xffffL) { - bytes = new byte[utf8.length + 3]; - bytes[0] = (byte)0x79; - bytes[1] = (byte)((utf8.length >> 8) & 0xff); - bytes[2] = (byte)(utf8.length & 0xff); - System.arraycopy(utf8, 0, bytes, 3, utf8.length); - return bytes; - } - byte[] posbytes = GetPositiveInt64Bytes(3, utf8.length); - bytes = new byte[utf8.length + posbytes.length]; - System.arraycopy(posbytes, 0, bytes, 0, posbytes.length); - System.arraycopy(utf8, 0, bytes, posbytes.length, utf8.length); - return bytes; - } - private static byte[] GetPositiveInt64Bytes(int type, long value) { if (value < 0) { throw new IllegalArgumentException("value(" + value + ") is less than " + @@ -6815,13 +6718,13 @@ private static List PushObject( Object parent, Object child) { if (stack == null) { - stack = new ArrayList(4); + stack = new ArrayList(); stack.add(parent); } for (Object o : stack) { if (o == child) { throw new IllegalArgumentException("Circular reference in data" + - "\u0020structure"); +"\u0020structure"); } } stack.add(child); @@ -6912,17 +6815,17 @@ private static void WriteObjectMap( CBORObject key = entry.getKey(); CBORObject value = entry.getValue(); stack = WriteChildObject( - thisObj, - key, - outputStream, - stack, - options); + thisObj, + key, + outputStream, + stack, + options); stack = WriteChildObject( - thisObj, - value, - outputStream, - stack, - options); + thisObj, + value, + outputStream, + stack, + options); } } @@ -6951,8 +6854,8 @@ private static void WriteStreamedString(String str, OutputStream stream) throws int bufferLength = Math.min(StreamedStringBufferLength, str.length()); if (bufferLength < StreamedStringBufferLength) { bufferLength = Math.min( - StreamedStringBufferLength, - bufferLength * 3); + StreamedStringBufferLength, + bufferLength * 3); } bytes = new byte[bufferLength]; int byteIndex = 0; diff --git a/src/main/java/com/upokecenter/cbor/CBORReader.java b/src/main/java/com/upokecenter/cbor/CBORReader.java index 49c53dae..ccd88a7b 100644 --- a/src/main/java/com/upokecenter/cbor/CBORReader.java +++ b/src/main/java/com/upokecenter/cbor/CBORReader.java @@ -68,16 +68,6 @@ private CBORObject ObjectFromByteArray(byte[] data, int lengthHint) { } return cbor; } - - private CBORObject ObjectFromUtf8Array(byte[] data, int lengthHint) { - CBORObject cbor = data.length == 0 ? CBORObject.FromObject("") : - CBORObject.FromRawUtf8(data); - if (this.stringRefs != null) { - this.stringRefs.AddStringIfNeeded(cbor, lengthHint); - } - return cbor; - } - private static CBORObject ResolveSharedRefs( CBORObject obj, SharedRefs sharedRefs) { @@ -152,7 +142,7 @@ private CBORObject ReadInternal() throws java.io.IOException { private CBORObject ReadStringArrayMap(int type, long uadditional) throws java.io.IOException { boolean canonical = this.options.getCtap2Canonical(); - if (type == 2 || type == 3) { // Byte String or text String + if (type == 2) { // Byte String if ((uadditional >> 31) != 0) { throw new CBORException("Length of " + ToUnsignedEInteger(uadditional).toString() + " is bigger" + @@ -161,14 +151,36 @@ private CBORObject ReadStringArrayMap(int type, long uadditional) throws java.io int hint = (uadditional > Integer.MAX_VALUE || (uadditional >> 63) != 0) ? Integer.MAX_VALUE : (int)uadditional; byte[] data = ReadByteData(this.stream, uadditional, null); - if (type == 3) { - if (!CBORUtilities.CheckUtf8(data)) { + return this.ObjectFromByteArray(data, hint); + } + if (type == 3) { // Text String + if ((uadditional >> 31) != 0) { + throw new CBORException("Length of " + + ToUnsignedEInteger(uadditional).toString() + " is bigger" + + "\u0020than supported"); + } + if (PropertyMap.ExceedsKnownLength(this.stream, uadditional)) { + throw new CBORException("Premature end of data"); + } + StringBuilder builder = new StringBuilder(); + switch ( + DataUtilities.ReadUtf8( + this.stream, + (int)uadditional, + builder, + false)) { + case -1: throw new CBORException("Invalid UTF-8"); - } - return this.ObjectFromUtf8Array(data, hint); - } else { - return this.ObjectFromByteArray(data, hint); + case -2: + throw new CBORException("Premature end of data"); + } + CBORObject cbor = CBORObject.FromRaw(builder.toString()); + if (this.stringRefs != null) { + int hint = (uadditional > Integer.MAX_VALUE || (uadditional >> 63) != + 0) ? Integer.MAX_VALUE : (int)uadditional; + this.stringRefs.AddStringIfNeeded(cbor, hint); } + return cbor; } if (type == 4) { // Array if (this.options.getCtap2Canonical() && this.depth >= 4) { @@ -502,14 +514,12 @@ public CBORObject ReadForFirstByte(int firstbyte) throws java.io.IOException { throw new CBORException("Unexpected data encountered"); } - private static final byte[] EmptyByteArray = new byte[0]; - private static byte[] ReadByteData( InputStream stream, long uadditional, OutputStream outputStream) throws java.io.IOException { if (uadditional == 0) { - return EmptyByteArray; + return new byte[0]; } if ((uadditional >> 63) != 0 || uadditional > Integer.MAX_VALUE) { throw new CBORException("Length" + ToUnsignedEInteger(uadditional) + diff --git a/src/main/java/com/upokecenter/cbor/CBORUriConverter.java b/src/main/java/com/upokecenter/cbor/CBORUriConverter.java index edf8b0bb..1e33b99b 100644 --- a/src/main/java/com/upokecenter/cbor/CBORUriConverter.java +++ b/src/main/java/com/upokecenter/cbor/CBORUriConverter.java @@ -8,7 +8,7 @@ */ class CBORUriConverter implements ICBORToFromConverter { - private CBORObject ValidateObject(CBORObject obj) { + private static CBORObject ValidateObject(CBORObject obj) { if (obj.getType() != CBORType.TextString) { throw new CBORException("URI/IRI must be a text String"); } @@ -40,7 +40,7 @@ public java.net.URI FromCBORObject(CBORObject obj) { if (obj.HasMostOuterTag(32) || obj.HasMostOuterTag(266) || obj.HasMostOuterTag(267)) { - this.ValidateObject(obj); + ValidateObject(obj); try { return new java.net.URI(obj.AsString()); } catch (Exception ex) { diff --git a/src/main/java/com/upokecenter/cbor/CBORUtilities.java b/src/main/java/com/upokecenter/cbor/CBORUtilities.java index 4de7c853..a93b09d6 100644 --- a/src/main/java/com/upokecenter/cbor/CBORUtilities.java +++ b/src/main/java/com/upokecenter/cbor/CBORUtilities.java @@ -1109,7 +1109,7 @@ public static int DoubleToHalfPrecisionIfSameValue(long bits) { long mant = bits & 0xfffffffffffffL; int sign = ((int)(bits >> 48)) & (1 << 15); int sexp = exp - 1008; - // System.out.println("bits={0:X8}, exp=" + exp + " sexp=" + (sexp)); + // System.out.println("bits={0:X8}, exp=" + exp + " sexp=" + (sexp),bits); if (exp == 2047) { // Infinity and NaN int newmant = ((int)(mant >> 42)); return ((mant & ((1L << 42) - 1)) == 0) ? (sign | 0x7c00 | newmant) : @@ -1122,8 +1122,13 @@ public static int DoubleToHalfPrecisionIfSameValue(long bits) { return ((mant & ((1L << 42) - 1)) == 0) ? (sign | (sexp << 10) | RoundedShift(mant, 42)) : -1; } else { // subnormal and zero - return ((mant & ((1L << (42 - (sexp - 1))) - 1)) == 0) ? (sign | - RoundedShift(mant | (1L << 52), 42 - (sexp - 1))) : -1; + int rs = RoundedShift(mant | (1L << 52), 42 - (sexp - 1)); + // System.out.println("mant=" + mant + " rs=" + (rs)); + if (sexp == -10 && rs == 0) { +{ return -1; +} } + return ((mant & ((1L << (42 - (sexp - 1))) - 1)) == 0) ? (sign | rs) : +-1; } } @@ -1138,6 +1143,9 @@ public static boolean DoubleRetainsSameValueInSingle(long bits) { return false; } else if (sexp > 0) { // normal return (mant & ((1L << 29) - 1)) == 0; + } else if (sexp == -23) { + return (mant & ((1L << (29 - (sexp - 1))) - 1)) == 0 && + RoundedShift(mant | (1L << 52), 29 - (sexp - 1)) != 0; } else { // subnormal and zero return (mant & ((1L << (29 - (sexp - 1))) - 1)) == 0; } @@ -1223,11 +1231,14 @@ public static int SingleToHalfPrecisionIfSameValue(float f) { return -1; } else if (exp <= 112) { // Subnormal int shift = 126 - exp; - return (bits & ((1 << shift) - 1)) == 0 ? sign + - (1024 >> (145 - exp)) + (mant >> shift) : -1; + int rs = (1024 >> (145 - exp)) + (mant >> shift); + if (mant != 0 && exp == 103) { { + return -1; + } } + return (bits & ((1 << shift) - 1)) == 0 ? sign + rs : -1; } else { return (bits & 0x1fff) == 0 ? sign + ((exp - 112) << 10) + - (mant >> 13) : -1; +-(mant >> 13) : -1; } } diff --git a/src/main/java/com/upokecenter/cbor/CBORUuidConverter.java b/src/main/java/com/upokecenter/cbor/CBORUuidConverter.java index 5184c27a..117b84b8 100644 --- a/src/main/java/com/upokecenter/cbor/CBORUuidConverter.java +++ b/src/main/java/com/upokecenter/cbor/CBORUuidConverter.java @@ -8,7 +8,7 @@ */ class CBORUuidConverter implements ICBORToFromConverter { - private CBORObject ValidateObject(CBORObject obj) { + private static CBORObject ValidateObject(CBORObject obj) { if (obj.getType() != CBORType.ByteString) { throw new CBORException("UUID must be a byte String"); } @@ -33,7 +33,7 @@ public java.util.UUID FromCBORObject(CBORObject obj) { if (!obj.HasMostOuterTag(37)) { throw new CBORException("Must have outermost tag 37"); } - this.ValidateObject(obj); + ValidateObject(obj); byte[] bytes = obj.GetByteString(); char[] guidChars = new char[36]; String hex = "0123456789abcdef"; diff --git a/src/main/java/com/upokecenter/cbor/ICBORNumber.java b/src/main/java/com/upokecenter/cbor/ICBORNumber.java index 66da5051..6569f6e8 100644 --- a/src/main/java/com/upokecenter/cbor/ICBORNumber.java +++ b/src/main/java/com/upokecenter/cbor/ICBORNumber.java @@ -10,174 +10,52 @@ import com.upokecenter.util.*; import com.upokecenter.numbers.*; - /** - * This is an internal API. - */ interface ICBORNumber { - /** - * This is an internal API. - * @param obj The parameter {@code obj} is an arbitrary object. - * @return The return value is an internal value. - */ boolean IsPositiveInfinity(Object obj); - /** - * This is an internal API. - * @param obj The parameter {@code obj} is an arbitrary object. - * @return The return value is an internal value. - */ boolean IsInfinity(Object obj); - /** - * This is an internal API. - * @param obj The parameter {@code obj} is an arbitrary object. - * @return The return value is an internal value. - */ boolean IsNegativeInfinity(Object obj); - /** - * This is an internal API. - * @param obj The parameter {@code obj} is an arbitrary object. - * @return The return value is an internal value. - */ boolean IsNaN(Object obj); - /** - * This is an internal API. - * @param obj The parameter {@code obj} is an arbitrary object. - * @return The return value is an internal value. - */ boolean IsNegative(Object obj); - /** - * This is an internal API. - * @param obj The parameter {@code obj} is an arbitrary object. - * @return The return value is an internal value. - */ double AsDouble(Object obj); - /** - * This is an internal API. - * @param obj The parameter {@code obj} is an arbitrary object. - * @return The return value is an internal value. - */ Object Negate(Object obj); - /** - * This is an internal API. - * @param obj The parameter {@code obj} is an arbitrary object. - * @return The return value is an internal value. - */ Object Abs(Object obj); - /** - * This is an internal API. - * @param obj The parameter {@code obj} is an arbitrary object. - * @return The return value is an internal value. - */ EDecimal AsEDecimal(Object obj); - /** - * This is an internal API. - * @param obj The parameter {@code obj} is an arbitrary object. - * @return The return value is an internal value. - */ EFloat AsEFloat(Object obj); - /** - * This is an internal API. - * @param obj The parameter {@code obj} is an arbitrary object. - * @return The return value is an internal value. - */ ERational AsERational(Object obj); - /** - * This is an internal API. - * @param obj The parameter {@code obj} is an arbitrary object. - * @return The return value is an internal value. - */ float AsSingle(Object obj); - /** - * This is an internal API. - * @param obj The parameter {@code obj} is an arbitrary object. - * @return The return value is an internal value. - */ EInteger AsEInteger(Object obj); - /** - * This is an internal API. - * @param obj The parameter {@code obj} is an arbitrary object. - * @return The return value is an internal value. - */ long AsInt64(Object obj); - /** - * This is an internal API. - * @param obj The parameter {@code obj} is an arbitrary object. - * @return The return value is an internal value. - */ boolean CanFitInSingle(Object obj); - /** - * This is an internal API. - * @param obj The parameter {@code obj} is an arbitrary object. - * @return The return value is an internal value. - */ boolean CanFitInDouble(Object obj); - /** - * This is an internal API. - * @param obj The parameter {@code obj} is an arbitrary object. - * @return The return value is an internal value. - */ boolean CanFitInInt32(Object obj); - /** - * This is an internal API. - * @param obj The parameter {@code obj} is an arbitrary object. - * @return The return value is an internal value. - */ boolean CanFitInInt64(Object obj); - /** - * This is an internal API. - * @param obj The parameter {@code obj} is an arbitrary object. - * @return The return value is an internal value. - */ boolean CanTruncatedIntFitInInt64(Object obj); - /** - * This is an internal API. - * @param obj The parameter {@code obj} is an arbitrary object. - * @return The return value is an internal value. - */ boolean CanTruncatedIntFitInInt32(Object obj); - /** - * This is an internal API. - * @return The return value is an internal value. - */ int AsInt32(Object obj, int minValue, int maxValue); - /** - * This is an internal API. - * @param obj The parameter {@code obj} is an arbitrary object. - * @return The return value is an internal value. - */ boolean IsNumberZero(Object obj); - /** - * This is an internal API. - * @param obj The parameter {@code obj} is an arbitrary object. - * @return The return value is an internal value. - */ int Sign(Object obj); - /** - * This is an internal API. - * @param obj The parameter {@code obj} is an arbitrary object. - * @return The return value is an internal value. - */ boolean IsIntegral(Object obj); } diff --git a/src/main/java/com/upokecenter/cbor/JSONOptions.java b/src/main/java/com/upokecenter/cbor/JSONOptions.java index fc438f8e..787a17dd 100644 --- a/src/main/java/com/upokecenter/cbor/JSONOptions.java +++ b/src/main/java/com/upokecenter/cbor/JSONOptions.java @@ -12,15 +12,9 @@ public final class JSONOptions { public enum ConversionMode { /** * JSON numbers are decoded to CBOR using the full precision given in the JSON - * text. The number will be converted to a CBOR object as follows: - * If the number's exponent is 0 (after shifting the decimal point - * to the end of the number without changing its value), using the - * rules given in the CBORObject.FromObject(EInteger) method; - * otherwise, using the rules given in the - * CBORObject.FromObject(EDecimal) method. An exception in - * version 4.x involves negative zeros; if the negative zero's - * exponent is 0, it's written as a CBOR floating-point number; - * otherwise the negative zero is written as an EDecimal. + * text. This may involve numbers being converted to + * arbitrary-precision integers or decimal numbers, where + * appropriate. */ Full, diff --git a/src/main/java/com/upokecenter/cbor/PropertyMap.java b/src/main/java/com/upokecenter/cbor/PropertyMap.java index ae424182..4b53e8d5 100644 --- a/src/main/java/com/upokecenter/cbor/PropertyMap.java +++ b/src/main/java/com/upokecenter/cbor/PropertyMap.java @@ -14,7 +14,7 @@ import java.util.Arrays; import java.util.Collection; import java.util.Collections; -import java.util.TreeMap; +import java.util.HashMap; import java.util.List; import java.util.Map; @@ -125,10 +125,10 @@ public String GetAdjustedName(boolean useCamelCase){ } private static Map, List> propertyLists = - new TreeMap, List>(); + new HashMap, List>(); private static Map, List> setterPropertyList = - new TreeMap, List>(); + new HashMap, List>(); private static List GetPropertyList(final Class t) { return GetPropertyList(t,false); @@ -177,11 +177,11 @@ private static List GetPropertyList(final Class t, boolean setter List setMethods=new ArrayList(); List isMethods=new ArrayList(); Map getMethodNames=new - TreeMap(); + HashMap(); Map setMethodNames=new - TreeMap(); + HashMap(); Map methodNamesToIndices=new - TreeMap(); + HashMap(); boolean hasAmbiguousGetName=false; boolean hasAmbiguousSetName=false; for(Method pi : t.getMethods()) { @@ -284,7 +284,7 @@ private static List GetPropertyList(final Class t, boolean setter } public static Collection> - GetEntries(Map dict) { + GetEntries(Map dict) { return Collections.unmodifiableMap(dict).entrySet(); } @@ -330,7 +330,7 @@ public static Object ObjectWithProperties( int depth) { try { Object o = t.getDeclaredConstructor().newInstance(); - Map dict = new TreeMap(); + Map dict = new HashMap(); for (Map.Entry kv : keysValues) { String name = kv.getKey(); dict.put(name,kv.getValue()); @@ -618,9 +618,9 @@ public static Object TypeToObject(CBORObject objThis, Type t, } if(objThis.getType()==CBORType.Map){ if(rawType!=null && - rawType.equals(TreeMap.class) || rawType.equals(Map.class)){ + rawType.equals(HashMap.class) || rawType.equals(Map.class)){ if(typeArguments==null || typeArguments.length<2){ - TreeMap alist=new TreeMap(); + HashMap alist=new HashMap(); for(CBORObject cbor : objThis.getKeys()){ CBORObject cborValue=objThis.get(cbor); alist.put(cbor.ToObject(Object.class,mapper,options,depth+1), @@ -628,7 +628,7 @@ public static Object TypeToObject(CBORObject objThis, Type t, } return alist; } else { - TreeMap alist=new TreeMap(); + HashMap alist=new HashMap(); for(CBORObject cbor : objThis.getKeys()){ CBORObject cborValue=objThis.get(cbor); alist.put(cbor.ToObject(typeArguments[0],mapper,options,depth+1), diff --git a/src/main/java/com/upokecenter/cbor/StringOutput.java b/src/main/java/com/upokecenter/cbor/StringOutput.java index 3367fef3..e636642d 100644 --- a/src/main/java/com/upokecenter/cbor/StringOutput.java +++ b/src/main/java/com/upokecenter/cbor/StringOutput.java @@ -46,9 +46,7 @@ public void WriteString(String str) throws java.io.IOException { } public void WriteString(String str, int index, int length) throws java.io.IOException { - if (this.outputStream == null) { - this.builder.append(str, index, (index)+(length)); - } else { + if (this.outputStream != null) { if (length == 1) { this.WriteCodePoint((int)str.charAt(index)); } else { @@ -62,19 +60,12 @@ public void WriteString(String str, int index, int length) throws java.io.IOExce throw new IllegalArgumentException("str has an unpaired surrogate"); } } + } else { + this.builder.append(str, index, (index)+(length)); } } public void WriteCodePoint(int codePoint) throws java.io.IOException { - if ((codePoint >> 7) == 0) { - // Code point is in the Basic Latin range (U+0000 to U+007F) - if (this.outputStream == null) { - this.builder.append((char)codePoint); - } else { - this.outputStream.write((byte)codePoint); -} - return; - } if (codePoint < 0) { throw new IllegalArgumentException("codePoint(" + codePoint + ") is less than 0"); @@ -101,7 +92,7 @@ public void WriteCodePoint(int codePoint) throws java.io.IOException { this.outputStream.write((byte)(0x80 | (codePoint & 0x3f))); } else { this.outputStream.write((byte)(0xf0 | ((codePoint >> 18) & - 0x07))); + 0x08))); this.outputStream.write((byte)(0x80 | ((codePoint >> 12) & 0x3f))); this.outputStream.write((byte)(0x80 | ((codePoint >> 6) & diff --git a/src/main/java/com/upokecenter/cbor/StringRefs.java b/src/main/java/com/upokecenter/cbor/StringRefs.java index 87f37238..a23f1839 100644 --- a/src/main/java/com/upokecenter/cbor/StringRefs.java +++ b/src/main/java/com/upokecenter/cbor/StringRefs.java @@ -11,6 +11,10 @@ import com.upokecenter.util.*; import com.upokecenter.numbers.*; + /** + * Implements CBOR string references, described at + * http://cbor.schmorp.de/stringref. + */ class StringRefs { private final ArrayList> stack; diff --git a/src/main/java/com/upokecenter/util/DataUtilities.java b/src/main/java/com/upokecenter/util/DataUtilities.java index c42cbe83..a8a07613 100644 --- a/src/main/java/com/upokecenter/util/DataUtilities.java +++ b/src/main/java/com/upokecenter/util/DataUtilities.java @@ -32,8 +32,6 @@ public final class DataUtilities { private DataUtilities() { } -// TODO: In CodePointAt/CodePointBefore, consider adding -// mode to return -2 or throw an exception on unpaired surrogate private static final int StreamedStringBufferLength = 4096; /** @@ -135,7 +133,7 @@ public static String GetUtf8String( *

    Encodes a string in UTF-8 as a byte array. This method does not insert a * byte-order mark (U+FEFF) at the beginning of the encoded byte * array.

    REMARK: It is not recommended to use - * Encoding.UTF8.GetBytes in.getNET(), or the getBytes() + * Encoding.UTF8.GetBytes in.NET, or the getBytes() * method in Java to do this. For instance, getBytes() encodes * text strings in a default (so not fixed) character encoding, which * can be undesirable.

    @@ -156,7 +154,7 @@ public static byte[] GetUtf8Bytes(String str, boolean replace) { *

    Encodes a string in UTF-8 as a byte array. This method does not insert a * byte-order mark (U+FEFF) at the beginning of the encoded byte * array.

    REMARK: It is not recommended to use - * Encoding.UTF8.GetBytes in.getNET(), or the getBytes() + * Encoding.UTF8.GetBytes in.NET, or the getBytes() * method in Java to do this. For instance, getBytes() encodes * text strings in a default (so not fixed) character encoding, which * can be undesirable.

    diff --git a/src/test/java/com/upokecenter/test/CBORTest.java b/src/test/java/com/upokecenter/test/CBORTest.java index 6ce1a035..d241a50f 100644 --- a/src/test/java/com/upokecenter/test/CBORTest.java +++ b/src/test/java/com/upokecenter/test/CBORTest.java @@ -718,54 +718,54 @@ public static String ObjectMessage(CBORObject obj) { } public static void TestCanFitInOne(CBORObject ed) { - EDecimal ed2; - if (ed == null) { - throw new NullPointerException("ed"); - } - CBORNumber edNumber = ed.AsNumber(); - EDecimal edNumberED = AsED(ed); - ed2 = EDecimal.FromDouble(edNumberED.ToDouble()); - if ((edNumberED.compareTo(ed2) == 0) != edNumber.CanFitInDouble()) { - Assert.fail(ObjectMessage(ed)); - } - ed2 = EDecimal.FromSingle(AsED(ed).ToSingle()); - if ((edNumberED.compareTo(ed2) == 0) != edNumber.CanFitInSingle()) { + EDecimal ed2; + if (ed == null) { + throw new NullPointerException("ed"); + } + CBORNumber edNumber = ed.AsNumber(); + EDecimal edNumberED = AsED(ed); + ed2 = EDecimal.FromDouble(edNumberED.ToDouble()); + if ((edNumberED.compareTo(ed2) == 0) != edNumber.CanFitInDouble()) { + Assert.fail(ObjectMessage(ed)); + } + ed2 = EDecimal.FromSingle(AsED(ed).ToSingle()); + if ((edNumberED.compareTo(ed2) == 0) != edNumber.CanFitInSingle()) { + Assert.fail(ObjectMessage(ed)); + } + if (!edNumber.IsInfinity() && !edNumber.IsNaN()) { + if (edNumberED.IsInteger() != edNumber.IsInteger()) { Assert.fail(ObjectMessage(ed)); } - if (!edNumber.IsInfinity() && !edNumber.IsNaN()) { - if (edNumberED.IsInteger() != edNumber.IsInteger()) { - Assert.fail(ObjectMessage(ed)); - } + } + if (!edNumber.IsInfinity() && !edNumber.IsNaN()) { + EDecimal edec = edNumberED; + EInteger bi = null; + try { + bi = edec.ToSizedEInteger(128); + } catch (ArithmeticException ex) { + bi = null; } - if (!edNumber.IsInfinity() && !edNumber.IsNaN()) { - EDecimal edec = edNumberED; - EInteger bi = null; - try { - bi = edec.ToSizedEInteger(128); - } catch (ArithmeticException ex) { - bi = null; - } - if (edNumber.IsInteger()) { - if ((bi != null && bi.GetSignedBitLengthAsInt64() <= 31) != - edNumber.CanFitInInt32()) { - Assert.fail(ObjectMessage(ed)); - } - } + if (edNumber.IsInteger()) { if ((bi != null && bi.GetSignedBitLengthAsInt64() <= 31) != - edNumber.CanTruncatedIntFitInInt32()) { + edNumber.CanFitInInt32()) { Assert.fail(ObjectMessage(ed)); } - if (edNumber.IsInteger()) { - if ((bi != null && bi.GetSignedBitLengthAsInt64() <= 63) != - edNumber.CanFitInInt64()) { - Assert.fail(ObjectMessage(ed)); - } - } + } + if ((bi != null && bi.GetSignedBitLengthAsInt64() <= 31) != + edNumber.CanTruncatedIntFitInInt32()) { + Assert.fail(ObjectMessage(ed)); + } + if (edNumber.IsInteger()) { if ((bi != null && bi.GetSignedBitLengthAsInt64() <= 63) != - edNumber.CanTruncatedIntFitInInt64()) { + edNumber.CanFitInInt64()) { Assert.fail(ObjectMessage(ed)); } } + if ((bi != null && bi.GetSignedBitLengthAsInt64() <= 63) != + edNumber.CanTruncatedIntFitInInt64()) { + Assert.fail(ObjectMessage(ed)); + } + } } @Test @@ -800,8 +800,8 @@ public void TestCanFitInSpecificCases() { 0x18, 0x2f, 0x32, }); // -2674012278751232 Assert.assertEquals( - 52L, - AsEI(cbor).GetSignedBitLengthAsInt64()); + 52L, + AsEI(cbor).GetSignedBitLengthAsInt64()); if (!(cbor.AsNumber().CanFitInInt64())) { Assert.fail(); } @@ -1036,142 +1036,325 @@ public void TestCBORInfinityRoundTrip() { ToObjectTest.TestToFromObjectRoundTrip(Float.POSITIVE_INFINITY)); } + @Test + public void TestEquivJSONSpecificA() { + TestEquivJSONOne(new byte[] { + 0x2d, 0x37, 0x30, 0x31, 0x39, 0x34, + 0x38, 0x33, 0x35, 0x39, 0x31, 0x33, 0x37, 0x34, 0x38, 0x45, 0x30, + }); + } + + public static boolean TestEquivJSONOne(byte[] bytes) { + if (bytes == null) { + throw new NullPointerException("bytes"); + } + if (!(bytes.length > 0)) { + return false; + } + CBORObject cbo = CBORObject.FromJSONBytes(bytes); + if (!(cbo != null)) { + Assert.fail(); + } + CBORObject cbo2 = CBORObject.FromJSONString(cbo.ToJSONString()); + if (!(cbo2 != null)) { + Assert.fail(); + } + if (!cbo.equals(cbo2)) { + System.out.print("jsonstring"); + System.out.print(TestCommon.ToByteArrayString(bytes)); + System.out.print(DataUtilities.GetUtf8String(bytes, true)); + System.out.print("old " + TestCommon.ToByteArrayString(cbo.ToJSONBytes())); + System.out.print(cbo.ToJSONString()); + System.out.print("new " + +TestCommon.ToByteArrayString(cbo2.ToJSONBytes())); + System.out.print(cbo2.ToJSONString()); + Assert.assertEquals(cbo, cbo2); + } + cbo2 = CBORObject.FromJSONBytes(cbo.ToJSONBytes()); + if (!(cbo2 != null)) { + Assert.fail(); + } + if (!cbo.equals(cbo2)) { + System.out.print("jsonbytes"); + System.out.print(TestCommon.ToByteArrayString(bytes)); + System.out.print(DataUtilities.GetUtf8String(bytes, true)); + System.out.print("old " + TestCommon.ToByteArrayString(cbo.ToJSONBytes())); + System.out.print(cbo.ToJSONString()); + System.out.print("new " + +TestCommon.ToByteArrayString(cbo2.ToJSONBytes())); + System.out.print(cbo2.ToJSONString()); + Assert.assertEquals(cbo, cbo2); + } + return true; + } + public static boolean TestEquivJSONNumberOne(byte[] bytes) { + // Assume the JSON begins and ends with a digit + if (bytes == null) { + throw new NullPointerException("bytes"); + } + if (!(bytes.length > 0)) { + return false; + } + if (!((bytes[0] >= 0x30 && bytes[0] <= 0x39) || bytes[0] == (byte)'-')) { + return false; + } + if (!(bytes[bytes.length - 1] >= 0x30 && bytes[bytes.length - 1] <= +0x39)) { + return false; + } + CBORObject cbor, cbor2, cbored, cbor3; + JSONOptions jsoptions = new JSONOptions("numberconversion=full"); + String str = DataUtilities.GetUtf8String(bytes, true); + EDecimal ed = EDecimal.FromString(str); + // Test consistency between JSON conversion methods + cbor = CBORObject.FromJSONBytes(bytes, jsoptions); + cbor2 = CBORDataUtilities.ParseJSONNumber(str, jsoptions); + cbor3 = CBORObject.FromJSONString(str, jsoptions); + cbored = (ed.getExponent().compareTo(0) == 0 && !(ed.isNegative() && ed.signum() +== 0)) ? + CBORObject.FromObject(ed.getMantissa()) : CBORObject.FromObject(ed); + Assert.assertEquals("[" + str + "] cbor2",cbor,cbor2); + Assert.assertEquals("[" + str + "] cbor3",cbor,cbor3); + Assert.assertEquals("[" + str + "] cbored",cbor,cbored); + return true; + } + public static boolean TestEquivJSONNumberDecimal128One(byte[] bytes) { + // Assume the JSON begins and ends with a digit + if (bytes == null) { + throw new NullPointerException("bytes"); + } + if (!(bytes.length > 0)) { + return false; + } + if (!((bytes[0] >= 0x30 && bytes[0] <= 0x39) || bytes[0] == (byte)'-')) { + return false; + } + if (!(bytes[bytes.length - 1] >= 0x30 && bytes[bytes.length - 1] <= +0x39)) { + return false; + } + CBORObject cbor, cbor2, cbored, cbor3; + JSONOptions jsoptions = new JSONOptions("numberconversion=decimal128"); + String str = DataUtilities.GetUtf8String(bytes, true); + // Test consistency between JSON conversion methods + EDecimal ed = EDecimal.FromString(str, EContext.Decimal128); + cbor = CBORObject.FromJSONBytes(bytes, jsoptions); + cbor2 = CBORDataUtilities.ParseJSONNumber(str, jsoptions); + cbor3 = CBORObject.FromJSONString(str, jsoptions); + cbored = CBORObject.FromObject(ed); + Assert.assertEquals("[" + str + "] cbor2",cbor,cbor2); + Assert.assertEquals("[" + str + "] cbor3",cbor,cbor3); + Assert.assertEquals("[" + str + "] cbored",cbor,cbored); + return true; + } public static void TestCompareToOne(byte[] bytes) { - CBORObject cbor = CBORObject.DecodeFromBytes(bytes, new -CBOREncodeOptions("allowduplicatekeys=1")); - byte[] bytes2 = cbor.EncodeToBytes(); - CBORObject cbor2 = CBORObject.DecodeFromBytes(bytes2); - if (!cbor.equals(cbor2)) { - String sbytes = TestCommon.ToByteArrayString(bytes) + - "\ncbor=" + cbor + - "\ncborbytes=" + TestCommon.ToByteArrayString(bytes2) + - "\ncbor2=" + cbor2 + - "\ncborbytes2=" + TestCommon.ToByteArrayString(cbor2.EncodeToBytes()); - Assert.assertEquals(sbytes, cbor, cbor2); - } else { - Assert.assertEquals(cbor, cbor2); - } - if (cbor.compareTo(cbor2) != 0) { - String sbytes = TestCommon.ToByteArrayString(bytes) + - "\ncbor=" + cbor + - "\ncborbytes=" + TestCommon.ToByteArrayString(bytes2) + - "\ncbor2=" + cbor2 + - "\ncborbytes2=" + TestCommon.ToByteArrayString(cbor2.EncodeToBytes()); - Assert.assertEquals(sbytes, 0, cbor.compareTo(cbor2)); - } else { - Assert.assertEquals(0, cbor.compareTo(cbor2)); - } + CBORObject cbor = CBORObject.DecodeFromBytes(bytes, new + CBOREncodeOptions("allowduplicatekeys=1")); + byte[] bytes2 = cbor.EncodeToBytes(); + CBORObject cbor2 = CBORObject.DecodeFromBytes(bytes2); + if (!cbor.equals(cbor2)) { + String sbytes = TestCommon.ToByteArrayString(bytes) + + "\ncbor=" + cbor + + "\ncborbytes=" + TestCommon.ToByteArrayString(bytes2) + + "\ncbor2=" + cbor2 + + "\ncborbytes2=" + TestCommon.ToByteArrayString(cbor2.EncodeToBytes()); + Assert.assertEquals(sbytes, cbor, cbor2); + } else { + Assert.assertEquals(cbor, cbor2); + } + if (cbor.compareTo(cbor2) != 0) { + String sbytes = TestCommon.ToByteArrayString(bytes) + + "\ncbor=" + cbor + + "\ncborbytes=" + TestCommon.ToByteArrayString(bytes2) + + "\ncbor2=" + cbor2 + + "\ncborbytes2=" + TestCommon.ToByteArrayString(cbor2.EncodeToBytes()); + Assert.assertEquals(sbytes, 0, cbor.compareTo(cbor2)); + } else { + Assert.assertEquals(0, cbor.compareTo(cbor2)); + } } @Test public void TestCompareToSpecificA() { -byte[] bytes = new byte[] { (byte)0xfa, (byte)0xb3, 0x00, 0x00, 0x00 }; -TestCompareToOne(bytes); + byte[] bytes = new byte[] { (byte)0xfa, (byte)0xb3, 0x00, 0x00, 0x00 }; + TestCompareToOne(bytes); } @Test public void TestCompareToSpecificE() { -byte[] bytes = new byte[] { - (byte)0xbf, - (byte)0xf9, - (byte)0xce, - (byte)0xdc, - (byte)0x99, 0x00, 0x01, - (byte)0xf8, - (byte)0xa0, 0x61, 0x37, 0x12, 0x7f, 0x78, 0x0d, 0x1c, 0x78, 0x4a, 0x48, 0x3e, - (byte)0xe1, - (byte)0xa5, - (byte)0xb2, - (byte)0xf4, - (byte)0x82, - (byte)0x8f, - (byte)0x8a, 0x32, 0x7b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, - 0x2d, 0x57, 0x55, 0x08, 0x7b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x02, 0x41, 0x28, - (byte)0xff, (byte)0xe3, (byte)0xff, - }; -TestCompareToOne(bytes); + byte[] bytes = new byte[] { + (byte)0xbf, + (byte)0xf9, + (byte)0xce, + (byte)0xdc, + (byte)0x99, 0x00, 0x01, + (byte)0xf8, + (byte)0xa0, 0x61, 0x37, 0x12, 0x7f, 0x78, 0x0d, 0x1c, 0x78, 0x4a, + 0x48, 0x3e, + (byte)0xe1, + (byte)0xa5, + (byte)0xb2, + (byte)0xf4, + (byte)0x82, + (byte)0x8f, + (byte)0x8a, 0x32, 0x7b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, + 0x2d, 0x57, 0x55, 0x08, 0x7b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x41, 0x28, + (byte)0xff, (byte)0xe3, (byte)0xff, + }; + TestCompareToOne(bytes); } @Test public void TestCompareToSpecificC() { -byte[] bytes = new byte[] { - (byte)0xb9, 0x00, 0x02, - (byte)0xfa, - (byte)0x93, - (byte)0x96, - (byte)0xf3, - (byte)0xcb, 0x1b, - (byte)0xe7, 0x65, 0x72, - (byte)0x83, - (byte)0xa0, 0x39, - (byte)0xa0, - (byte)0xfe, 0x7f, 0x7b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, - 0x2e, 0x7a, 0x00, 0x00, 0x00, 0x03, 0x1e, 0x33, 0x52, 0x60, 0x7a, 0x00, - 0x00, 0x00, 0x03, 0x62, 0x1e, 0x23, - (byte)0xff, 0x18, (byte)0x89, - }; -TestCompareToOne(bytes); + byte[] bytes = new byte[] { + (byte)0xb9, 0x00, 0x02, + (byte)0xfa, + (byte)0x93, + (byte)0x96, + (byte)0xf3, + (byte)0xcb, 0x1b, + (byte)0xe7, 0x65, 0x72, + (byte)0x83, + (byte)0xa0, 0x39, + (byte)0xa0, + (byte)0xfe, 0x7f, 0x7b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x2e, 0x7a, 0x00, 0x00, 0x00, 0x03, 0x1e, 0x33, 0x52, 0x60, 0x7a, 0x00, + 0x00, 0x00, 0x03, 0x62, 0x1e, 0x23, + (byte)0xff, 0x18, (byte)0x89, + }; + TestCompareToOne(bytes); } @Test public void TestCompareToSpecificD() { -byte[] bytes = new byte[] { - (byte)0xbf, 0x00, 0x00, - (byte)0xe0, 0x00, 0x7f, 0x78, 0x10, 0x64, 0x6b, 0x05, 0x77, 0x38, 0x3c, - 0x51, 0x66, 0x7c, 0x02, 0x31, 0x51, 0x56, 0x33, 0x56, 0x6a, 0x7b, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x70, 0x16, 0x20, 0x2f, 0x29, - 0x1a, 0x1f, 0x7b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, - 0x01, 0x5c, - (byte)0xff, (byte)0xfa, (byte)0xa1, (byte)0xeb, (byte)0xc3, 0x1d, - (byte)0xff, - }; -TestCompareToOne(bytes); + byte[] bytes = new byte[] { + (byte)0xbf, 0x00, 0x00, + (byte)0xe0, 0x00, 0x7f, 0x78, 0x10, 0x64, 0x6b, 0x05, 0x77, 0x38, 0x3c, + 0x51, 0x66, 0x7c, 0x02, 0x31, 0x51, 0x56, 0x33, 0x56, 0x6a, 0x7b, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x70, 0x16, 0x20, 0x2f, 0x29, + 0x1a, 0x1f, 0x7b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, + 0x01, 0x5c, + (byte)0xff, (byte)0xfa, (byte)0xa1, (byte)0xeb, (byte)0xc3, 0x1d, + (byte)0xff, + }; + TestCompareToOne(bytes); } @Test public void TestCompareToSpecificB() { -byte[] bytes = new byte[] { - (byte)0xa4, - (byte)0xe3, - (byte)0xf8, 0x70, - (byte)0xdb, 0x02, 0x2d, 0x0d, 0x30, 0x39, 0x14, - (byte)0xf5, - (byte)0x8c, 0x39, 0x56, 0x1c, 0x3a, - (byte)0x92, 0x27, 0x00, 0x04, 0x39, 0x1e, 0x05, - (byte)0xf9, 0x73, - (byte)0xac, 0x7f, 0x78, 0x05, 0x2d, - (byte)0xe5, - (byte)0xad, - (byte)0xb8, 0x0b, 0x63, 0x27, 0x50, 0x7e, 0x78, 0x02, 0x04, 0x56, - (byte)0xff, 0x1b, - (byte)0x9d, (byte)0x8c, 0x66, (byte)0xaf, 0x18, 0x1d, 0x01, (byte)0x8e, - }; -TestCompareToOne(bytes); + byte[] bytes = new byte[] { + (byte)0xa4, + (byte)0xe3, + (byte)0xf8, 0x70, + (byte)0xdb, 0x02, 0x2d, 0x0d, 0x30, 0x39, 0x14, + (byte)0xf5, + (byte)0x8c, 0x39, 0x56, 0x1c, 0x3a, + (byte)0x92, 0x27, 0x00, 0x04, 0x39, 0x1e, 0x05, + (byte)0xf9, 0x73, + (byte)0xac, 0x7f, 0x78, 0x05, 0x2d, + (byte)0xe5, + (byte)0xad, + (byte)0xb8, 0x0b, 0x63, 0x27, 0x50, 0x7e, 0x78, 0x02, 0x04, 0x56, + (byte)0xff, 0x1b, + (byte)0x9d, (byte)0x8c, 0x66, (byte)0xaf, 0x18, 0x1d, 0x01, + (byte)0x8e, + }; + TestCompareToOne(bytes); } @Test public void TestCompareToSpecific() { -byte[] bytes; -bytes = new byte[] { - (byte)0xa2, - (byte)0xf8, - (byte)0xf7, 0x19, - (byte)0xde, - (byte)0x91, 0x7f, 0x79, 0x00, 0x11, 0x7b, 0x1b, 0x29, 0x59, 0x57, 0x6a, - 0x70, 0x68, - (byte)0xe3, - (byte)0x98, - (byte)0xba, 0x6a, 0x49, 0x50, 0x54, 0x0b, 0x21, 0x62, 0x32, 0x17, 0x7b, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x67, 0x43, 0x37, 0x42, - 0x5f, 0x22, 0x7c, 0x0e, 0x68, 0x13, 0x74, 0x43, 0x1e, 0x4c, 0x5b, 0x2b, - 0x6c, 0x7b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7a, 0x00, - 0x00, 0x00, 0x00, 0x7b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x78, 0x01, 0x38, 0x78, 0x00, 0x78, 0x00, 0x7b, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x01, 0x39, - (byte)0xff, (byte)0x9f, (byte)0xff, - }; -TestCompareToOne(bytes); + byte[] bytes; + bytes = new byte[] { + (byte)0xa2, + (byte)0xf8, + (byte)0xf7, 0x19, + (byte)0xde, + (byte)0x91, 0x7f, 0x79, 0x00, 0x11, 0x7b, 0x1b, 0x29, 0x59, 0x57, 0x6a, + 0x70, 0x68, + (byte)0xe3, + (byte)0x98, + (byte)0xba, 0x6a, 0x49, 0x50, 0x54, 0x0b, 0x21, 0x62, 0x32, 0x17, 0x7b, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x67, 0x43, 0x37, 0x42, + 0x5f, 0x22, 0x7c, 0x0e, 0x68, 0x13, 0x74, 0x43, 0x1e, 0x4c, 0x5b, 0x2b, + 0x6c, 0x7b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7a, 0x00, + 0x00, 0x00, 0x00, 0x7b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x78, 0x01, 0x38, 0x78, 0x00, 0x78, 0x00, 0x7b, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x39, + (byte)0xff, (byte)0x9f, (byte)0xff, + }; + TestCompareToOne(bytes); + } + + @Test + public void TestCompareB1() { + byte[] bytes; + CBORObject o; + bytes = new byte[] { + (byte)0xbb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x02, + (byte)0xf8, 0x2d, 0x11, 0x7f, 0x79, 0x00, 0x2e, 0x7c, 0x2c, 0x18, + 0x40, 0x3e, + (byte)0xc7, + (byte)0xa9, 0x0c, 0x57, 0x50, 0x63, 0x30, 0x0f, 0x07, 0x76, 0x14, + 0x31, 0x52, 0x5c, 0x0a, 0x43, 0x4a, 0x6f, 0x08, 0x11, 0x25, 0x0b, 0x1a, + 0x10, 0x74, + (byte)0xf1, + (byte)0x84, + (byte)0xbd, + (byte)0x93, 0x4f, 0x74, 0x23, 0x5b, 0x7c, 0x5c, 0x76, 0x70, 0x0a, + (byte)0xde, + (byte)0xa3, 0x5e, 0x7b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0b, 0x76, + (byte)0xf0, + (byte)0xad, + (byte)0xbf, + (byte)0xba, 0x14, 0x45, 0x0d, 0x2e, 0x6e, 0x62, 0x62, 0x10, 0x63, + (byte)0xff, 0x35, + }; + o = CBORObject.DecodeFromBytes(bytes, + new CBOREncodeOptions("allowduplicatekeys=1")); + CBORTestCommon.AssertRoundTrip(o); + bytes = new byte[] { + (byte)0xd9, 0x0e, 0x02, + (byte)0xbf, 0x7f, 0x78, 0x07, 0x12, 0x45, 0x2f, 0x48, + (byte)0xc8, + (byte)0xb7, 0x5a, 0x79, 0x00, 0x01, 0x5e, 0x7b, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x72, 0x78, 0x00, 0x7a, 0x00, 0x00, 0x00, + 0x01, 0x49, 0x61, 0x6d, 0x7b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x13, + (byte)0xff, + (byte)0xed, + (byte)0xfb, + (byte)0x82, 0x18, + (byte)0xc9, 0x6c, 0x3b, (byte)0xc0, 0x53, 0x1f, (byte)0xeb, + (byte)0xff, + }; + o = CBORObject.DecodeFromBytes(bytes, + new CBOREncodeOptions("allowduplicatekeys=1")); + CBORTestCommon.AssertRoundTrip(o); + bytes = new byte[] { + (byte)0xbf, + (byte)0xfa, + (byte)0xc5, 0x7f, 0x16, + (byte)0xe2, + (byte)0xf9, 0x05, 0x2d, 0x7f, 0x79, 0x00, 0x02, 0x4f, 0x0a, 0x67, + 0x1a, 0x17, 0x17, 0x1d, 0x0a, 0x74, 0x0a, 0x79, 0x00, 0x0e, 0x48, 0x23, + 0x4e, 0x32, 0x53, 0x74, 0x78, + (byte)0xf0, + (byte)0xa9, + (byte)0x8b, + (byte)0xb9, 0x03, 0x68, 0x3b, 0x7b, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x02, 0x67, 0x0e, 0x7a, 0x00, 0x00, 0x00, 0x02, 0x74, 0x37, + 0x79, 0x00, 0x09, 0x6f, 0x11, 0x60, 0x3c, 0x24, 0x13, 0x16, 0x25, 0x35, + 0x78, 0x01, 0x6a, + (byte)0xff, (byte)0xf9, (byte)0xc0, 0x69, 0x19, 0x0b, (byte)0x8a, + 0x05, (byte)0xff, + }; + o = CBORObject.DecodeFromBytes(bytes, + new CBOREncodeOptions("allowduplicatekeys=1")); + CBORTestCommon.AssertRoundTrip(o); } @Test @@ -1209,27 +1392,19 @@ public void TestCompareB() { Double.NEGATIVE_INFINITY, 1956611); CBORTestCommon.AssertRoundTrip(cbor); - cbor = - - CBORObject.FromObjectAndTag( + cbor = CBORObject.FromObjectAndTag( ToObjectTest.TestToFromObjectRoundTrip(Double.NEGATIVE_INFINITY), 1956611); CBORTestCommon.AssertRoundTrip(cbor); - cbor = - - CBORObject.FromObjectAndTag( + cbor = CBORObject.FromObjectAndTag( ToObjectTest.TestToFromObjectRoundTrip(CBORTestCommon.FloatNegInf), 1956611); CBORTestCommon.AssertRoundTrip(cbor); - cbor = - - CBORObject.FromObjectAndTag( + cbor = CBORObject.FromObjectAndTag( ToObjectTest.TestToFromObjectRoundTrip(CBORTestCommon.DecNegInf), 1956611); CBORTestCommon.AssertRoundTrip(cbor); - cbor = - - CBORObject.FromObjectAndTag( + cbor = CBORObject.FromObjectAndTag( ToObjectTest.TestToFromObjectRoundTrip(CBORTestCommon.FloatNegInf), 1956611); CBORTestCommon.AssertRoundTrip(cbor); @@ -1255,27 +1430,6 @@ public void TestEquivJSON() { TestEquivJSONOne(jsonBytes); } - public static void TestEquivJSONOne(byte[] bytes) { - CBORObject cbo = CBORObject.FromJSONBytes(bytes); - if (!(cbo != null)) { - Assert.fail(); - } - CBORObject cbo2 = CBORObject.FromJSONString(cbo.ToJSONString()); - if (!(cbo2 != null)) { - Assert.fail(); - } - if (!cbo.equals(cbo2)) { - Assert.assertEquals("differs for JSONString",cbo,cbo2); - } - cbo2 = CBORObject.FromJSONBytes(cbo.ToJSONBytes()); - if (!(cbo2 != null)) { - Assert.fail(); - } - if (!cbo.equals(cbo2)) { - Assert.assertEquals("differs for JSONBytes",cbo,cbo2); - } - } - @Test public void TestDecFracCompareIntegerVsBigFraction() { CBORObject o1 = null; diff --git a/src/test/java/com/upokecenter/test/RandomObjects.java b/src/test/java/com/upokecenter/test/RandomObjects.java index da72e182..671ceead 100644 --- a/src/test/java/com/upokecenter/test/RandomObjects.java +++ b/src/test/java/com/upokecenter/test/RandomObjects.java @@ -12,6 +12,9 @@ import com.upokecenter.util.*; import com.upokecenter.numbers.*; + /** + * Description of RandomObjects. + */ public final class RandomObjects { private RandomObjects() { }