2 * Heap Buffer object representation. Used for all Buffer variants.
5 #ifndef DUK_HBUFFEROBJECT_H_INCLUDED
6 #define DUK_HBUFFEROBJECT_H_INCLUDED
8 /* All element accessors are host endian now (driven by TypedArray spec). */
9 #define DUK_HBUFFEROBJECT_ELEM_UINT8 0
10 #define DUK_HBUFFEROBJECT_ELEM_UINT8CLAMPED 1
11 #define DUK_HBUFFEROBJECT_ELEM_INT8 2
12 #define DUK_HBUFFEROBJECT_ELEM_UINT16 3
13 #define DUK_HBUFFEROBJECT_ELEM_INT16 4
14 #define DUK_HBUFFEROBJECT_ELEM_UINT32 5
15 #define DUK_HBUFFEROBJECT_ELEM_INT32 6
16 #define DUK_HBUFFEROBJECT_ELEM_FLOAT32 7
17 #define DUK_HBUFFEROBJECT_ELEM_FLOAT64 8
18 #define DUK_HBUFFEROBJECT_ELEM_MAX 8
20 #define DUK_ASSERT_HBUFFEROBJECT_VALID(h) do { \
21 DUK_ASSERT((h) != NULL); \
22 DUK_ASSERT((h)->shift <= 3); \
23 DUK_ASSERT((h)->elem_type <= DUK_HBUFFEROBJECT_ELEM_MAX); \
24 DUK_ASSERT(((h)->shift == 0 && (h)->elem_type == DUK_HBUFFEROBJECT_ELEM_UINT8) || \
25 ((h)->shift == 0 && (h)->elem_type == DUK_HBUFFEROBJECT_ELEM_UINT8CLAMPED) || \
26 ((h)->shift == 0 && (h)->elem_type == DUK_HBUFFEROBJECT_ELEM_INT8) || \
27 ((h)->shift == 1 && (h)->elem_type == DUK_HBUFFEROBJECT_ELEM_UINT16) || \
28 ((h)->shift == 1 && (h)->elem_type == DUK_HBUFFEROBJECT_ELEM_INT16) || \
29 ((h)->shift == 2 && (h)->elem_type == DUK_HBUFFEROBJECT_ELEM_UINT32) || \
30 ((h)->shift == 2 && (h)->elem_type == DUK_HBUFFEROBJECT_ELEM_INT32) || \
31 ((h)->shift == 2 && (h)->elem_type == DUK_HBUFFEROBJECT_ELEM_FLOAT32) || \
32 ((h)->shift == 3 && (h)->elem_type == DUK_HBUFFEROBJECT_ELEM_FLOAT64)); \
33 DUK_ASSERT((h)->is_view == 0 || (h)->is_view == 1); \
34 DUK_ASSERT(DUK_HOBJECT_IS_BUFFEROBJECT((duk_hobject *) (h))); \
35 if ((h)->buf == NULL) { \
36 DUK_ASSERT((h)->offset == 0); \
37 DUK_ASSERT((h)->length == 0); \
39 /* No assertions for offset or length; in particular, \
40 * it's OK for length to be longer than underlying \
41 * buffer. Just ensure they don't wrap when added. \
43 DUK_ASSERT((h)->offset + (h)->length >= (h)->offset); \
47 /* Get the current data pointer (caller must ensure buf != NULL) as a
50 #define DUK_HBUFFEROBJECT_GET_SLICE_BASE(heap,h) \
51 (DUK_ASSERT_EXPR((h) != NULL), DUK_ASSERT_EXPR((h)->buf != NULL), \
52 (((duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR((heap), (h)->buf)) + (h)->offset))
54 /* True if slice is full, i.e. offset is zero and length covers the entire
55 * buffer. This status may change independently of the duk_hbufferobject if
56 * the underlying buffer is dynamic and changes without the hbufferobject
59 #define DUK_HBUFFEROBJECT_FULL_SLICE(h) \
60 (DUK_ASSERT_EXPR((h) != NULL), DUK_ASSERT_EXPR((h)->buf != NULL), \
61 ((h)->offset == 0 && (h)->length == DUK_HBUFFER_GET_SIZE((h)->buf)))
63 /* Validate that the whole slice [0,length[ is contained in the underlying
64 * buffer. Caller must ensure 'buf' != NULL.
66 #define DUK_HBUFFEROBJECT_VALID_SLICE(h) \
67 (DUK_ASSERT_EXPR((h) != NULL), DUK_ASSERT_EXPR((h)->buf != NULL), \
68 ((h)->offset + (h)->length <= DUK_HBUFFER_GET_SIZE((h)->buf)))
70 /* Validate byte read/write for virtual 'offset', i.e. check that the
71 * offset, taking into account h->offset, is within the underlying
72 * buffer size. This is a safety check which is needed to ensure
73 * that even a misconfigured duk_hbufferobject never causes memory
74 * unsafe behavior (e.g. if an underlying dynamic buffer changes
75 * after being setup). Caller must ensure 'buf' != NULL.
77 #define DUK_HBUFFEROBJECT_VALID_BYTEOFFSET_INCL(h,off) \
78 (DUK_ASSERT_EXPR((h) != NULL), DUK_ASSERT_EXPR((h)->buf != NULL), \
79 ((h)->offset + (off) < DUK_HBUFFER_GET_SIZE((h)->buf)))
81 #define DUK_HBUFFEROBJECT_VALID_BYTEOFFSET_EXCL(h,off) \
82 (DUK_ASSERT_EXPR((h) != NULL), DUK_ASSERT_EXPR((h)->buf != NULL), \
83 ((h)->offset + (off) <= DUK_HBUFFER_GET_SIZE((h)->buf)))
85 /* Clamp an input byte length (already assumed to be within the nominal
86 * duk_hbufferobject 'length') to the current dynamic buffer limits to
87 * yield a byte length limit that's safe for memory accesses. This value
88 * can be invalidated by any side effect because it may trigger a user
89 * callback that resizes the underlying buffer.
91 #define DUK_HBUFFEROBJECT_CLAMP_BYTELENGTH(h,len) \
92 (DUK_ASSERT_EXPR((h) != NULL), \
93 duk_hbufferobject_clamp_bytelength((h), (len)))
95 struct duk_hbufferobject
{
96 /* Shared object part. */
99 /* Underlying buffer (refcounted), may be NULL. */
102 /* Slice and accessor information.
104 * Because the underlying buffer may be dynamic, these may be
105 * invalidated by the buffer being modified so that both offset
106 * and length should be validated before every access. Behavior
107 * when the underlying buffer has changed doesn't need to be clean:
108 * virtual 'length' doesn't need to be affected, reads can return
109 * zero/NaN, and writes can be ignored.
111 * Note that a data pointer cannot be precomputed because 'buf' may
112 * be dynamic and its pointer unstable.
115 duk_uint_t offset
; /* byte offset to buf */
116 duk_uint_t length
; /* byte index limit for element access, exclusive */
117 duk_uint8_t shift
; /* element size shift:
123 duk_uint8_t elem_type
; /* element type */
127 #if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
128 DUK_INTERNAL_DECL duk_uint_t
duk_hbufferobject_clamp_bytelength(duk_hbufferobject
*h_bufobj
, duk_uint_t len
);
130 DUK_INTERNAL_DECL
void duk_hbufferobject_push_validated_read(duk_context
*ctx
, duk_hbufferobject
*h_bufobj
, duk_uint8_t
*p
, duk_small_uint_t elem_size
);
131 DUK_INTERNAL_DECL
void duk_hbufferobject_validated_write(duk_context
*ctx
, duk_hbufferobject
*h_bufobj
, duk_uint8_t
*p
, duk_small_uint_t elem_size
);
133 #endif /* DUK_HBUFFEROBJECT_H_INCLUDED */