Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  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.