├── .gitignore ├── manifest ├── source ├── test │ ├── TestMathUtils.brs │ ├── TestUtil.brs │ ├── TestStrings.brs │ ├── TestUrlUtils.brs │ ├── TestArray.brs │ ├── TestPrioQueue.brs │ ├── TestByteReader.brs │ └── TestBitfieldParser.brs ├── main.brs └── main │ ├── StringUtils.brs │ ├── Time.brs │ ├── UrlUtils.brs │ ├── MathUtils.brs │ ├── ArrayUtils.brs │ ├── BitFieldParser.brs │ ├── PriorityQueue.brs │ └── ByteArrayReader.brs ├── README.md ├── deploy.sh └── LICENSE /.gitignore: -------------------------------------------------------------------------------- 1 | .vs 2 | timestamp 3 | -------------------------------------------------------------------------------- /manifest: -------------------------------------------------------------------------------- 1 | title=Brightscript-Utilities 2 | major_version=1 3 | minor_version=0 4 | build_version=0 5 | -------------------------------------------------------------------------------- /source/test/TestMathUtils.brs: -------------------------------------------------------------------------------- 1 | function mathUtilTests() 2 | printHeader("Math Utils") 3 | mathsUtil = initMathsUtil() 4 | checkSuccess("xorTest", xorTest(mathsUtil)) 5 | end function 6 | 7 | function xorTest(mathsUtil) 8 | shouldBe2 = mathsUtil.xor(3, 1) 9 | shouldBe0 = mathsUtil.xor(255, 255) 10 | return shouldBe2 = 2 and shouldBe0 = 0 11 | end function 12 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Brightscript-Utilities 2 | A repo for brightscript utilities and tools 3 | 4 | This repo consists of patterns and functions not natively provided by Roku or brightscript including: 5 | * Generic Priority Queues 6 | * Generic Array Sorting 7 | * to string functions for boolean variables 8 | * epoch data time representation in milliseconds 9 | * Byte Array Reader wrapper layer 10 | * Bitfield Parser 11 | * Utility to format objects for urls 12 | 13 | To run tests: 14 | sh deploy.sh 15 | -------------------------------------------------------------------------------- /source/main.brs: -------------------------------------------------------------------------------- 1 | '**************************************************************************** 2 | '* Licensed under the Apache License, Version 2.0 (the "License"); * 3 | '* you may not use this file except in compliance with the License. * 4 | '* You may obtain a copy of the License at * 5 | '* http://www.apache.org/licenses/LICENSE-2.0 * 6 | '* Unless required by applicable law or agreed to in writing, software * 7 | '* distributed under the License is distributed on an "AS IS" BASIS, * 8 | '* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * 9 | '* See the License for the specific language governing permissions and * 10 | '* limitations under the License. * 11 | '**************************************************************************** 12 | sub Main() 13 | bitfieldParserTests() 14 | stringsTest() 15 | arrayTests() 16 | prioQueueTests() 17 | byteArrayTests() 18 | urlUtilsTests() 19 | mathUtilTests() 20 | end sub 21 | -------------------------------------------------------------------------------- /deploy.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | ROKU_DEV_TARGET=$1 3 | ROKU_DEV_PASS=$2 4 | 5 | if [ -z "$1" ] 6 | then 7 | echo ERROR: Missing Roku IP Address argument. Please pass the IP address of your Roku box as the first argument to the deploy script 1>&2 8 | exit 1 # terminate and indicate error 9 | fi 10 | 11 | echo "Wake up device" 12 | 13 | # wake up/interrupt Roku - workaround for fw5.4 crash 14 | curl -sS -d '' http://$ROKU_DEV_TARGET:8060/keypress/Home 15 | curl -sS -d '' http://$ROKU_DEV_TARGET:8060/keypress/Home 16 | 17 | echo "build & zip" 18 | 19 | # build. zip _must_ change for Roku to accept re-deploy (grr!) 20 | cd -- "$(dirname "$0")" 21 | touch timestamp 22 | zip -9 -r bundle source manifest 23 | 24 | echo "deploy to roku device" 25 | # deploy 26 | curl -f -sS --user rokudev:$ROKU_DEV_PASS --anyauth -F "mysubmit=Install" -F "archive=@bundle.zip" -F "passwd=" http://$ROKU_DEV_TARGET/plugin_install \ 27 | | python -c 'import sys, re; print "\n".join(re.findall("(.*?)", sys.stdin.read(), re.DOTALL))' 28 | 29 | echo "Executing tests in 1 second..." 30 | 31 | echo "Cleaning up bundle.zip output" 32 | (sleep 3; rm bundle.zip) 33 | -------------------------------------------------------------------------------- /source/main/StringUtils.brs: -------------------------------------------------------------------------------- 1 | '**************************************************************************** 2 | '* Licensed under the Apache License, Version 2.0 (the "License"); * 3 | '* you may not use this file except in compliance with the License. * 4 | '* You may obtain a copy of the License at * 5 | '* http://www.apache.org/licenses/LICENSE-2.0 * 6 | '* Unless required by applicable law or agreed to in writing, software * 7 | '* distributed under the License is distributed on an "AS IS" BASIS, * 8 | '* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * 9 | '* See the License for the specific language governing permissions and * 10 | '* limitations under the License. * 11 | '**************************************************************************** 12 | function initializeStringsUtil() 13 | stringsUtil = {} 14 | 15 | stringsUtil.booleanToString = function(input as boolean) as string 16 | if input then return "True" 17 | return "False" 18 | end function 19 | 20 | 21 | return stringsUtil 22 | end function 23 | -------------------------------------------------------------------------------- /source/test/TestUtil.brs: -------------------------------------------------------------------------------- 1 | '**************************************************************************** 2 | '* Licensed under the Apache License, Version 2.0 (the "License"); * 3 | '* you may not use this file except in compliance with the License. * 4 | '* You may obtain a copy of the License at * 5 | '* http://www.apache.org/licenses/LICENSE-2.0 * 6 | '* Unless required by applicable law or agreed to in writing, software * 7 | '* distributed under the License is distributed on an "AS IS" BASIS, * 8 | '* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * 9 | '* See the License for the specific language governing permissions and * 10 | '* limitations under the License. * 11 | '**************************************************************************** 12 | function checkSuccess(funcName as string, success as boolean) as void 13 | if success then print funcName; ": passed" 14 | if not success then print funcName; ": failed" 15 | end function 16 | 17 | function printHeader(funcName) as void 18 | print 19 | print funcName 20 | print "==============================" 21 | end function 22 | -------------------------------------------------------------------------------- /source/main/Time.brs: -------------------------------------------------------------------------------- 1 | '**************************************************************************** 2 | '* Licensed under the Apache License, Version 2.0 (the "License"); * 3 | '* you may not use this file except in compliance with the License. * 4 | '* You may obtain a copy of the License at * 5 | '* http://www.apache.org/licenses/LICENSE-2.0 * 6 | '* Unless required by applicable law or agreed to in writing, software * 7 | '* distributed under the License is distributed on an "AS IS" BASIS, * 8 | '* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * 9 | '* See the License for the specific language governing permissions and * 10 | '* limitations under the License. * 11 | '**************************************************************************** 12 | function intializeTimeUtil() as object 13 | timeUtil = {} 14 | 15 | 'Input: 16 | ' date time object. Defaults to new object creation 17 | 'Output: 18 | ' 64 bit long integer epoch time 19 | timeUtil.getEpochTime = function(date=createObject("roDateTime") as object) as LongInteger 20 | return date.AsSeconds()*1000& + date.getMilliseconds() 21 | end function 22 | 23 | return timeUtil 24 | 25 | end function 26 | -------------------------------------------------------------------------------- /source/test/TestStrings.brs: -------------------------------------------------------------------------------- 1 | '**************************************************************************** 2 | '* Licensed under the Apache License, Version 2.0 (the "License"); * 3 | '* you may not use this file except in compliance with the License. * 4 | '* You may obtain a copy of the License at * 5 | '* http://www.apache.org/licenses/LICENSE-2.0 * 6 | '* Unless required by applicable law or agreed to in writing, software * 7 | '* distributed under the License is distributed on an "AS IS" BASIS, * 8 | '* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * 9 | '* See the License for the specific language governing permissions and * 10 | '* limitations under the License. * 11 | '**************************************************************************** 12 | function stringsTest() 13 | printHeader("Strings Test") 14 | stringsUtil = initializeStringsUtil() 15 | checkSuccess("testBooleanToStringTrue", testBooleanToStringTrue(stringsUtil)) 16 | checkSuccess("testBooleanToStringFalse", testBooleanToStringFalse(stringsUtil)) 17 | end function 18 | 19 | function testBooleanToStringTrue(stringsUtil as object) as boolean 20 | result = stringsUtil.booleanToString(true) 21 | return result = "True" 22 | end function 23 | 24 | function testBooleanToStringFalse(stringsUtil as object) as boolean 25 | result = stringsUtil.booleanToString(false) 26 | return result = "False" 27 | end function 28 | -------------------------------------------------------------------------------- /source/test/TestUrlUtils.brs: -------------------------------------------------------------------------------- 1 | '**************************************************************************** 2 | '* Licensed under the Apache License, Version 2.0 (the "License"); * 3 | '* you may not use this file except in compliance with the License. * 4 | '* You may obtain a copy of the License at * 5 | '* http://www.apache.org/licenses/LICENSE-2.0 * 6 | '* Unless required by applicable law or agreed to in writing, software * 7 | '* distributed under the License is distributed on an "AS IS" BASIS, * 8 | '* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * 9 | '* See the License for the specific language governing permissions and * 10 | '* limitations under the License. * 11 | '**************************************************************************** 12 | function urlUtilsTests() 13 | printHeader("Url Utils Test") 14 | checkSuccess("testAssociativeArrayToQueryString", testAssociativeArrayToQueryString()) 15 | end function 16 | 17 | function testAssociativeArrayToQueryString() as boolean 18 | util = initializeUrlUtils() 19 | func = function() 20 | print "Hello World!" 21 | end function 22 | 23 | AA = { 24 | a: "v1" 25 | b: 1 26 | c: 2.1 27 | d: func 28 | e: {} 29 | f: [] 30 | g: invalid 31 | h: box(8) 32 | 33 | } 34 | queryString = util.concatAaQueryParamList(AA) 35 | return queryString = "a=v1&b=1&c=2.1&g=null&h=8" 36 | 37 | end function 38 | -------------------------------------------------------------------------------- /source/main/UrlUtils.brs: -------------------------------------------------------------------------------- 1 | 2 | '**************************************************************************** 3 | '* Licensed under the Apache License, Version 2.0 (the "License"); * 4 | '* you may not use this file except in compliance with the License. * 5 | '* You may obtain a copy of the License at * 6 | '* http://www.apache.org/licenses/LICENSE-2.0 * 7 | '* Unless required by applicable law or agreed to in writing, software * 8 | '* distributed under the License is distributed on an "AS IS" BASIS, * 9 | '* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * 10 | '* See the License for the specific language governing permissions and * 11 | '* limitations under the License. * 12 | '**************************************************************************** 13 | function initializeUrlUtils() as object 14 | UrlUtils = {} 15 | UrlUtils.invalidString = "null" 16 | UrlUtils.skipFunctions = true 17 | 18 | 'Input: 19 | ' Associative Array of Objects to be concatenated 20 | ' e.g. { 21 | ' a: v1, 22 | ' b: v2, 23 | ' c: v3 24 | ' } 25 | 'Output: 26 | ' formatted query string e.g. 27 | ' "a=v1&b=v2&c=v3" 28 | ' 29 | ' Will only add keys that implement the ifToStr interface 30 | UrlUtils.concatAaQueryParamList = function(AA) 31 | if type(AA) <> "roAssociativeArray" then return "" 32 | 33 | outString = "" 34 | keys = AA.keys() 35 | length = keys.count() - 1 36 | 37 | for i = 0 to length - 1 38 | 39 | key = keys[i] 40 | value = AA[key] 41 | if value = invalid 42 | outString = outString + key.toStr() + "=" + m.invalidString + "&" 43 | else if getInterface(value, "ifFunction") <> invalid and m.skipFunctions 44 | 45 | else if getInterface(key, "ifToStr") <> invalid and getInterface(value, "ifToStr") <> invalid 46 | outString = outString + key.toStr() + "=" + value.toStr() + "&" 47 | end if 48 | 49 | end for 50 | 51 | key = keys[length] 52 | value = AA[key] 53 | 54 | if value = invalid 55 | outString = outString + key.toStr() + "=" + m.invalidString 56 | else if getInterface(key, "ifToStr") <> invalid and getInterface(value, "ifToStr") <> invalid 57 | outString = outString + key.toStr() + "=" + value.toStr() 58 | end if 59 | 60 | return outString 61 | end function 62 | return UrlUtils 63 | end function 64 | -------------------------------------------------------------------------------- /source/test/TestArray.brs: -------------------------------------------------------------------------------- 1 | '**************************************************************************** 2 | '* Licensed under the Apache License, Version 2.0 (the "License"); * 3 | '* you may not use this file except in compliance with the License. * 4 | '* You may obtain a copy of the License at * 5 | '* http://www.apache.org/licenses/LICENSE-2.0 * 6 | '* Unless required by applicable law or agreed to in writing, software * 7 | '* distributed under the License is distributed on an "AS IS" BASIS, * 8 | '* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * 9 | '* See the License for the specific language governing permissions and * 10 | '* limitations under the License. * 11 | '**************************************************************************** 12 | function arrayTests() 13 | 14 | printHeader("Array Tests") 15 | arrayUtil = initArrayUtil() 16 | checkSuccess("testInPlaceInsertionSort", testInPlaceInsertionSort(arrayUtil)) 17 | checkSuccess("testArrayCopy", testArrayCopy(arrayUtil)) 18 | checkSuccess("testBinarySearch", testBinarySearch(arrayUtil)) 19 | 20 | end function 21 | 22 | function initializeTest() as object 23 | testObject = {} 24 | testObject.array = [10, 5, 15, 25, 20] 25 | testObject.arrayLong = [] 26 | for i = 0 to 100 27 | testObject.arrayLong.push(i*5) 28 | end for 29 | 30 | testObject.basicGreaterThan = function (a as integer, b as integer) as boolean 31 | return a > b 32 | end function 33 | 34 | testObject.basicLessThan = function (a as integer, b as integer) as boolean 35 | return a < b 36 | end function 37 | 38 | testObject.basicEqualTo = function (a as integer, b as integer) as boolean 39 | return a = b 40 | end function 41 | 42 | return testObject 43 | end function 44 | 45 | function testArrayCopy(arrayUtil as object ) as boolean 46 | testObject = initializeTest() 47 | arrayCopy = arrayUtil.copyArray(testObject.array) 48 | result = arrayCopy[0] = testObject.array[0] and arrayCopy[1] = testObject.array[1] and arrayCopy[2] = testObject.array[2] and arrayCopy[3] = testObject.array[3] 49 | return result 50 | end function 51 | 52 | function testInPlaceInsertionSort(arrayUtil as object) as boolean 53 | testObject = initializeTest() 54 | arrayUtil.inPlaceInsertionSort(testObject.array, testObject.basicGreaterThan) 55 | 56 | result = testObject.array[0] = 5 and testObject.array[1] = 10 and testObject.array[2] = 15 and testObject.array[3] = 20 and testObject.array[4] = 25 57 | return result 58 | end function 59 | 60 | function testBinarySearch(arrayUtil as object) as boolean 61 | testObject = initializeTest() 62 | index = arrayUtil.binarySearch(testObject.arrayLong, 50, testObject.basicLessThan, testObject.basicEqualTo) 63 | return testObject.arrayLong[index] = 50 64 | end function 65 | 66 | function testFisherYatesShuffle() as boolean 67 | 68 | return false 69 | 70 | end function 71 | -------------------------------------------------------------------------------- /source/main/MathUtils.brs: -------------------------------------------------------------------------------- 1 | '**************************************************************************** 2 | '* Licensed under the Apache License, Version 2.0 (the "License"); * 3 | '* you may not use this file except in compliance with the License. * 4 | '* You may obtain a copy of the License at * 5 | '* http://www.apache.org/licenses/LICENSE-2.0 * 6 | '* Unless required by applicable law or agreed to in writing, software * 7 | '* distributed under the License is distributed on an "AS IS" BASIS, * 8 | '* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * 9 | '* See the License for the specific language governing permissions and * 10 | '* limitations under the License. * 11 | '**************************************************************************** 12 | function initMathsUtil() 13 | mathsUtil = {} 14 | 15 | '== CONSTANTS ==' 16 | mathsUtil["_8_BIT_INT_MAX"] = 127% 17 | mathsUtil["_8_BIT_INT_MIN"] = -128% 18 | mathsUtil["_16_BIT_INT_MAX"] = 32767% 19 | mathsUtil["_16_BIT_INT_MIN"] = -32768% 20 | mathsUtil["_32_BIT_INT_MAX"] = 2147483647% 21 | mathsUtil["_32_BIT_INT_MIN"] = -2147483648% 22 | mathsUtil["_64_BIT_INT_MAX"] = 9223372036854775807& 23 | mathsUtil["_64_BIT_INT_MAX"] = -9223372036854775808& 24 | mathsUtil["_PI_SINGLE"] = 3.1415927410125732421875! 25 | mathsUtil["_PI_DOUBLE"] = 3.141592653589793115997963468544185161590576171875# 26 | mathsUtil["_E_SINGLE"] = 2.71828174591064453125! 27 | mathsUtil["_E_DOUBLE"] = 2.718281828459045090795598298427648842334747314453125# 28 | 29 | 'ceiling function 30 | ' Input must be float or double returns invalid otherwise 31 | mathsUtil.ceiling = function (unit) as integer 32 | if (getInterface(unit, "ifFloat") = invalid) or (type(unit) <> "Double") return invalid 33 | i = int(unit) 34 | if i < unit then i++ 35 | return i 36 | end function 37 | 38 | mathsUtil.floor = function (unit) as integer 39 | if (getInterface(unit, "ifFloat") = invalid) or (type(unit) <> "Double") return invalid 40 | return int(unit) 41 | end function 42 | 43 | mathsUtil.min = function (A, B) 44 | if A <= B then return A 45 | return B 46 | end function 47 | 48 | mathsUtil.max = function (A, B) 49 | if A >= B then return A 50 | return B 51 | end function 52 | 53 | mathsUtil.xor = function(A, B) 54 | return (A or B) and not (A and B) 55 | end function 56 | 57 | mathsUtil.random = function(upperBound as integer, lowerBound=0 as integer) as integer 58 | 'shift random window over from (0, 1) -> (0, upperBound - lowerBound + 1) 59 | randomValue = rnd(upperBound - lowerBound + 1) 60 | 'reshift random window to [lowerBound, lowerBound] 61 | randomValue = randomValue + lowerBound - 1 62 | return randomValue 63 | 64 | end function 65 | 66 | mathsUtil.log = function(value as float, base as float) as float 67 | return log(value)/log(base) 68 | end function 69 | 70 | return mathsUtil 71 | 72 | end function 73 | -------------------------------------------------------------------------------- /source/test/TestPrioQueue.brs: -------------------------------------------------------------------------------- 1 | '**************************************************************************** 2 | '* Licensed under the Apache License, Version 2.0 (the "License"); * 3 | '* you may not use this file except in compliance with the License. * 4 | '* You may obtain a copy of the License at * 5 | '* http://www.apache.org/licenses/LICENSE-2.0 * 6 | '* Unless required by applicable law or agreed to in writing, software * 7 | '* distributed under the License is distributed on an "AS IS" BASIS, * 8 | '* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * 9 | '* See the License for the specific language governing permissions and * 10 | '* limitations under the License. * 11 | '**************************************************************************** 12 | function prioQueueTests() 13 | printHeader("Prio Queue Test") 14 | myPrioQueue = initPriorityQueue(5) 15 | beforePrioQueue(myPrioQueue) 16 | checkSuccess("testPush",testPush(myPrioQueue)) 17 | beforePrioQueue(myPrioQueue) 18 | checkSuccess("testHeapify", testHeapify(myPrioQueue)) 19 | beforePrioQueue(myPrioQueue) 20 | checkSuccess("testPop", testPop(myPrioQueue)) 21 | beforePrioQueue(myPrioQueue) 22 | checkSuccess("testRemove", testRemove(myPrioQueue)) 23 | end function 24 | 25 | function beforePrioQueue(prioQueue as object) as void 26 | 'Max Heap 27 | prioQueue.comparator = function(A as integer, B as integer) as boolean 28 | return A > B 29 | end function 30 | prioQueue.clear() 31 | end function 32 | 33 | function testPush(prioQueue) as boolean 34 | '1,8,12,43,10,25,22 35 | prioQueue.push(1) 36 | prioQueue.push(3) 37 | prioQueue.push(5) 38 | prioQueue.push(4) 39 | prioQueue.push(6) 40 | prioQueue.push(13) 41 | prioQueue.push(10) 42 | prioQueue.push(9) 43 | prioQueue.push(8) 44 | prioQueue.push(15) 45 | prioQueue.push(17) 46 | result = true 47 | for each index in prioQueue.data 48 | result = result and (prioQueue.data[0] >= index ) 49 | end for 50 | if result = false then print "Test Push Failed!" 51 | return result 52 | end function 53 | 54 | function testHeapify(prioQueue) as boolean 55 | 56 | array = [1, 3, 5, 4, 6, 13, 10, 9, 8, 15, 17] 57 | prioQueue.setData(array) 58 | result = true 59 | for each index in prioQueue.data 60 | result = result and (prioQueue.data[0] >= index ) 61 | if result = false then print "value: "; index; " greater than "; prioQueue.data[0] 62 | end for 63 | if result = false then print "Test Heapify Failed! Value was: "; 64 | return result 65 | 66 | end function 67 | 68 | function testPop(prioQueue) as boolean 69 | 70 | array = [1, 3, 5, 4, 6, 13, 10, 9, 8, 15, 17] 71 | prioQueue.setData(array) 72 | maxValue = prioQueue.pop() 73 | nextValue = prioQueue.peek() 74 | 75 | if maxValue <> 17 then print "Test Pop Failed!, max value was: "; maxValue 76 | if nextValue <> 15 then print "Test Pop Failed! next heap head was not largest value. Value was: "; nextValue 77 | return maxValue = 17 and nextValue = 15 78 | 79 | end function 80 | 81 | function testRemove(prioQueue) as boolean 82 | 83 | array = [1, 3, 5, 4, 6, 13, 10, 9, 8, 15, 17] 84 | prioQueue.setData(array) 85 | prioQueue.remove(2) 86 | result = true 87 | queueSize = prioQueue.size() 88 | for i = 0 to queueSize 89 | 90 | leftChildIndex = prioQueue.getLeft(i) 91 | if leftChildIndex < queueSize 92 | result = result and prioQueue.data[i] > prioQueue.data[leftChildIndex] 93 | end if 94 | 95 | rightChildIndex = prioQueue.getRight(i) 96 | if rightChildIndex < queueSize 97 | result = result and prioQueue.data[i] > prioQueue.data[rightChildIndex] 98 | end if 99 | 100 | end for 101 | return result 102 | end function 103 | -------------------------------------------------------------------------------- /source/main/ArrayUtils.brs: -------------------------------------------------------------------------------- 1 | '**************************************************************************** 2 | '* Licensed under the Apache License, Version 2.0 (the "License"); * 3 | '* you may not use this file except in compliance with the License. * 4 | '* You may obtain a copy of the License at * 5 | '* http://www.apache.org/licenses/LICENSE-2.0 * 6 | '* Unless required by applicable law or agreed to in writing, software * 7 | '* distributed under the License is distributed on an "AS IS" BASIS, * 8 | '* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * 9 | '* See the License for the specific language governing permissions and * 10 | '* limitations under the License. * 11 | '**************************************************************************** 12 | 13 | function initArrayUtil() as object 14 | arrayUtil = {} 15 | 16 | 'copy objects 17 | arrayUtil.copyArray = function(array as object) as object 18 | 19 | size = array.count() 20 | newArray = createObject("roArray", size, false) 21 | 22 | for i = 0 to size - 1 23 | newArray[i] = array[i] 24 | end for 25 | 26 | return newArray 27 | end function 28 | 29 | 'Input: 30 | ' array to be sorted 31 | ' comparator function with signature f(a,b) as boolean 32 | ' with a and b of the same type as the array items 33 | arrayUtil.inPlaceInsertionSort = function(array as object, comparatorFunc as function) as void 34 | for i = 0 to array.count() - 1 35 | key = array[i] 36 | j = i - 1 37 | 38 | while j >= 0 and comparatorFunc(array[j], key) 39 | array[j + 1] = array[j] 40 | j-- 41 | end while 42 | 43 | array[j + 1] = key 44 | end for 45 | end function 46 | 47 | 'Input: 48 | ' comparator func must 49 | 'Output: 50 | ' integer index of the desired value or -1 51 | arrayUtil.binarySearch = function(array as object, value as dynamic, lessThanFunc as function, equalToFunc as function) as integer 52 | lowerBound = 0 53 | upperBound = array.count() 54 | while lowerBound <= upperBound 55 | middle = lowerBound + (upperBound - 1) / 2 56 | 57 | if equalToFunc(array[middle], value) then return middle 58 | 59 | if lessThanFunc(array[middle], value) 60 | lowerBound = middle + 1 61 | else 62 | upperBound = middle - 1 63 | end if 64 | 65 | end while 66 | 67 | return -1 68 | 69 | end function 70 | 71 | 72 | ' arrayUtil.fisherYatesShuffle = function(array as object, randomFunc as function) 73 | ' size = array.count() 74 | ' newArray = createObject("roArray", size, false) 75 | ' for i = size - 1 to 1 76 | ' 77 | ' j = randomFunc(0,) 78 | ' m.swap(array, i, j) 79 | ' end for 80 | ' end function 81 | 82 | arrayUtil.swap = function(array as object, a as integer, b as integer) 83 | 84 | 85 | tmp = array[a] 86 | array[a] = array[b] 87 | array[b] = tmp 88 | 89 | end function 90 | 91 | 'Input: 92 | ' a - a string of the form "1234" 93 | ' b - a string of the form "1234" 94 | ' 95 | 'Output: 96 | ' default a < b 97 | arrayUtil.compareStringByValueLessThan = function(a as string, b as string) as boolean 98 | return val(a.trim()) < val(b.trim()) 99 | end function 100 | 101 | 'Input: 102 | ' a - a string of the form "1234" 103 | ' b - a string of the form "1234" 104 | ' 105 | 'Output: 106 | ' default a > b 107 | arrayUtil.compareStringByValueGreaterThan = function(a as string, b as string) as boolean 108 | return val(a.trim()) > val(b.trim()) 109 | end function 110 | 111 | return arrayUtil 112 | 113 | end function 114 | -------------------------------------------------------------------------------- /source/main/BitFieldParser.brs: -------------------------------------------------------------------------------- 1 | ' Assumes big endianess 2 | ' that is to say msb is stored in the smallest index 3 | '| 0 | 1 |. . .| n | 4 | function newBitfieldParser() as object 5 | this = {} 6 | 7 | ' Member variables 8 | this["index"] = 0 9 | this["byteIndex"] = 0 10 | this["bits"] = 0 11 | this["data"] = invalid 12 | 13 | this["error"] = false 14 | this["reason"] = "" 15 | 16 | ' Private Member functions 17 | 18 | ' Public Member functions 19 | this.isInError = function() 20 | return m.error 21 | end function 22 | 23 | this.getIndex = function() 24 | return m.index 25 | end function 26 | 27 | this.getByteIndex = function() 28 | return m.byteIndex 29 | end function 30 | 31 | this.getBitCount = function() 32 | return m.bits 33 | end function 34 | 35 | this.initialize = function(ba) as void 36 | m.data = ba 37 | m.bits = ba.count() * 8 38 | end function 39 | 40 | this.hasBits = function() 41 | return m.index < m.bits - 1 42 | end function 43 | 44 | this.getBit = function() 45 | nextBit = m.index + 1 46 | if nextBit >= m.bits 47 | m.error = true 48 | m.reason = "getBit next bit is out of bounds" 49 | return invalid 50 | end if 51 | 52 | currentByte = m.data[m.byteIndex] 53 | intraByteIndex = m.index mod 8 54 | 55 | bitmask = 1 56 | 57 | value = (currentByte >> (7 - intraByteIndex)) and bitmask 58 | if m.index > 0 and intraByteIndex + 1 = 8 then m.byteIndex = m.byteIndex + 1 59 | m.index = nextBit 60 | 61 | return value 62 | 63 | end function 64 | 65 | 'retrieves the bit at the current index as a boolean flag 66 | this.getFlag = function() 67 | flag = m.getBit() 68 | if m.isInError() 69 | return invalid 70 | end if 71 | return flag = 1 72 | end function 73 | 74 | this.getBits32 = function(size as integer) 75 | if size > 32 76 | m.error = true 77 | m.reason = "getBits32 size is larger than a 32 bit integer can hold: " + size.toStr() 78 | end if 79 | 80 | if size >= m.bits - m.index 81 | m.error = true 82 | m.reason = "getBits32 size is larger than number of bits left in bytearray: size: " + size + " bits left " + m.bits - m.index 83 | end if 84 | value = 0 85 | 86 | 'get all bits to next byte boundary 87 | while (m.index mod 8) > 0 and size > 0 88 | value = value << 1 89 | value = value or m.getBit() 90 | size = size - 1 91 | end while 92 | 93 | 'If there are more than 8 bits left, shift bytes onto value 94 | while size >= 8 95 | value = value << 8 96 | value = value or m.data[m.byteIndex] 97 | m.byteIndex = m.byteIndex + 1 98 | size = size - 8 99 | end while 100 | 101 | 'get any bits left over that are mid last byte 102 | while size > 0 103 | value = value << 1 104 | value = value or m.getBit() 105 | size = size - 1 106 | end while 107 | 108 | return value 109 | end function 110 | 111 | this.getBits64 = function(size as integer) as longinteger 112 | if size > 64 113 | m.error = true 114 | m.reason = "getBits64 size is larger than a 64 bit integer can hold: " + size.toStr() 115 | end if 116 | 117 | if size >= m.bits - m.index 118 | m.error = true 119 | m.reason = "getBits64 size is larger than number of bits left in bytearray: size: " + size + " bits left " + m.bits - m.index 120 | end if 121 | 122 | value = 0& 123 | 124 | 'get all bits to next byte boundary 125 | while (m.index mod 8) > 0 and size > 0 126 | value = value << 1 127 | value = value or m.getBit() 128 | size = size - 1 129 | end while 130 | 131 | 'If there are more than 8 bits left, shift bytes onto value 132 | while size >= 8 133 | value = value << 8 134 | value = value or m.data[m.byteIndex] 135 | m.byteIndex = m.byteIndex + 1 136 | size = size - 8 137 | end while 138 | 139 | 'get any bits left over that are mid last byte 140 | while size > 0 141 | value = value << 1 142 | value = value or m.getBit() 143 | size = size - 1 144 | end while 145 | 146 | return value 147 | end function 148 | 149 | 150 | this.seek = function(size) 151 | if size > 0 152 | 153 | indexCopy = m.index 154 | 'calculate bit index 155 | m.index = m.index + size 156 | 157 | 'calculate byte index 158 | bitsLeftInByte = indexCopy mod 8 159 | if (bitsLeftInByte > 0 and (7 - bitsLeftInByte) < size ) then m.byteIndex = m.byteIndex + 1 160 | if bitsLeftInByte < size 161 | size = size - bitsLeftInByte 162 | bytes = int(size / 8) 163 | m.byteIndex = m.byteIndex + bytes 164 | end if 165 | 166 | else if size < 0 167 | print "Not Implemented" 168 | end if 169 | 170 | end function 171 | 172 | return this 173 | end function 174 | -------------------------------------------------------------------------------- /source/main/PriorityQueue.brs: -------------------------------------------------------------------------------- 1 | '**************************************************************************** 2 | '* Licensed under the Apache License, Version 2.0 (the "License"); * 3 | '* you may not use this file except in compliance with the License. * 4 | '* You may obtain a copy of the License at * 5 | '* http://www.apache.org/licenses/LICENSE-2.0 * 6 | '* Unless required by applicable law or agreed to in writing, software * 7 | '* distributed under the License is distributed on an "AS IS" BASIS, * 8 | '* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * 9 | '* See the License for the specific language governing permissions and * 10 | '* limitations under the License. * 11 | '**************************************************************************** 12 | function initPriorityQueue(size=10 as integer) as object 13 | prioQueue = {} 14 | 15 | prioQueue["Data"] = createObject("roArray", size, true) 16 | 17 | 'Default comparator function object just returns true regadless of A and B 18 | ' Comparator function must take two indicies A and B and return boolean 19 | prioQueue["Comparator"] = function(A as dynamic, B as dynamic) as boolean 20 | return true 21 | end function 22 | 23 | '=================== 24 | '="Private" methods= 25 | '=================== 26 | prioQueue.getParent = function(node as integer) as integer 27 | return (node - 1)/2 28 | end function 29 | 30 | prioQueue.getLeft = function(node as integer) as integer 31 | return (2 * node) + 1 32 | end function 33 | 34 | prioQueue.getRight = function(node as integer) as integer 35 | return (2 * node) + 2 36 | end function 37 | 38 | prioQueue.hasChildren = function(node as integer) as boolean 39 | size = m.size() 40 | if node > size then return false 41 | if node.getLeft() > size and node.getRight() > size then return false 42 | return true 43 | end function 44 | 45 | 46 | 'swap location A and location B in internal array 47 | prioQueue.swap = function(A as integer, B as integer) as void 48 | 49 | tmp = m["Data"][A] 50 | m["Data"][A] = m["Data"][B] 51 | m["Data"][B] = tmp 52 | 53 | end function 54 | 55 | 'Top to bottom heapify 56 | prioQueue.heapify = function(i=(m.data.count() - 1) as integer) as void 57 | begin = m.getParent(i) 58 | while begin > -1 59 | m.siftDown(begin, i) 60 | begin-- 61 | end while 62 | end function 63 | 64 | prioQueue.siftDown = function (begin as integer, term as integer) 65 | root = begin 66 | while m.getLeft(root) <= term 67 | 68 | child = m.getLeft(root) 69 | save = root 70 | 71 | if m.comparator(m.data[child], m.data[save] ) 72 | save = child 73 | end if 74 | 75 | if child + 1 <= term and m.comparator(m.data[child + 1], m.data[save]) 76 | save = child + 1 77 | end if 78 | 79 | if save = root 80 | return invalid 81 | else 82 | m.swap(root, save) 83 | root = save 84 | end if 85 | 86 | end while 87 | end function 88 | 89 | '================== 90 | '="Public" methods= 91 | '================== 92 | prioQueue.setComparator = function(comparatorFunc as function) as void 93 | m["Comparator"] = comparatorFunc 94 | end function 95 | 96 | prioQueue.getComparator = function() as function 97 | return m["Comparator"] 98 | end function 99 | 100 | prioQueue.setData = function(data as object) as void 101 | if type(data) = "roArray" 'exit if trying to set data to type other than array 102 | m["Data"] = data 103 | m.heapify() 104 | end if 105 | 106 | end function 107 | 108 | prioQueue.size = function() as integer 109 | return m["Data"].count() 110 | end function 111 | 112 | prioQueue.push = function(A as object) as void 113 | i = m.size() 114 | parent = m.getParent(i) 115 | m["Data"].push(A) 116 | 'Heapify from the bottom up 117 | while i > 0 and m.comparator(m.data[i], m.data[parent]) 118 | m.swap(parent, i) 119 | i = parent 120 | parent = m.getParent(i) 121 | end while 122 | end function 123 | 124 | prioQueue.pop = function() as dynamic 125 | 126 | headValue = m["Data"].shift() 127 | m.heapify() 128 | return headValue 129 | 130 | end function 131 | 132 | prioQueue.peek = function() as dynamic 133 | return m["Data"][0] 134 | end function 135 | 136 | prioQueue.remove = function(node as integer) as void 137 | m.swap(node, 0) 138 | m.pop() 139 | m.heapify() 140 | end function 141 | 142 | prioQueue.clear = function() as void 143 | m["Data"] = createObject("roArray", 10, true) 144 | end function 145 | 146 | prioQueue.toStr = function() as string 147 | header = "prioQueue: { " 148 | trailer = " }" 149 | spacer = ", " 150 | stringVal = box("") 151 | stringVal.appendString(header, len(header)) 152 | sizeString = "size: " 153 | sizeVal = m.size() 154 | sizeValString = sizeVal.toStr() 155 | stringVal.appendString(sizeString, len(sizeString)) 156 | stringVal.appendString(sizeValString, len(sizeValString)) 157 | dataHead = ", data: [ " 158 | stringVal.appendString(dataHead, len(dataHead)) 159 | dataTrailer = " ]" 160 | for i=0 to sizeVal - 2 161 | 162 | valueI = m.data[i].toStr() 163 | stringVal.appendString(valueI, len(valueI)) 164 | stringVal.appendString(spacer, len(spacer)) 165 | end for 166 | 167 | valueI = m.data[sizeVal -1].toStr() 168 | stringVal.appendString(valueI, len(valueI)) 169 | stringVal.appendString(dataTrailer, len(dataTrailer)) 170 | stringVal.appendString(trailer, len(trailer)) 171 | return stringVal.toStr() 172 | 173 | end function 174 | 175 | return prioQueue 176 | 177 | end function 178 | -------------------------------------------------------------------------------- /source/main/ByteArrayReader.brs: -------------------------------------------------------------------------------- 1 | '**************************************************************************** 2 | '* Licensed under the Apache License, Version 2.0 (the "License"); * 3 | '* you may not use this file except in compliance with the License. * 4 | '* You may obtain a copy of the License at * 5 | '* http://www.apache.org/licenses/LICENSE-2.0 * 6 | '* Unless required by applicable law or agreed to in writing, software * 7 | '* distributed under the License is distributed on an "AS IS" BASIS, * 8 | '* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * 9 | '* See the License for the specific language governing permissions and * 10 | '* limitations under the License. * 11 | '**************************************************************************** 12 | function newByteArrayReader() as object 13 | byteArrayReader = {} 14 | byteArrayReader.byteArray = invalid 15 | byteArrayReader.index = 0 16 | byteArrayReader.error = false 17 | byteArrayReader.reason = "" 18 | 19 | 'check if there is an error 20 | byteArrayReader.isInError = function () as boolean 21 | return m.error 22 | end function 23 | 24 | 'clear the error state on the object 25 | byteArrayReader.clearError = function () as void 26 | m.error = false 27 | m.reason = "" 28 | end function 29 | 30 | byteArrayReader.getReason = function () 31 | return m.reason 32 | end function 33 | 34 | 'Retrieve the current index location 35 | byteArrayReader.getIndexLocation = function() as integer 36 | return m.index 37 | end function 38 | 39 | 'Moves the index to the specified location in the array. 40 | 'Does not set array if array is larger than the length of the internal 41 | 'Byte array 42 | byteArrayReader.setIndexLocation = function(index as integer) as void 43 | if m.byteArray.count() <= index 44 | m.index = index 45 | else 46 | m.error = true 47 | m.reason = "setIndexLocation failed; Index out of bounds" 48 | end if 49 | end function 50 | 51 | byteArrayReader.initializeAsNewByteArray = function() as void 52 | m.byteArray = createObject("roByteArray") 53 | end function 54 | 55 | 56 | byteArrayReader.initializeFromByteArray = function(ba) as void 57 | 'if the object type isn't byteArray, then don't assign 58 | if type(ba) <> "roByteArray" 59 | m.error = true 60 | m.reason = "setting byte array object failed; object is not byte array" 61 | else 62 | m.byteArray = ba 63 | end if 64 | 65 | end function 66 | 67 | ' retrieves 4 bytes from the byte array and moves the index up 4. 68 | byteArrayReader.getInt32FromByteArray = function () as integer 69 | 70 | if m.index + 4 > m.byteArray.count() 71 | m.error = true 72 | m.reason = "4 bytes would put index out of bounds" 73 | return 0 74 | end if 75 | 76 | value = 0 77 | value = value + m.byteArray[m.index] 78 | for i = 1 to 3 79 | value = value << 8 80 | value = value + m.byteArray[m.index + i] 81 | end for 82 | m.index = m.index + 4 83 | return value 84 | end function 85 | 86 | ' retrieves 4 bytes from the byte array and moves the index up 4. 87 | ' upcasts the return to a 64 bit 88 | byteArrayReader.getInt32FromByteArrayAsInt64 = function () as LongInteger 89 | 90 | if m.index + 4 > m.byteArray.count() 91 | m.error = true 92 | m.reason = "getInt32FromByteArrayAsInt64 failed;4 bytes would put index out of bounds" 93 | return 0 94 | end if 95 | 96 | value = 0& 97 | value = value + m.byteArray[m.index] 98 | for i = 1 to 3 99 | value = value << 8 100 | value = value + m.byteArray[m.index + i] 101 | end for 102 | m.index = m.index + 4 103 | return value 104 | end function 105 | 106 | 'Retrive 8 bytes from the byte array and move the index up 8 107 | byteArrayReader.getInt64FromByteArray = function () as LongInteger 108 | 109 | if m.index + 8 > m.byteArray.count() 110 | m.error = true 111 | m.reason = "getInt64FromByteArray failed; 8 bytes would put index out of bounds" 112 | return 0 113 | end if 114 | 115 | value = 0& 116 | value = value + m.byteArray[m.index] 117 | for i = 1 to 7 118 | value = value << 8 119 | value = value + m.byteArray[m.index + i] 120 | end for 121 | m.index = m.index + 8 122 | return value 123 | end function 124 | 125 | 'retrieve one byte from array as a signed integer, range (-128, 127) 126 | byteArrayReader.getInt8FromByteArray = function () as integer 127 | if m.index + 1 > m.byteArray.count() 128 | m.error = true 129 | m.reason = "getInt8FromByteArray failed; 1 byte would put index out of bounds" 130 | return 0 131 | end if 132 | 133 | value = m.byteArray.GetSignedByte(m.index) 134 | m.index = m.index + 1 135 | return value 136 | end function 137 | 138 | 'Retrieve one byte from array as an unsigned integer, range (0, 255) 139 | byteArrayReader.getUint8FromByteArray = function () as integer 140 | if m.index + 1 > m.byteArray.count() 141 | m.error = true 142 | m.reason = "getUint8FromByteArray failed; 1 byte would put index out of bounds" 143 | return 0 144 | end if 145 | 146 | value = m.byteArray[m.index] 147 | m.index = m.index + 1 148 | 149 | return value 150 | end function 151 | 152 | byteArrayReader.getUint16FromByteArray = function () as integer 153 | if m.index + 2 > m.byteArray.count() 154 | m.error = true 155 | m.reason = "getUInt16FromByteArray failed; 2 byte would put index out of bounds" 156 | end if 157 | 158 | value = m.byteArray[m.index] 159 | value = value << 8 160 | value = value + m.byteArray[m.index + 1] 161 | m.index = m.index + 2 162 | 163 | return value 164 | end function 165 | 166 | byteArrayReader.getInt16FromByteArray = function () as integer 167 | if m.index + 2 > m.byteArray.count() 168 | m.error = true 169 | m.reason = "getUInt16FromByteArray failed; 2 byte would put index out of bounds" 170 | end if 171 | 172 | value = m.byteArray[m.index] 173 | value = value << 8 174 | value = value + m.byteArray[m.index + 1] 175 | m.index = m.index + 2 176 | 177 | int16Max = 32767 178 | 179 | if value > int16Max 180 | diff = int16Max - value 181 | value = (diff or int16Max) and not (diff and int16Max) 182 | end if 183 | 184 | return value 185 | end function 186 | 187 | 'Move index up by some 32 bit integer number of bytes 188 | 'If out of bounds, do not set index, print error 189 | byteArrayReader.skipBytes = function (numberOfBytesToSkip as integer) as void 190 | if m.index + numberOfBytesToSkip < m.byteArray.count() 191 | m.index = m.index + numberOfBytesToSkip 192 | else 193 | m.error = true 194 | m.reason = "skip moves index out of range" 195 | end if 196 | end function 197 | 198 | 'Move index back by some 32 bit integer number of bytes 199 | 'If out of bounds do not set index 200 | byteArrayReader.rewindBytes = function (numberOfBytesToRewind as integer) as void 201 | if m.index - numberOfBytesToRewind > 0 202 | m.index = m.index - numberOfBytesToRewind 203 | else 204 | m.error = true 205 | m.reason = "rewindBytes failed; rewind moves index out of range" 206 | end if 207 | end function 208 | 209 | 'Grab a subarray of size `numberOfBytes from the current byte array 210 | 'If out of bounds, do nothing. 211 | byteArrayReader.getBytes = function (numberOfBytes) 212 | newByteArray = CreateObject("roByteArray") 213 | if m.index + numberOfBytes <= m.byteArray.count() 214 | i = numberOfBytes 215 | while i > 0 216 | newByteArray.push(m.byteArray[m.index + numberOfBytes - i]) 217 | i = i - 1 218 | end while 219 | m.index = m.index + numberOfBytes 220 | else 221 | m.error = true 222 | m.reason = "getBytes failed; subbyte array is larger than end of array" 223 | end if 224 | return newByteArray 225 | end function 226 | 227 | return byteArrayReader 228 | end function 229 | -------------------------------------------------------------------------------- /source/test/TestByteReader.brs: -------------------------------------------------------------------------------- 1 | '**************************************************************************** 2 | '* Licensed under the Apache License, Version 2.0 (the "License"); * 3 | '* you may not use this file except in compliance with the License. * 4 | '* You may obtain a copy of the License at * 5 | '* http://www.apache.org/licenses/LICENSE-2.0 * 6 | '* Unless required by applicable law or agreed to in writing, software * 7 | '* distributed under the License is distributed on an "AS IS" BASIS, * 8 | '* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * 9 | '* See the License for the specific language governing permissions and * 10 | '* limitations under the License. * 11 | '**************************************************************************** 12 | function byteArrayTests() 13 | printHeader("Byte Array Tests") 14 | checkSuccess("testInitializationWithValidByteArray", testInitializationWithValidByteArray()) 15 | checkSuccess("testInitializationWithInvalidByteArray", testInitializationWithInvalidByteArray()) 16 | checkSuccess("testInitializationWithNewByteArray", testInitializationWithNewByteArray()) 17 | checkSuccess("testRead32BitInteger", testRead32BitInteger()) 18 | checkSuccess("testRead32BitIntegerOutOfBounds", testRead32BitIntegerOutOfBounds()) 19 | checkSuccess("testgetInt32FromByteArrayAsInt64", testgetInt32FromByteArrayAsInt64()) 20 | checkSuccess("testgetInt32FromByteArrayAsInt64OutOfBounds", testgetInt32FromByteArrayAsInt64OutOfBounds()) 21 | checkSuccess("testGetInt64FromByteArray", testGetInt64FromByteArray()) 22 | checkSuccess("testGetInt16FromByteArrayNegative", testGetInt16FromByteArrayNegative()) 23 | checkSuccess("testGetInt16FromByteArrayPositive", testGetInt16FromByteArrayPositive()) 24 | checkSuccess("testGetInt16FromByteArrayInt16Max", testGetInt16FromByteArrayInt16Max()) 25 | checkSuccess("testGetInt16FromByteArrayInt16Min", testGetInt16FromByteArrayInt16Min()) 26 | checkSuccess("testGetUint16FromByteArray", testGetUint16FromByteArray()) 27 | checkSuccess("testGetUint8FromByteArray", testGetUint8FromByteArray()) 28 | checkSuccess("testGetInt8FromByteArray", testGetInt8FromByteArray()) 29 | end function 30 | 31 | function testInitializationWithValidByteArray() as boolean 32 | byteArrayReader = newByteArrayReader() 33 | byteArray = createobject("roByteArray") 34 | byteArray.push(1) 35 | byteArray.push(2) 36 | byteArray.push(3) 37 | byteArrayReader.initializeFromByteArray(byteArray) 38 | return type(byteArrayReader.byteArray) = "roByteArray" 39 | end function 40 | 41 | function testInitializationWithInvalidByteArray() as boolean 42 | 43 | byteArrayReader = newByteArrayReader() 44 | byteArray = invalid 45 | byteArrayReader.initializeFromByteArray(invalid) 46 | return byteArrayReader.byteArray = invalid and byteArrayReader.isInError() = true 47 | 48 | end function 49 | 50 | function testInitializationWithNewByteArray() as boolean 51 | byteArrayReader = newByteArrayReader() 52 | byteArrayReader.initializeAsNewByteArray() 53 | return type(byteArrayReader.byteArray) = "roByteArray" and byteArrayReader.isInError() = false 54 | end function 55 | 56 | function testRead32BitInteger() as boolean 57 | byteArrayReader = newByteArrayReader() 58 | byteArray = createobject("roByteArray") 59 | byteArray.push(1) '0000 0001 60 | byteArray.push(4) '0000 0100 61 | byteArray.push(16)'0001 0000 62 | byteArray.push(64)'0100 0000 63 | '0000 0001 0000 0100 0001 0000 0100 0000 64 | byteArrayReader.initializeFromByteArray(byteArray) 65 | result = byteArrayReader.getInt32FromByteArray() 66 | return result = 17043520 and byteArrayReader.index = 4 and byteArrayReader.isInError() = false 67 | end function 68 | 69 | function testRead32BitIntegerOutOfBounds() as boolean 70 | 71 | byteArrayReader = newByteArrayReader() 72 | byteArray = createobject("roByteArray") 73 | byteArray.push(0) 74 | byteArray.push(0) 75 | byteArray.push(0) 76 | byteArrayReader.initializeFromByteArray(byteArray) 77 | result = byteArrayReader.getInt32FromByteArray() 78 | return result = 0 and byteArrayReader.index = 0 and byteArrayReader.isInError() = true 79 | 80 | end function 81 | 82 | function testgetInt32FromByteArrayAsInt64() as boolean 83 | byteArrayReader = newByteArrayReader() 84 | byteArray = createobject("roByteArray") 85 | byteArray.push(1) 86 | byteArray.push(4) 87 | byteArray.push(16) 88 | byteArray.push(64) 89 | byteArrayReader.initializeFromByteArray(byteArray) 90 | result = byteArrayReader.getInt32FromByteArrayAsInt64() 91 | return result = 17043520& and byteArrayReader.index = 4 and type(result) = "LongInteger" and byteArrayReader.isInError() = false 92 | end function 93 | 94 | function testgetInt32FromByteArrayAsInt64OutOfBounds() as boolean 95 | byteArrayReader = newByteArrayReader() 96 | byteArray = createobject("roByteArray") 97 | byteArray.push(0) 98 | byteArray.push(0) 99 | byteArray.push(0) 100 | byteArrayReader.initializeFromByteArray(byteArray) 101 | result = byteArrayReader.getInt32FromByteArray() 102 | return result = 0 and byteArrayReader.index = 0 and byteArrayReader.isInError() = true 103 | 104 | 105 | end function 106 | 107 | function testGetInt64FromByteArray() as boolean 108 | 109 | byteArrayReader = newByteArrayReader() 110 | byteArray = createobject("roByteArray") 111 | byteArray.push(1) '0000 0001 112 | byteArray.push(2) '0000 0010 113 | byteArray.push(4) '0000 0100 114 | byteArray.push(8) '0000 1000 115 | 116 | byteArray.push(13) '0000 1101 117 | byteArray.push(53) '0011 0101 118 | byteArray.push(255) '1111 1111 119 | byteArray.push(15) '0000 1111 120 | '0000 0001 0000 0010 0000 0100 0000 1000 0000 1101 0011 0101 1111 1111 0000 1111 121 | byteArrayReader.initializeFromByteArray(byteArray) 122 | result = byteArrayReader.getInt64FromByteArray() 123 | return result = 72624976619241231& and byteArrayReader.index = 8 and byteArrayReader.isInError() = false 124 | 125 | end function 126 | 127 | function testGetInt16FromByteArrayNegative() as boolean 128 | byteArrayReader = newByteArrayReader() 129 | byteArray = createobject("roByteArray") 130 | byteArray.push(-82) '1101 0001 131 | byteArray.push(19) '1110 1100 132 | 133 | '1111 1111 1111 1111 1010 1110 0001 0011 134 | byteArrayReader.initializeFromByteArray(byteArray) 135 | result = byteArrayReader.getInt16FromByteArray() 136 | return result = -20973 and byteArrayReader.index = 2 and byteArrayReader.isInError() = false 137 | end function 138 | 139 | function testGetInt16FromByteArrayPositive() as boolean 140 | byteArrayReader = newByteArrayReader() 141 | byteArray = createobject("roByteArray") 142 | byteArray.push(63) '0011 1111 143 | byteArray.push(-31) '1110 0001 144 | 145 | '0000 0000 0000 0000 0011 1111 1110 0001 146 | byteArrayReader.initializeFromByteArray(byteArray) 147 | result = byteArrayReader.getInt16FromByteArray() 148 | return result = 16353 and byteArrayReader.index = 2 and byteArrayReader.isInError() = false 149 | end function 150 | 151 | function testGetInt16FromByteArrayInt16Max() as boolean 152 | INT16_MAX = 32767 153 | byteArrayReader = newByteArrayReader() 154 | byteArray = createobject("roByteArray") 155 | byteArray.push(127) '0111 1111 156 | byteArray.push(-1) '1111 1111 157 | byteArrayReader.initializeFromByteArray(byteArray) 158 | result = byteArrayReader.getInt16FromByteArray() 159 | return result = INT16_MAX and byteArrayReader.index = 2 and byteArrayReader.isInError() = false 160 | end function 161 | 162 | function testGetInt16FromByteArrayInt16Min() as boolean 163 | INT16_MIN = -32768 164 | byteArrayReader = newByteArrayReader() 165 | byteArray = createobject("roByteArray") 166 | byteArray.push(-128) '1000 0000 167 | byteArray.push(0) '0000 0000 168 | byteArrayReader.initializeFromByteArray(byteArray) 169 | result = byteArrayReader.getInt16FromByteArray() 170 | return result = INT16_MIN and byteArrayReader.index = 2 and byteArrayReader.isInError() = false 171 | end function 172 | 173 | function testGetUint16FromByteArray() as boolean 174 | expected = 44563 175 | byteArrayReader = newByteArrayReader() 176 | byteArray = createobject("roByteArray") 177 | byteArray.push(-82) '10101110 178 | byteArray.push(19) '00010011 179 | byteArrayReader.initializeFromByteArray(byteArray) 180 | result = byteArrayReader.getUint16FromByteArray() 181 | return result = expected and byteArrayReader.index = 2 and byteArrayReader.isInError() = false 182 | end function 183 | 184 | function testGetUint8FromByteArray() as boolean 185 | expected = 200 186 | byteArrayReader = newByteArrayReader() 187 | byteArray = createobject("roByteArray") 188 | byteArray.push(-56) '11001000 189 | byteArrayReader.initializeFromByteArray(byteArray) 190 | result = byteArrayReader.getUint8FromByteArray() 191 | return result = expected and byteArrayReader.index = 1 and byteArrayReader.isInError() = false 192 | end function 193 | 194 | function testGetInt8FromByteArray() as boolean 195 | expected = -56 196 | byteArrayReader = newByteArrayReader() 197 | byteArray = createobject("roByteArray") 198 | byteArray.push(-56) '11001000 199 | byteArrayReader.initializeFromByteArray(byteArray) 200 | result = byteArrayReader.getInt8FromByteArray() 201 | return result = expected and byteArrayReader.index = 1 and byteArrayReader.isInError() = false 202 | end function 203 | -------------------------------------------------------------------------------- /source/test/TestBitfieldParser.brs: -------------------------------------------------------------------------------- 1 | function bitfieldParserTests() 2 | printHeader("Test Bitfield Parser") 3 | checkSuccess("Test bitfield parser creation", testCreatebitfieldParser() ) 4 | checkSuccess("Test Bitfield parser Initialization", testBitfieldParserInitialization()) 5 | checkSuccess("Test Bitfield Parser GetBit", testGetBit()) 6 | checkSuccess("Test get bits stored in 32 bit int with perfect byte boundaries", testGetBits32_perfect_bytes()) 7 | checkSuccess("Test get bits stored in 32 bit int intra byte from the front perfect boundary back", testGetBits32_intraByte_front()) 8 | checkSuccess("Test get bits stored in 32 bit int perfect boundary front intra byte back", testGetBits32_intraByte_back()) 9 | checkSuccess("test get bits stored in 32 bit int intra boundary for both", testGetBits32_intraByte_both()) 10 | checkSuccess("test get bits strored in 32 bit in with intra bytes no middle",getBits32_intraByte_no_middle()) 11 | checkSuccess("Test get bits stored in 64 bit int with perfect byte boundaries", testGetBits64_perfect_bytes()) 12 | checkSuccess("Test get bits stored in 64 bit int intra byte from the front perfect boundary back", testGetBits64_intraByte_front()) 13 | checkSuccess("Test get bits stored in 64 bit int perfect boundary front intra byte back", testGetBits64_intraByte_back()) 14 | checkSuccess("test get bits stored in 64 bit int intra boundary for both", testGetBits64_intraByte_both()) 15 | checkSuccess("test get bits strored in 64 bit in with intra bytes no middle",getBits64_intraByte_no_middle()) 16 | checkSuccess("Test get bits stored in a 64 bit int - larger than 32 bits", getBits64_large()) 17 | checkSuccess("Test bitfield seek positive", testSeek_positive()) 18 | end function 19 | 20 | function initializeBitfieldTestVector() 21 | scte35Message = "/DBQAAFyPWVA///wBQb+czRpoAA6AhRDVUVJXhYcln+/AQVDMDMyMDUAAAIiQ1VFSV4WHqZ/3wAB7acqAQ5FUDAyNzkwNzMyMDU5MyADZF+5Ei4=" 22 | ba = createObject("roByteArray") 23 | ba.fromBase64String(scte35Message) 24 | return ba 25 | end function 26 | 27 | function testCreatebitfieldParser() 28 | bitfieldParser = newBitfieldParser() 29 | return bitfieldParser.index = 0 and bitfieldParser.byteIndex = 0 and bitfieldParser.bits = 0 and bitfieldParser.data = invalid 30 | end function 31 | 32 | function testBitfieldParserInitialization() 33 | testVector = initializeBitfieldTestVector() 34 | bitfieldParser = newBitfieldParser() 35 | bitfieldParser.initialize(testVector) 36 | return bitfieldParser.index = 0 and bitfieldParser.byteIndex = 0 and bitfieldParser.bits = 664 and bitfieldParser.data <> invalid 37 | end function 38 | 39 | 'parses the entire string one bit at a time 40 | function testGetBit() 41 | expected = [1,1,1,1,1,1,0,0,0,0,1,1,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,1,1,0,0,1,0,0,0,1,1,1,1,0,1,0,1,1,0,0,1,0,1,0,1,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,1,1,0,1,1,1,1,1,1,1,0,0,1,1,1,0,0,1,1,0,0,1,1,0,1,0,0,0,1,1,0,1,0,0,1,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,1,0,0,0,0,0,0,0,1,0,0,0,0,1,0,1,0,0,0,1,0,0,0,0,1,1,0,1,0,1,0,1,0,1,0,1,0,0,0,1,0,1,0,1,0,0,1,0,0,1,0,1,0,1,1,1,1,0,0,0,0,1,0,1,1,0,0,0,0,1,1,1,0,0,1,0,0,1,0,1,1,0,0,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,1,0,1,0,0,0,0,1,1,0,0,1,1,0,0,0,0,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,0,0,0,1,1,0,0,0,0,0,0,1,1,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,0,1,0,0,0,0,1,1,0,1,0,1,0,1,0,1,0,1,0,0,0,1,0,1,0,1,0,0,1,0,0,1,0,1,0,1,1,1,1,0,0,0,0,1,0,1,1,0,0,0,0,1,1,1,1,0,1,0,1,0,0,1,1,0,0,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,1,1,0,1,1,0,1,0,0,1,1,1,0,0,1,0,1,0,1,0,0,0,0,0,0,0,0,1,0,0,0,0,1,1,1,0,0,1,0,0,0,1,0,1,0,1,0,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,1,0,0,0,1,1,0,1,1,1,0,0,1,1,1,0,0,1,0,0,1,1,0,0,0,0,0,0,1,1,0,1,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,0,0,0,1,1,0,0,0,0,0,0,1,1,0,1,0,1,0,0,1,1,1,0,0,1,0,0,1,1,0,0,1,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,1,1,0,1,1,0,0,1,0,0,0,1,0,1,1,1,1,1,1,0,1,1,1,0,0,1,0,0,0,1,0,0,1,0,0,0,1,0,1,1,1] 42 | testVector = initializeBitfieldTestVector() 43 | bitfieldParser = newBitfieldParser() 44 | bitfieldParser.initialize(testVector) 45 | resultArray = [] 46 | while bitfieldParser.hasBits() 47 | value = bitfieldParser.getBit() 48 | if value = invalid then stop 49 | resultArray.push(value) 50 | end while 51 | result = true 52 | for i = 0 to resultArray.count() - 1 53 | if resultArray[i] <> expected[i] 54 | print "Failed at - Index:"; i; " values - expected: "; expected[i]; " actual: "; resultArray[i] 55 | end if 56 | result = result and resultArray[i] = expected[i] 57 | end for 58 | return result 59 | end function 60 | 61 | function testGetBits32_perfect_bytes() 62 | expected = 16527440 63 | testVector = initializeBitfieldTestVector() 64 | bitfieldParser = newBitfieldParser() 65 | bitfieldParser.initialize(testVector) 66 | result = bitfieldParser.getBits32(24) 67 | return expected = result 68 | end function 69 | 70 | function testGetBits32_intraByte_front() 71 | expected = 1847376 72 | testVector = initializeBitfieldTestVector() 73 | bitfieldParser = newBitfieldParser() 74 | bitfieldParser.initialize(testVector) 75 | 'Three bits in 76 | bitfieldParser.getBit() 77 | bitfieldParser.getBit() 78 | bitfieldParser.getBit() 79 | 'End on same boundary as above 80 | result = bitfieldParser.getBits32(21) 81 | 82 | return expected = result 83 | end function 84 | 85 | function testGetBits32_intraByte_back() 86 | 87 | expected = 2065930 88 | testVector = initializeBitfieldTestVector() 89 | bitfieldParser = newBitfieldParser() 90 | bitfieldParser.initialize(testVector) 91 | result = bitfieldParser.getBits32(21) 92 | return expected = result 93 | 94 | end function 95 | 96 | function testGetBits32_intraByte_both() 97 | expected = 197888 98 | testVector = initializeBitfieldTestVector() 99 | bitfieldParser = newBitfieldParser() 100 | bitfieldParser.initialize(testVector) 101 | 102 | for i = 0 to 8 103 | bitfieldParser.getBit() 104 | end for 105 | 106 | result = bitfieldParser.getBits32(19) 107 | 108 | return expected = result 109 | end function 110 | 111 | function getBits32_intraByte_no_middle() 112 | expected = 773 113 | testVector = initializeBitfieldTestVector() 114 | bitfieldParser = newBitfieldParser() 115 | bitfieldParser.initialize(testVector) 116 | for i = 0 to 8 117 | bitfieldParser.getBit() 118 | end for 119 | result = bitfieldParser.getBits32(11) 120 | return expected = result 121 | end function 122 | 123 | '64 bit integer container 124 | function testGetBits64_perfect_bytes() 125 | expected = 16527440& 126 | testVector = initializeBitfieldTestVector() 127 | bitfieldParser = newBitfieldParser() 128 | bitfieldParser.initialize(testVector) 129 | result = bitfieldParser.getBits64(24) 130 | return expected = result 131 | end function 132 | 133 | function testGetBits64_intraByte_front() 134 | expected = 1847376& 135 | testVector = initializeBitfieldTestVector() 136 | bitfieldParser = newBitfieldParser() 137 | bitfieldParser.initialize(testVector) 138 | 'Three bits in 139 | bitfieldParser.getBit() 140 | bitfieldParser.getBit() 141 | bitfieldParser.getBit() 142 | 'End on same boundary as above 143 | result = bitfieldParser.getBits64(21) 144 | 145 | return expected = result 146 | end function 147 | 148 | function testGetBits64_intraByte_back() 149 | 150 | expected = 2065930& 151 | testVector = initializeBitfieldTestVector() 152 | bitfieldParser = newBitfieldParser() 153 | bitfieldParser.initialize(testVector) 154 | result = bitfieldParser.getBits64(21) 155 | return expected = result 156 | 157 | end function 158 | 159 | function testGetBits64_intraByte_both() 160 | expected = 197888& 161 | testVector = initializeBitfieldTestVector() 162 | bitfieldParser = newBitfieldParser() 163 | bitfieldParser.initialize(testVector) 164 | 165 | for i = 0 to 8 166 | bitfieldParser.getBit() 167 | end for 168 | 169 | result = bitfieldParser.getBits64(19) 170 | 171 | return expected = result 172 | end function 173 | 174 | function getBits64_intraByte_no_middle() 175 | expected = 773& 176 | testVector = initializeBitfieldTestVector() 177 | bitfieldParser = newBitfieldParser() 178 | bitfieldParser.initialize(testVector) 179 | for i = 0 to 8 180 | bitfieldParser.getBit() 181 | end for 182 | result = bitfieldParser.getBits64(11) 183 | return expected = result 184 | end function 185 | 186 | function getBits64_large() 187 | '011000001010000000000000000000101110010001111010110010 188 | expected = 6799379918298802& 189 | testVector = initializeBitfieldTestVector() 190 | bitfieldParser = newBitfieldParser() 191 | bitfieldParser.initialize(testVector) 192 | for i = 0 to 8 193 | bitfieldParser.getBit() 194 | end for 195 | result = bitfieldParser.getBits64(54) 196 | return result = expected 197 | end function 198 | 199 | 'Seek 200 | function testSeek_positive() 201 | testVector = initializeBitfieldTestVector() 202 | bitfieldParser = newBitfieldParser() 203 | bitfieldParser.initialize(testVector) 204 | for i = 0 to 5 205 | bitfieldParser.getBit() 206 | end for 207 | 'bit 6 byte 0 208 | bitfieldParser.seek(23) 'bit 29 byte 3 209 | bitfieldParser.seek(2) 'bit 31 byte 3 210 | bitfieldParser.seek(2) 'bit 33 byte 4 211 | bitfieldParser.seek(2) 'bit 35 byte 4 212 | bitfieldParser.seek(2) 'bit 37 byte 4 213 | bitfieldParser.seek(4) 'bit 41 byte 5 214 | return bitfieldParser.getIndex() = 41 and bitfieldParser.getByteIndex() = 5 215 | end function 216 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | --------------------------------------------------------------------------------