Home | History | Annotate | Download | only in glsl
      1 /*
      2  * Copyright  2014 Intel Corporation
      3  *
      4  * Permission is hereby granted, free of charge, to any person obtaining a
      5  * copy of this software and associated documentation files (the "Software"),
      6  * to deal in the Software without restriction, including without limitation
      7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      8  * and/or sell copies of the Software, and to permit persons to whom the
      9  * Software is furnished to do so, subject to the following conditions:
     10  *
     11  * The above copyright notice and this permission notice (including the next
     12  * paragraph) shall be included in all copies or substantial portions of the
     13  * Software.
     14  *
     15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
     20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
     21  * IN THE SOFTWARE.
     22  */
     23 
     24 #include <string.h>
     25 
     26 #include "main/macros.h"
     27 #include "util/ralloc.h"
     28 #include "blob.h"
     29 
     30 #define BLOB_INITIAL_SIZE 4096
     31 
     32 /* Ensure that \blob will be able to fit an additional object of size
     33  * \additional.  The growing (if any) will occur by doubling the existing
     34  * allocation.
     35  */
     36 static bool
     37 grow_to_fit(struct blob *blob, size_t additional)
     38 {
     39    size_t to_allocate;
     40    uint8_t *new_data;
     41 
     42    if (blob->size + additional <= blob->allocated)
     43       return true;
     44 
     45    if (blob->allocated == 0)
     46       to_allocate = BLOB_INITIAL_SIZE;
     47    else
     48       to_allocate = blob->allocated * 2;
     49 
     50    to_allocate = MAX2(to_allocate, blob->allocated + additional);
     51 
     52    new_data = reralloc_size(blob, blob->data, to_allocate);
     53    if (new_data == NULL)
     54       return false;
     55 
     56    blob->data = new_data;
     57    blob->allocated = to_allocate;
     58 
     59    return true;
     60 }
     61 
     62 /* Align the blob->size so that reading or writing a value at (blob->data +
     63  * blob->size) will result in an access aligned to a granularity of \alignment
     64  * bytes.
     65  *
     66  * \return True unless allocation fails
     67  */
     68 static bool
     69 align_blob(struct blob *blob, size_t alignment)
     70 {
     71    const size_t new_size = ALIGN(blob->size, alignment);
     72 
     73    if (! grow_to_fit (blob, new_size - blob->size))
     74       return false;
     75 
     76    blob->size = new_size;
     77 
     78    return true;
     79 }
     80 
     81 static void
     82 align_blob_reader(struct blob_reader *blob, size_t alignment)
     83 {
     84    blob->current = blob->data + ALIGN(blob->current - blob->data, alignment);
     85 }
     86 
     87 struct blob *
     88 blob_create(void *mem_ctx)
     89 {
     90    struct blob *blob;
     91 
     92    blob = ralloc(mem_ctx, struct blob);
     93    if (blob == NULL)
     94       return NULL;
     95 
     96    blob->data = NULL;
     97    blob->allocated = 0;
     98    blob->size = 0;
     99 
    100    return blob;
    101 }
    102 
    103 bool
    104 blob_overwrite_bytes(struct blob *blob,
    105                      size_t offset,
    106                      const void *bytes,
    107                      size_t to_write)
    108 {
    109    /* Detect an attempt to overwrite data out of bounds. */
    110    if (offset < 0 || blob->size - offset < to_write)
    111       return false;
    112 
    113    memcpy(blob->data + offset, bytes, to_write);
    114 
    115    return true;
    116 }
    117 
    118 bool
    119 blob_write_bytes(struct blob *blob, const void *bytes, size_t to_write)
    120 {
    121    if (! grow_to_fit(blob, to_write))
    122        return false;
    123 
    124    memcpy(blob->data + blob->size, bytes, to_write);
    125    blob->size += to_write;
    126 
    127    return true;
    128 }
    129 
    130 uint8_t *
    131 blob_reserve_bytes(struct blob *blob, size_t to_write)
    132 {
    133    uint8_t *ret;
    134 
    135    if (! grow_to_fit (blob, to_write))
    136       return NULL;
    137 
    138    ret = blob->data + blob->size;
    139    blob->size += to_write;
    140 
    141    return ret;
    142 }
    143 
    144 bool
    145 blob_write_uint32(struct blob *blob, uint32_t value)
    146 {
    147    align_blob(blob, sizeof(value));
    148 
    149    return blob_write_bytes(blob, &value, sizeof(value));
    150 }
    151 
    152 bool
    153 blob_overwrite_uint32 (struct blob *blob,
    154                        size_t offset,
    155                        uint32_t value)
    156 {
    157    return blob_overwrite_bytes(blob, offset, &value, sizeof(value));
    158 }
    159 
    160 bool
    161 blob_write_uint64(struct blob *blob, uint64_t value)
    162 {
    163    align_blob(blob, sizeof(value));
    164 
    165    return blob_write_bytes(blob, &value, sizeof(value));
    166 }
    167 
    168 bool
    169 blob_write_intptr(struct blob *blob, intptr_t value)
    170 {
    171    align_blob(blob, sizeof(value));
    172 
    173    return blob_write_bytes(blob, &value, sizeof(value));
    174 }
    175 
    176 bool
    177 blob_write_string(struct blob *blob, const char *str)
    178 {
    179    return blob_write_bytes(blob, str, strlen(str) + 1);
    180 }
    181 
    182 void
    183 blob_reader_init(struct blob_reader *blob, uint8_t *data, size_t size)
    184 {
    185    blob->data = data;
    186    blob->end = data + size;
    187    blob->current = data;
    188    blob->overrun = false;
    189 }
    190 
    191 /* Check that an object of size \size can be read from this blob.
    192  *
    193  * If not, set blob->overrun to indicate that we attempted to read too far.
    194  */
    195 static bool
    196 ensure_can_read(struct blob_reader *blob, size_t size)
    197 {
    198    if (blob->current < blob->end && blob->end - blob->current >= size)
    199       return true;
    200 
    201    blob->overrun = true;
    202 
    203    return false;
    204 }
    205 
    206 void *
    207 blob_read_bytes(struct blob_reader *blob, size_t size)
    208 {
    209    void *ret;
    210 
    211    if (! ensure_can_read (blob, size))
    212       return NULL;
    213 
    214    ret = blob->current;
    215 
    216    blob->current += size;
    217 
    218    return ret;
    219 }
    220 
    221 void
    222 blob_copy_bytes(struct blob_reader *blob, uint8_t *dest, size_t size)
    223 {
    224    uint8_t *bytes;
    225 
    226    bytes = blob_read_bytes(blob, size);
    227    if (bytes == NULL)
    228       return;
    229 
    230    memcpy(dest, bytes, size);
    231 }
    232 
    233 /* These next three read functions have identical form. If we add any beyond
    234  * these first three we should probably switch to generating these with a
    235  * preprocessor macro.
    236 */
    237 uint32_t
    238 blob_read_uint32(struct blob_reader *blob)
    239 {
    240    uint32_t ret;
    241    int size = sizeof(ret);
    242 
    243    align_blob_reader(blob, size);
    244 
    245    if (! ensure_can_read(blob, size))
    246       return 0;
    247 
    248    ret = *((uint32_t*) blob->current);
    249 
    250    blob->current += size;
    251 
    252    return ret;
    253 }
    254 
    255 uint64_t
    256 blob_read_uint64(struct blob_reader *blob)
    257 {
    258    uint64_t ret;
    259    int size = sizeof(ret);
    260 
    261    align_blob_reader(blob, size);
    262 
    263    if (! ensure_can_read(blob, size))
    264       return 0;
    265 
    266    ret = *((uint64_t*) blob->current);
    267 
    268    blob->current += size;
    269 
    270    return ret;
    271 }
    272 
    273 intptr_t
    274 blob_read_intptr(struct blob_reader *blob)
    275 {
    276    intptr_t ret;
    277    int size = sizeof(ret);
    278 
    279    align_blob_reader(blob, size);
    280 
    281    if (! ensure_can_read(blob, size))
    282       return 0;
    283 
    284    ret = *((intptr_t *) blob->current);
    285 
    286    blob->current += size;
    287 
    288    return ret;
    289 }
    290 
    291 char *
    292 blob_read_string(struct blob_reader *blob)
    293 {
    294    int size;
    295    char *ret;
    296    uint8_t *nul;
    297 
    298    /* If we're already at the end, then this is an overrun. */
    299    if (blob->current >= blob->end) {
    300       blob->overrun = true;
    301       return NULL;
    302    }
    303 
    304    /* Similarly, if there is no zero byte in the data remaining in this blob,
    305     * we also consider that an overrun.
    306     */
    307    nul = memchr(blob->current, 0, blob->end - blob->current);
    308 
    309    if (nul == NULL) {
    310       blob->overrun = true;
    311       return NULL;
    312    }
    313 
    314    size = nul - blob->current + 1;
    315 
    316    assert(ensure_can_read(blob, size));
    317 
    318    ret = (char *) blob->current;
    319 
    320    blob->current += size;
    321 
    322    return ret;
    323 }
    324