Current File : //home/tradevaly/www/node_modules/restructure/src/Pointer.coffee |
utils = require './utils'
class Pointer
constructor: (@offsetType, @type, @options = {}) ->
@type = null if @type is 'void'
@options.type ?= 'local'
@options.allowNull ?= true
@options.nullValue ?= 0
@options.lazy ?= false
if @options.relativeTo
@relativeToGetter = new Function('ctx', "return ctx.#{@options.relativeTo}")
decode: (stream, ctx) ->
offset = @offsetType.decode(stream, ctx)
# handle NULL pointers
if offset is @options.nullValue and @options.allowNull
return null
relative = switch @options.type
when 'local' then ctx._startOffset
when 'immediate' then stream.pos - @offsetType.size()
when 'parent' then ctx.parent._startOffset
else
c = ctx
while c.parent
c = c.parent
c._startOffset or 0
if @options.relativeTo
relative += @relativeToGetter ctx
ptr = offset + relative
if @type?
val = null
decodeValue = =>
return val if val?
pos = stream.pos
stream.pos = ptr
val = @type.decode(stream, ctx)
stream.pos = pos
return val
# If this is a lazy pointer, define a getter to decode only when needed.
# This obviously only works when the pointer is contained by a Struct.
if @options.lazy
return new utils.PropertyDescriptor
get: decodeValue
return decodeValue()
else
return ptr
size: (val, ctx) ->
parent = ctx
switch @options.type
when 'local', 'immediate'
break
when 'parent'
ctx = ctx.parent
else # global
while ctx.parent
ctx = ctx.parent
type = @type
unless type?
unless val instanceof VoidPointer
throw new Error "Must be a VoidPointer"
type = val.type
val = val.value
if val and ctx
ctx.pointerSize += type.size(val, parent)
return @offsetType.size()
encode: (stream, val, ctx) ->
parent = ctx
if not val?
@offsetType.encode(stream, @options.nullValue)
return
switch @options.type
when 'local'
relative = ctx.startOffset
when 'immediate'
relative = stream.pos + @offsetType.size(val, parent)
when 'parent'
ctx = ctx.parent
relative = ctx.startOffset
else # global
relative = 0
while ctx.parent
ctx = ctx.parent
if @options.relativeTo
relative += @relativeToGetter parent.val
@offsetType.encode(stream, ctx.pointerOffset - relative)
type = @type
unless type?
unless val instanceof VoidPointer
throw new Error "Must be a VoidPointer"
type = val.type
val = val.value
ctx.pointers.push
type: type
val: val
parent: parent
ctx.pointerOffset += type.size(val, parent)
# A pointer whose type is determined at decode time
class VoidPointer
constructor: (@type, @value) ->
exports.Pointer = Pointer
exports.VoidPointer = VoidPointer