Skip to content

Commit

Permalink
Merge pull request #4 from XYOracleNetwork/develop
Browse files Browse the repository at this point in the history
To JSON and Reset
  • Loading branch information
carterharrison authored Nov 21, 2018
2 parents 324848e + fcca678 commit 64e4490
Show file tree
Hide file tree
Showing 8 changed files with 132 additions and 60 deletions.
4 changes: 3 additions & 1 deletion build.gradle
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@


apply plugin: 'kotlin'
apply plugin: 'java'
apply plugin: "jacoco"


group 'com.github.XYOracleNetwork'
version '1.0-SNAPSHOT'

Expand Down Expand Up @@ -31,7 +34,6 @@ buildscript {
}
dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.3.0"

classpath "org.junit.platform:junit-platform-gradle-plugin:1.0.0-M4"
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
package network.xyo.sdkobjectmodelkotlin.objects

import network.xyo.sdkobjectmodelkotlin.objects.sets.XyoObjectIterator
import network.xyo.sdkobjectmodelkotlin.schema.XyoObjectSchema
import org.json.JSONArray
import org.json.JSONObject
import java.lang.StringBuilder
import java.nio.ByteBuffer


/**
* An object for creating Xyo Objects.
*/
@ExperimentalUnsignedTypes
object XyoObjectCreator {

/**
Expand All @@ -24,16 +27,16 @@ object XyoObjectCreator {
/**
* Gets the best size of size to use.
*/
fun getSmartSize (sizeOfItem : UInt) : Int {
if (sizeOfItem + 1.toUInt() <= UByte.MAX_VALUE) {
fun getSmartSize (sizeOfItem : Int) : Int {
if (sizeOfItem + 1 <= 255) {
return 1
}

if (sizeOfItem + 2.toUInt() <= UShort.MAX_VALUE) {
if (sizeOfItem + 2 <= 65535) {
return 2
}

if (sizeOfItem + 4.toUInt() <= UInt.MAX_VALUE) {
if (sizeOfItem + 4 <= Int.MAX_VALUE) {
return 4
}

Expand All @@ -46,4 +49,29 @@ object XyoObjectCreator {
return item.copyOfRange(2 + objectSchema.sizeIdentifier, item.size)
}

fun itemToJSON (item : ByteArray) : JSONArray {
val itemHeader = XyoObjectSchema.createFromHeader(item.copyOfRange(0, 2))
val rootJsonObject = JSONArray()

if (itemHeader.isIterable) {
for (subItem in XyoObjectIterator(item)) {
rootJsonObject.put(itemToJSON(subItem))
}
} else {
rootJsonObject.put(item.toHexString())
}

return rootJsonObject
}

private fun ByteArray.toHexString(): String {
val builder = StringBuilder()
val it = this.iterator()
builder.append("0x")
while (it.hasNext()) {
builder.append(String.format("%02X", it.next()))
}

return builder.toString()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,13 @@ package network.xyo.sdkobjectmodelkotlin.objects.sets

import network.xyo.sdkobjectmodelkotlin.exceptions.XyoObjectIteratorException
import network.xyo.sdkobjectmodelkotlin.schema.XyoObjectSchema
import java.lang.reflect.Array
import java.nio.Buffer
import java.nio.ByteBuffer
import java.util.ArrayList
import kotlin.experimental.and

@ExperimentalUnsignedTypes
/**
* An Iterator for iterating over sets created with XyoObjectSetCreator.
*/
class XyoObjectIterator (private val item : ByteArray) : Iterator<ByteArray> {
open class XyoObjectIterator (private val item : ByteArray) : Iterator<ByteArray> {
private var globalSchema : XyoObjectSchema? = null
private var currentOffset = 0

Expand All @@ -26,9 +23,11 @@ class XyoObjectIterator (private val item : ByteArray) : Iterator<ByteArray> {
* Gets the next item in the set.
*/
override fun next(): ByteArray {

val startingIndex = currentOffset
val schemaOfItem = globalSchema ?: getNextHeader()
val sizeOfObject = readSizeOfObject(schemaOfItem.sizeIdentifier)
checkBounds(sizeOfObject - schemaOfItem.sizeIdentifier)

if (globalSchema == null) {
currentOffset = startingIndex + sizeOfObject + 2
Expand All @@ -42,18 +41,24 @@ class XyoObjectIterator (private val item : ByteArray) : Iterator<ByteArray> {
return buffer.array()
}

private fun checkBounds (size : Int) {
if (size + currentOffset > item.size) {
throw XyoObjectIteratorException("Out of size. Length: ${item.size}, To Read: ${size + currentOffset}")
}
}

/**
* Reads the size of the object at the current offset.
*/
private fun readSizeOfObject (sizeToReadForSize : Int) : Int {
val buffer = ByteBuffer.allocate(sizeToReadForSize)
checkBounds(sizeToReadForSize)
currentOffset += sizeToReadForSize
buffer.put(item.copyOfRange(currentOffset - sizeToReadForSize, currentOffset))

when (sizeToReadForSize) {
1 -> return buffer[0].toInt()
2 -> return buffer.getShort(0).toInt()
1 -> return (buffer[0] and 0xFF.toByte()).toInt()
2 -> return (buffer.getShort(0).toInt() and 0xFFFF)
4 -> return buffer.getInt(0)
}

Expand All @@ -64,11 +69,7 @@ class XyoObjectIterator (private val item : ByteArray) : Iterator<ByteArray> {
* Gets the next object schema at the current offset.
*/
private fun getNextHeader () : XyoObjectSchema {
if ((currentOffset + 2) > item.size) {
throw XyoObjectIteratorException("Out of size, trying to read header at offset: $currentOffset. " +
"Max: ${item.size}")
}

checkBounds(2)
currentOffset += 2
return XyoObjectSchema.createFromHeader(item.copyOfRange(currentOffset - 2, currentOffset))
}
Expand All @@ -87,6 +88,22 @@ class XyoObjectIterator (private val item : ByteArray) : Iterator<ByteArray> {
return next
}

operator fun get(type: Byte): Array<ByteArray> {
val itemsThatFollowTheType = ArrayList<ByteArray>()

while (hasNext()) {
val next = next()
val nextHeader = XyoObjectSchema.createFromHeader(next.copyOfRange(0, 2))

if (nextHeader.id == type) {
itemsThatFollowTheType.add(next)
}
}

reset()
return itemsThatFollowTheType.toTypedArray()
}

val size : Int
get() {
var i = 0
Expand All @@ -96,11 +113,15 @@ class XyoObjectIterator (private val item : ByteArray) : Iterator<ByteArray> {
i++
}

currentOffset = 0
readOwnHeader()
reset()
return i
}

private fun reset() {
currentOffset = 0
readOwnHeader()
}

private fun readOwnHeader () {
val setHeader = getNextHeader()
val totalSize = readSizeOfObject(setHeader.sizeIdentifier)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ package network.xyo.sdkobjectmodelkotlin.schema
import network.xyo.sdkobjectmodelkotlin.exceptions.XyoSchemaException
import org.json.JSONObject
import java.math.BigInteger
import kotlin.experimental.and
import kotlin.experimental.or

/**
* A information class used to represent all identifying factors in the XyoObjectModel. This is typically represented
Expand Down Expand Up @@ -60,14 +62,13 @@ abstract class XyoObjectSchema {
*
* @throws XyoSchemaException when the sizeIdentifier is not 1, 2, 4, 8, or null
*/
@ExperimentalUnsignedTypes
private val sizeIdentifierByte : UByte
private val sizeIdentifierByte : Byte
get() {
when (sizeIdentifier) {
1 -> return (0x00.toUByte())
2 -> return (0x40.toUByte())
4 -> return (0x80.toUByte())
8 -> return (0xC0.toUByte())
1 -> return (0x00)
2 -> return (0x40)
4 -> return (0x80.toByte())
8 -> return (0xC0.toByte())
}
throw XyoSchemaException("Invalid Size $sizeIdentifier")
}
Expand All @@ -76,35 +77,32 @@ abstract class XyoObjectSchema {
* The 3rd most significant bit that represent sif the object is iterable. This value is obtained from
* isIterable.
*/
@ExperimentalUnsignedTypes
private val iterableByte : UByte
private val iterableByte : Byte
get() {
if (isIterable) {
return 0x20.toUByte()
return 0x20
}

return 0x00.toUByte()
return 0x00
}

/**
* The 4th most significant bit that represents if the following object is typed.
*/
@ExperimentalUnsignedTypes
private val typedByte : UByte
private val typedByte : Byte
get() {
if (isTyped) {
return 0x00.toUByte() or (0x10.toUByte())
return (0x00.toByte() or 0x10.toByte())
}

return 0x00.toUByte()
return 0x00.toByte()
}

/**
* The first byte of the object. This value contains the sizeIdentifierByte, the iterableByte, the typedByte, and
* four reserved bits (4 least significant bits).
*/
@ExperimentalUnsignedTypes
val encodingCatalogue : UByte
val encodingCatalogue : Byte
get() {
return sizeIdentifierByte or iterableByte or typedByte
}
Expand All @@ -113,72 +111,71 @@ abstract class XyoObjectSchema {
* The header of the schema or object, with the first byte being the encodingCatalogue, and the second catalogue ]
* being the ID of the object.
*/
@ExperimentalUnsignedTypes
val header : ByteArray
get() {
return byteArrayOf(encodingCatalogue.toByte(), id)
return byteArrayOf(encodingCatalogue, id)
}

companion object {

// This method creates a schema object with given header.
@ExperimentalUnsignedTypes
fun createFromHeader (byteArray: ByteArray) : XyoObjectSchema {
if (byteArray.size != 2) {
throw XyoSchemaException("Expected header size to be 2, saw: ${byteArray.size}")
}

return object : XyoObjectSchema() {
override val id: Byte
get() = byteArray[1]

override val isIterable: Boolean
get() = readIsIterable(byteArray[0].toUByte())
get() = readIsIterable(byteArray[0])

override val isTyped: Boolean
get() = readIsTyped(byteArray[0].toUByte())
get() = readIsTyped(byteArray[0])

override val meta: XyoObjectSchemaMeta? = null

override val sizeIdentifier: Int
get() = readSizeIdentifierFromEncodingCatalogue(byteArray[0].toUByte())
get() = readSizeIdentifierFromEncodingCatalogue(byteArray[0])
}
}


/**
* Checks if the encodingCatalogue is typed. The 3rd most significant bit.
*/
@ExperimentalUnsignedTypes
private fun readIsTyped (encodingCatalogue: UByte) : Boolean {
return (encodingCatalogue and 0x10.toUByte()).toInt() != 0
private fun readIsTyped (encodingCatalogue: Byte) : Boolean {
return (encodingCatalogue and 0x10).toInt() != 0
}

/**
* Checks if the object is iterable. The 4th most significant bit.
*/
@ExperimentalUnsignedTypes
private fun readIsIterable (encodingCatalogue: UByte) : Boolean {
return (encodingCatalogue and 0x20.toUByte()).toInt() != 0
private fun readIsIterable (encodingCatalogue: Byte) : Boolean {
return (encodingCatalogue and 0x20).toInt() != 0
}

/**
* Checks the size identifier from the encodingCatalogue. The 2 most significant bits.
*/
@ExperimentalUnsignedTypes
private fun readSizeIdentifierFromEncodingCatalogue (encodingCatalogue: UByte) : Int {
private fun readSizeIdentifierFromEncodingCatalogue (encodingCatalogue: Byte) : Int {

// masking the first two bits to get the result
// 0xC0 == 11000000
if (encodingCatalogue and 0xC0.toUByte() == 0x00.toUByte()) {
if (encodingCatalogue and 0xC0.toByte() == 0x00.toByte()) {
return 1
}

if (encodingCatalogue and 0xC0.toUByte() == 0x40.toUByte()) {
if (encodingCatalogue and 0xC0 .toByte() == 0x40.toByte()) {
return 2
}

if (encodingCatalogue and 0xC0.toUByte() == 0x80.toUByte()) {
if (encodingCatalogue and 0xC0.toByte() == 0x80.toByte()) {
return 4
}

if (encodingCatalogue and 0xC0.toUByte() == 0xC0.toUByte()) {
if (encodingCatalogue and 0xC0.toByte() == 0xC0.toByte()) {
return 8
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,28 +5,27 @@ import network.xyo.sdkobjectmodelkotlin.schema.XyoObjectSchema
import org.junit.Assert
import org.junit.Test

@ExperimentalUnsignedTypes
class XyoObjectCreatorTest {

@Test
fun testSmartSizeForByte () {
val sizeOfImageryObject = 254
val bestWayToEncodeSize = 1
Assert.assertEquals(bestWayToEncodeSize, XyoObjectCreator.getSmartSize(sizeOfImageryObject.toUInt()))
Assert.assertEquals(bestWayToEncodeSize, XyoObjectCreator.getSmartSize(sizeOfImageryObject))
}

@Test
fun testSmartSizeForShort () {
val sizeOfImageryObject = 64_000
val bestWayToEncodeSize = 2
Assert.assertEquals(bestWayToEncodeSize, XyoObjectCreator.getSmartSize(sizeOfImageryObject.toUInt()))
Assert.assertEquals(bestWayToEncodeSize, XyoObjectCreator.getSmartSize(sizeOfImageryObject))
}

@Test
fun testSmartSizeForInt () {
val sizeOfImageryObject = 66_000
val bestWayToEncodeSize = 4
Assert.assertEquals(bestWayToEncodeSize, XyoObjectCreator.getSmartSize(sizeOfImageryObject.toUInt()))
Assert.assertEquals(bestWayToEncodeSize, XyoObjectCreator.getSmartSize(sizeOfImageryObject))
}

@Test
Expand Down
Loading

0 comments on commit 64e4490

Please sign in to comment.