hummus-recipe
Version:
A powerful PDF tool for NodeJS based on HummusJS
126 lines (99 loc) • 3.04 kB
text/coffeescript
utils = require './utils'
class Pointer
constructor: (, , = {}) ->
= null if is 'void'
.type ?= 'local'
.allowNull ?= true
.nullValue ?= 0
.lazy ?= false
if .relativeTo
= new Function('ctx', "return ctx.#{@options.relativeTo}")
decode: (stream, ctx) ->
offset = .decode(stream, ctx)
# handle NULL pointers
if offset is .nullValue and .allowNull
return null
relative = switch .type
when 'local' then ctx._startOffset
when 'immediate' then stream.pos - .size()
when 'parent' then ctx.parent._startOffset
else
c = ctx
while c.parent
c = c.parent
c._startOffset or 0
if .relativeTo
relative += ctx
ptr = offset + relative
if ?
val = null
decodeValue = =>
return val if val?
pos = stream.pos
stream.pos = ptr
val = .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 .lazy
return new utils.PropertyDescriptor
get: decodeValue
return decodeValue()
else
return ptr
size: (val, ctx) ->
parent = ctx
switch .type
when 'local', 'immediate'
break
when 'parent'
ctx = ctx.parent
else # global
while ctx.parent
ctx = ctx.parent
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 .size()
encode: (stream, val, ctx) ->
parent = ctx
if not val?
.encode(stream, .nullValue)
return
switch .type
when 'local'
relative = ctx.startOffset
when 'immediate'
relative = stream.pos + .size(val, parent)
when 'parent'
ctx = ctx.parent
relative = ctx.startOffset
else # global
relative = 0
while ctx.parent
ctx = ctx.parent
if .relativeTo
relative += parent.val
.encode(stream, ctx.pointerOffset - relative)
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: (, ) ->
exports.Pointer = Pointer
exports.VoidPointer = VoidPointer