|
|
Struct = require './Struct'
|
|
|
|
|
|
class VersionedStruct extends Struct
|
|
|
constructor: (@type, @versions = {}) ->
|
|
|
if typeof @type is 'string'
|
|
|
@versionGetter = new Function('parent', "return parent.#{@type}")
|
|
|
@versionSetter = new Function('parent', 'version', "return parent.#{@type} = version")
|
|
|
|
|
|
decode: (stream, parent, length = 0) ->
|
|
|
res = @_setup stream, parent, length
|
|
|
|
|
|
if typeof @type is 'string'
|
|
|
res.version = @versionGetter parent
|
|
|
else
|
|
|
res.version = @type.decode(stream)
|
|
|
|
|
|
if @versions.header
|
|
|
@_parseFields stream, res, @versions.header
|
|
|
|
|
|
fields = @versions[res.version]
|
|
|
if not fields?
|
|
|
throw new Error "Unknown version #{res.version}"
|
|
|
|
|
|
if fields instanceof VersionedStruct
|
|
|
return fields.decode(stream, parent)
|
|
|
|
|
|
@_parseFields stream, res, fields
|
|
|
|
|
|
@process?.call(res, stream)
|
|
|
return res
|
|
|
|
|
|
size: (val, parent, includePointers = true) ->
|
|
|
unless val
|
|
|
throw new Error 'Not a fixed size'
|
|
|
|
|
|
ctx =
|
|
|
parent: parent
|
|
|
val: val
|
|
|
pointerSize: 0
|
|
|
|
|
|
size = 0
|
|
|
if typeof @type isnt 'string'
|
|
|
size += @type.size(val.version, ctx)
|
|
|
|
|
|
if @versions.header
|
|
|
for key, type of @versions.header when type.size?
|
|
|
size += type.size(val[key], ctx)
|
|
|
|
|
|
fields = @versions[val.version]
|
|
|
if not fields?
|
|
|
throw new Error "Unknown version #{val.version}"
|
|
|
|
|
|
for key, type of fields when type.size?
|
|
|
size += type.size(val[key], ctx)
|
|
|
|
|
|
if includePointers
|
|
|
size += ctx.pointerSize
|
|
|
|
|
|
return size
|
|
|
|
|
|
encode: (stream, val, parent) ->
|
|
|
@preEncode?.call(val, stream)
|
|
|
|
|
|
ctx =
|
|
|
pointers: []
|
|
|
startOffset: stream.pos
|
|
|
parent: parent
|
|
|
val: val
|
|
|
pointerSize: 0
|
|
|
|
|
|
ctx.pointerOffset = stream.pos + @size(val, ctx, false)
|
|
|
|
|
|
if typeof @type isnt 'string'
|
|
|
@type.encode(stream, val.version)
|
|
|
|
|
|
if @versions.header
|
|
|
for key, type of @versions.header when type.encode?
|
|
|
type.encode(stream, val[key], ctx)
|
|
|
|
|
|
fields = @versions[val.version]
|
|
|
for key, type of fields when type.encode?
|
|
|
type.encode(stream, val[key], ctx)
|
|
|
|
|
|
i = 0
|
|
|
while i < ctx.pointers.length
|
|
|
ptr = ctx.pointers[i++]
|
|
|
ptr.type.encode(stream, ptr.val, ptr.parent)
|
|
|
|
|
|
return
|
|
|
|
|
|
module.exports = VersionedStruct
|
|
|
|