--!parent
--!encoding=utf-8
--****************************************************************************
-- Software: BYTEARRAY_ENCODER
-- Version: 0.6
-- Date: 2009-04-18
-- Author: Valentin Schmidt
--
-- Supported data types:
-- #list
-- #propList
-- #bytearray
-- #string
-- #symbol
-- #integer
-- #float (either using lingo ( = slow) or crypto xtra ( = fast))
-- #image
-- #void
-- #date
-- #point, #rect, #vector, #transform (all coords stored as floats)
-- #color
-- #sprite, #member, #castlib
-- #media (requires crypto xtra!)
-- core objects (#_player, #_movie, ...)
-- all other types that can be stored/restored by using string(...)/value(...)
--
-- Usage:
-- v = [1,2,"hellö<>#+~",["foo":"bar", #foo2:#bar2], member("test").image]
-- enc = script("BYTEARRAY_ENCODER")
-- m = new(#bytearray)
-- m.bytearray = enc.mEncodeData(v)
-- put enc.mDecodeData(m.bytearray)
--
--****************************************************************************
----------------------------------------
-- v: arbitrary (supported) value
-- returns: bytearray
----------------------------------------
on mEncodeData (me, v)
baData = bytearray()
me._encode(v, baData)
return baData
end
----------------------------------------
-- baData: encoded value as bytearray
-- returns: value
----------------------------------------
on mDecodeData (me, baData)
baData.position = 1
return me._decode(baData)
end
----------------------------------------
-- similar to mEncodeData, but expects linear list and creates valid RIFF file
--
-- tList: list of arbitrary values
-- returns: bytearray
----------------------------------------
on mEncodeDataRIFF (me, tList)
baData = bytearray()
baData.writeRawString("RIFF", 4)
baData.writeInt32(0) -- update later
baData.writeRawString("BYARdata", 8)
baData.writeInt32(0) -- update later
cnt = count(tList)
repeat with i = 1 to cnt
me._encode(tList[i], baData)
end repeat
len = baData.position-17-4
baData.position = 17
baData.writeInt32(len)
baData.position = 5
baData.writeInt32(baData.length-8)
baData.position = 1
return baData
end
----------------------------------------
-- similar to mDecodeData, but based on valid RIFF file created with mEncodeDataRIFF
--
-- baData: encoded list as bytearray (RIFF version)
-- returns: list
----------------------------------------
on mDecodeDataRIFF (me, baData)
v = []
baData.position = 17
len = baData.readInt32()
pos = baData.position
repeat while true
v.add(me._decode(baData))
if baData.position> = pos+len then exit repeat
end repeat
return v
end
----------------------------------------
--
----------------------------------------
on _encode (me, v, baData)
t = ilk(v)
baData.writeRawString(string(t).char[1..4], 4)
case (t) of
#list:
cnt = count(v)
baData.writeInt32(cnt)
repeat with i = 1 to cnt
me._encode(v[i], baData)
end repeat
#proplist:
cnt = count(v)
baData.writeInt32(cnt)
repeat with i = 1 to cnt
me._encode(v.getPropAt(i), baData)
me._encode(v[i], baData)
end repeat
#bytearray:
baData.writeInt32(v.length)
baData.writeByteArray(v)
#string:
baData.writeString(v)
#symbol:
baData.writeString(string(v))
#integer:
baData.writeInt32(v)
#float:
me.writeDouble(baData, v)
#image:
baData.writeInt16(v.width)
baData.writeInt16(v.height)
baData.writeInt8(v.depth)
case (v.depth) of
32:
-- if v.useAlpha then
baData.writeByteArray(v.getPixels(#BGRA8888))
-- else
-- pData.writeByteArray(v.getPixels(#BGR888))
-- end if
24:
baData.writeByteArray(v.getPixels(#BGR888))
16:
cntx = v.width-1
cnty = v.height-1
repeat with y = 0 to cnty
repeat with x = 0 to cntx
baData.writeInt16(v.getPixel(x,y,#integer))
end repeat
end repeat
8:
cntx = v.width-1
cnty = v.height-1
repeat with y = 0 to cnty
repeat with x = 0 to cntx
baData.writeInt8(v.getPixel(x,y,#integer))
end repeat
end repeat
4:-- TODO
2:
1:
end case
#void: --> will be VOID
nothing
#point:
me.writeDouble(baData, v.locH)
me.writeDouble(baData, v.locV)
#vector:
me.writeDouble(baData, v.x)
me.writeDouble(baData, v.y)
me.writeDouble(baData, v.z)
#rect:
me.writeDouble(baData, v.left)
me.writeDouble(baData, v.top)
me.writeDouble(baData, v.right)
me.writeDouble(baData, v.bottom)
#transform:
me.writeDouble(baData, v.scale.x)
me.writeDouble(baData, v.scale.y)
me.writeDouble(baData, v.scale.z)
me.writeDouble(baData, v.position.x)
me.writeDouble(baData, v.position.y)
me.writeDouble(baData, v.position.z)
me.writeDouble(baData, v.rotation.x)
me.writeDouble(baData, v.rotation.y)
me.writeDouble(baData, v.rotation.z)
me.writeDouble(baData, v.axisangle[1].x)
me.writeDouble(baData, v.axisangle[1].y)
me.writeDouble(baData, v.axisangle[1].z)
me.writeDouble(baData, v.axisangle[2])
#date: -- save as 8 bytes
baData.writeInt16(v.year)
baData.writeInt8(v.month)
baData.writeInt8(v.day)
baData.writeInt32(v.seconds)
#color:
baData.writeInt8(v.red)
baData.writeInt8(v.green)
baData.writeInt8(v.blue)
#sprite:
baData.writeInt16(v.spriteNum)
#member:
baData.writeInt16(v.memberNum)
baData.writeInt16(v.castLibNum)
#castLib:
baData.writeInt16(v.number)
#media: -- requires CRYPTO XTRA
ba = cx_media_to_bytearray(v)
baData.writeByteArray(ba)
otherwise: -- everything that can be evaluated directly using value()...?
s = string(v)
if s.word[1] = "<Object" then -- core objects, e.g. _movie, _player, ...
baData.writeString(s.word[2])
else if s.word[1] = "<Xtra" AND s.word[2]<>"child" then -- xtra refs (no instances)
s = s.word[1..2]
delete char 1 of s
baData.writeString(s)
else
baData.writeString(s)
end if
end case
end
----------------------------------------
--
----------------------------------------
on _decode (me, baData)
t = baData.readRawString(4)
case (t) of
"list":
v = []
cnt = baData.readInt32()
repeat with i = 1 to cnt
v.add(me._decode(baData))
end repeat
"prop":
v = [:]
cnt = baData.readInt32()
repeat with i = 1 to cnt
p = me._decode(baData)
vl = me._decode(baData)
v.addProp(p, vl)
end repeat
"byte":
len = baData.readInt32()
v = baData.readByteArray(len)
"stri":
v = baData.readString()
"symb":
v = symbol(baData.readString())
"inte":
v = baData.readInt32()
"floa":
v = me.readDouble(baData)
"imag":
w = baData.readInt16()
h = baData.readInt16()
d = baData.readInt8()
v = image(w,h,d)
case (d) of
32:
ba = baData.readByteArray(w*h*4)
v.setPixels(ba, #BGRA8888)
24:
ba = baData.readByteArray(w*h*3)
v.setPixels(ba, #BGR888)
16:
ba = baData.readByteArray(w*h*2)
cntx = w-1
cnty = h-1
repeat with y = 0 to cnty
repeat with x = 0 to cntx
v.setPixel(x,y, baData.readInt16(), #integer)
end repeat
end repeat
8:
ba = baData.readByteArray(w*h)
cntx = w-1
cnty = h-1
repeat with y = 0 to cnty
repeat with x = 0 to cntx
v.setPixel(x,y, baData.readInt8(), #integer)
end repeat
end repeat
4: -- TODO
2:
1:
end case
"medi": -- requires CRYPTO XTRA
len = baData.readInt32()
ba = baData.readByteArray(len)
v = cx_bytearray_to_media(ba) -- TODO
"void":
nothing -- or: v = VOID
"poin":
v = point(me.readDouble(baData),me.readDouble(baData))
"vect":
v = vector(me.readDouble(baData),me.readDouble(baData),me.readDouble(baData))
"rect":
v = rect(me.readDouble(baData),me.readDouble(baData),me.readDouble(baData),me.readDouble(baData))
"tran":
v = transform()
v.scale = vector(me.readDouble(baData),me.readDouble(baData),me.readDouble(baData))
v.position = vector(me.readDouble(baData),me.readDouble(baData),me.readDouble(baData))
v.rotation = vector(me.readDouble(baData),me.readDouble(baData),me.readDouble(baData))
v.axisangle[1] = vector(me.readDouble(baData),me.readDouble(baData),me.readDouble(baData))
v.axisangle[2] = me.readDouble(baData)
"date":
y = baData.readInt16()
m = baData.readInt8()
d = baData.readInt8()
s = baData.readInt32()
v = date(y,m,d)
v.seconds = s
"colo":
v = RGB(baData.readInt8(),baData.readInt8(),baData.readInt8())
"spri":
v = sprite(baData.readInt16())
"memb":
v = member(baData.readInt16(),baData.readInt16())
"cast":
v = castLib(baData.readInt16())
otherwise: -- everything that can be evaluated directly using value()...?
v = value(baData.readString())
end case
return v
end
----------------------------------------
-- select a method
----------------------------------------
on writeDouble (me, baData, v)
-- A) SAVE FLOAT AS DOUBLE PRECISION IEEE-754 ( = 8 bytes, uses lingo, SLOW!)
writeDouble_lingo(baData, v)
-- B) SAVE FLOAT AS DOUBLE PRECISION IEEE-754 ( = 8 bytes, requires CRYPTO XTRA v0.9+)
-- cx_writeDouble(baData, v)
-- C) SAVE FLOAT AS STRING REPRESENTATION (with max. floatprecision = 15)
-- op = the floatprecision
-- the floatprecision = 15
-- baData.writeString(string(v))
-- the floatprecision = op
-- D) SAVE AS INT (IN CASE IT'S ACTUALLY AN INT)
-- baData.writeInt32(v)
end
----------------------------------------
-- select a method
----------------------------------------
on readDouble (me, baData)
-- A) FLOAT AS DOUBLE PRECISION IEEE-754 ( = 8 bytes, uses lingo, SLOW!)
return readDouble_lingo(baData)
-- B) FLOAT AS DOUBLE PRECISION IEEE-754 ( = 8 bytes, requires CRYPTO XTRA v0.9+)
-- return cx_readDouble(baData)
-- C) FLOAT AS STRING REPRESENTATION (with max. floatprecision = 15)
-- return float(baData.readString())
-- D) AS INT (IN CASE IT'S ACTUALLY AN INT)
-- return baData.readInt32()
end
----------------------------------------
-- WRITES FLOAT AS DOUBLE-PRECISION IEEE-754 TO BYTEARARY
----------------------------------------
on writeDouble_lingo(ba, v)
bits = []
bits[64] = 0
bits[1] = (v<0) -- sign bit
BinVal = []
BinVal[2102] = 0
-- seperate integer and decimal parts
val = abs(v)
intpart = bitOr(val, 0) -- floor
decpart = val - intpart
-- convert integer part
index1 = 1024
repeat while (((intpart<>0) > 0) AND (index1 > = 0))
BinVal[index1 +1] = intpart mod 2
intpart = intpart / 2
index1 = index1-1
end repeat
-- convert decimal part
index1 = 1025
repeat while ((decpart > 0) AND (index1 < 2102))
decpart = decpart*2
if (decpart > = 1) then
BinVal[index1 +1] = 1
decpart = decpart-1
else
BinVal[index1 +1] = 0
end if
index1 = index1+1
end repeat
-- find most significant bit of significand
index1 = BinVal.getPos(1)-1
if index1<0 then index1 = 2102
binexpnt = 1024 - index1
if ((binexpnt > = -1022) AND (binexpnt < = 1023)) then
index1 = index1+1
else if (binexpnt < -1022) then
binexpnt = -1023
index1 = 1024 - binexpnt
end if
-- copy the result
index2 = 12
repeat while ((index2 < 64) AND (index1 < 2102))
bits[index2 +1] = BinVal[index1 +1]
index2 = index2+1
index1 = index1+1
end repeat
-- convert exponent value to binary representation
index1 = 11
binexpnt = binexpnt+1023
repeat while (binexpnt>0)
bits[index1 +1] = binexpnt mod 2
binexpnt = binexpnt / 2
index1 = index1-1
end repeat
-- save 64 bits as 8 bytes in bytearray
repeat with i = 7 down to 0
s = 0
d = 1
repeat with j = 1 to 8
n = i*8+9-j
s = s + bits[n]*d
d = d*2
end repeat
ba.writeInt8(s)
end repeat
end
----------------------------------------
-- READS FLOAT AS DOUBLE-PRECISION IEEE-754 FROM BYTEARARY
----------------------------------------
on readDouble_lingo(ba)
-- read 8 bytes from bytearray as 64 bits
bits = []
f = [128,64,32,16,8,4,2,1]
repeat with i = 7 down to 0
n = ba.readInt8()
i8 = i*8
repeat with j = 1 to 8
k = f[j]
bits[i8 + j] = integer( bitAnd(k, n)/k)
end repeat
end repeat
-- convert bits to float
expo = 0
d = 1
repeat with i = 1 to 11
expo = expo + d * bits[13 - i]
d = d*2
end repeat
expo = expo - 1023
frac = 0.0
d = 1.0
repeat with i = 1 to 52
frac = frac + d * bits[65 - i]
d = d*2
end repeat
frac = frac / 4503599627370496.0
v = power(2, expo) * (1+frac)
if bits[1] then v = -v
return v
end