Exemple #1
0
static void
test_ensure(void)
{
    struct sol_buffer buf = SOL_BUFFER_INIT_EMPTY;
    const int size = 1024;
    char *buf_data;
    int i;

    sol_buffer_ensure(&buf, size);

    memset(buf.data, 22, size);

    sol_buffer_ensure(&buf, size * 2);
    buf_data = buf.data;
    for (i = 0; i < size; i++) {
        ASSERT_INT_EQ(buf_data[i], 22);
    }

    sol_buffer_ensure(&buf, size / 2);
    buf_data = buf.data;
    for (i = 0; i < size / 2; i++) {
        ASSERT_INT_EQ(buf_data[i], 22);
    }

    sol_buffer_fini(&buf);
}
SOL_API int
sol_buffer_append_slice(struct sol_buffer *buf, const struct sol_str_slice slice)
{
    const size_t nul_size = nul_byte_size(buf);
    char *p;
    size_t new_size;
    int err;

    SOL_NULL_CHECK(buf, -EINVAL);

    err = sol_util_size_add(buf->used, slice.len, &new_size);
    if (err < 0)
        return err;

    /* Extra room for the ending NUL-byte. */
    if (new_size >= SIZE_MAX - nul_size)
        return -EOVERFLOW;
    err = sol_buffer_ensure(buf, new_size + nul_size);
    if (err < 0)
        return err;

    p = sol_buffer_at_end(buf);
    memcpy(p, slice.data, slice.len);

    if (nul_size)
        p[slice.len] = '\0';
    buf->used += slice.len;
    return 0;
}
Exemple #3
0
SOL_API int
sol_buffer_set_char_at(struct sol_buffer *buf, size_t pos, char c)
{
    int err;
    const size_t nul_size = nul_byte_size(buf);

    SOL_NULL_CHECK(buf, -EINVAL);
    if (buf->used < pos) {
        return -EINVAL;
    }

    /* Extra room for the ending NUL-byte. */
    if (1 >= SIZE_MAX - nul_size - pos)
        return -EOVERFLOW;
    err = sol_buffer_ensure(buf, pos + 1 + nul_size);
    if (err < 0)
        return err;

    *((char *)buf->data + pos) = c;

    if (pos + 1 >= buf->used)
        buf->used = pos + 1;

    if (nul_byte_size(buf))
        return sol_buffer_ensure_nul_byte(buf);

    return 0;
}
SOL_API int
sol_buffer_append_char(struct sol_buffer *buf, const char c)
{
    char *p;
    size_t new_size;
    int err;

    SOL_NULL_CHECK(buf, -EINVAL);

    err = sol_util_size_add(buf->used, 1, &new_size);
    if (err < 0)
        return err;

    err = sol_buffer_ensure(buf, new_size);
    if (err < 0)
        return err;

    p = sol_buffer_at_end(buf);
    *p = c;
    buf->used++;

    if (nul_byte_size(buf))
        return sol_buffer_ensure_nul_byte(buf);
    return 0;
}
Exemple #5
0
static void
test_no_nul_byte(void)
{
    struct sol_buffer buf;
    int32_t backend;
    int32_t value = 0xdeadbeef;
    int err;

    sol_buffer_init_flags(&buf, &backend, sizeof(backend),
        SOL_BUFFER_FLAGS_MEMORY_NOT_OWNED | SOL_BUFFER_FLAGS_NO_NUL_BYTE);

    err = sol_buffer_ensure(&buf, sizeof(int32_t));
    ASSERT_INT_EQ(err, 0);

    err = sol_buffer_append_slice(&buf, SOL_STR_SLICE_STR((const char *)&value, sizeof(value)));
    ASSERT_INT_EQ(err, 0);

    err = sol_buffer_append_slice(&buf, SOL_STR_SLICE_STR((const char *)&value, sizeof(value)));
    ASSERT_INT_NE(err, 0);

    sol_buffer_fini(&buf);

    sol_buffer_init_flags(&buf, NULL, 0, SOL_BUFFER_FLAGS_NO_NUL_BYTE);
    err = sol_buffer_append_printf(&buf, "123");
    ASSERT_INT_EQ(err, 0);
    err = sol_buffer_append_printf(&buf, "4");
    ASSERT_INT_EQ(err, 0);

    ASSERT(sol_str_slice_eq(sol_buffer_get_slice(&buf),
        SOL_STR_SLICE_STR("1234", 4)));
    sol_buffer_fini(&buf);
}
SOL_API int
sol_buffer_insert_char(struct sol_buffer *buf, size_t pos, const char c)
{
    char *p;
    size_t new_size;
    int err;

    SOL_NULL_CHECK(buf, -EINVAL);
    SOL_INT_CHECK(pos, > buf->used, -EINVAL);

    if (pos == buf->used)
        return sol_buffer_append_char(buf, c);

    err = sol_util_size_add(buf->used, 1, &new_size);
    if (err < 0)
        return err;

    err = sol_buffer_ensure(buf, new_size);
    if (err < 0)
        return err;

    p = sol_buffer_at(buf, pos);
    memmove(p + 1, p, buf->used - pos);
    *p = c;
    buf->used++;

    if (nul_byte_size(buf))
        return sol_buffer_ensure_nul_byte(buf);
    return 0;
}
SOL_API int
sol_buffer_set_slice_at(struct sol_buffer *buf, size_t pos, const struct sol_str_slice slice)
{
    int err;
    const size_t nul_size = nul_byte_size(buf);

    SOL_NULL_CHECK(buf, -EINVAL);
    if (buf->used < pos) {
        return -EINVAL;
    }

    /* Extra room for the ending NUL-byte. */
    if (slice.len >= SIZE_MAX - nul_size - pos)
        return -EOVERFLOW;
    err = sol_buffer_ensure(buf, pos + slice.len + nul_size);
    if (err < 0)
        return err;

    /* deal with possible overlaps with memmove */
    memmove((char *)buf->data + pos, slice.data, slice.len);

    if (pos + slice.len >= buf->used) {
        buf->used = pos + slice.len;
        /* only terminate if we're growing */
        ((char *)buf->data)[buf->used] = 0;
    }

    return 0;
}
/* Extra room for the ending NUL-byte, necessary even when the buffer has
 * SOL_BUFFER_FLAGS_NO_NUL_BYTE because vsnprintf always write the '\0'. */
SOL_API int
sol_buffer_append_vprintf(struct sol_buffer *buf, const char *fmt, va_list args)
{
    va_list args_copy;
    size_t space;
    char *p;
    ssize_t done;
    int r;

    SOL_NULL_CHECK(buf, -EINVAL);
    SOL_NULL_CHECK(fmt, -EINVAL);

    /* We need to copy args since we first try to do one vsnprintf()
     * to the existing space and if it doesn't fit we do a second
     * one. The second one would fail since args may be changed by
     * vsnprintf(), so the copy.
     */
    va_copy(args_copy, args);

    space = buf->capacity - buf->used;
    p = sol_buffer_at_end(buf);
    done = vsnprintf(p, space, fmt, args_copy);
    if (done < 0) {
        r = -errno;
        goto end;
    } else if ((size_t)done >= space) {
        size_t new_size;

        r = sol_util_size_add(buf->used, done, &new_size);
        if (r < 0)
            goto end;

        /* Extra room for the ending NUL-byte. */
        if (new_size >= SIZE_MAX - 1) {
            r = -EOVERFLOW;
            goto end;
        }
        r = sol_buffer_ensure(buf, new_size + 1);
        if (r < 0)
            goto end;

        space = buf->capacity - buf->used;
        p = sol_buffer_at_end(buf);
        done = vsnprintf(p, space, fmt, args);
        if (done < 0) {
            r = -errno;
            goto end;
        }
    }

    buf->used += done;
    r = 0;

end:
    va_end(args_copy);
    return r;
}
SOL_API ssize_t
sol_util_fill_buffer(int fd, struct sol_buffer *buffer, size_t size)
{
    size_t bytes_read = 0, s;
    unsigned int retry = 0;
    ssize_t ret;

    SOL_NULL_CHECK(buffer, -EINVAL);

    if (sol_util_size_add(buffer->used, size, &s) < 0)
        return -EOVERFLOW;

    ret = sol_buffer_ensure(buffer, s);
    if (ret < 0)
        return ret;

    do {
        ret = read(fd, (char *)buffer->data + buffer->used + bytes_read,
            size - bytes_read);
        if (ret < 0) {
            retry++;
            if (retry >= SOL_UTIL_MAX_READ_ATTEMPTS) {
                if (errno == EINTR || errno == EAGAIN) {
                    ret = 0; /* if we exceed maximum attempts, don't return error */
                }
                break;
            }

            if (errno == EINTR || errno == EAGAIN)
                continue;
            else
                break;
        } else if (ret == 0) {
            retry++;
            if (retry >= SOL_UTIL_MAX_READ_ATTEMPTS)
                break;
            continue;
        }

        retry = 0; //We only count consecutive failures
        bytes_read += (size_t)ret;
    } while (bytes_read < size);

    buffer->used += bytes_read;

    if (ret >= 0)
        ret = bytes_read;

    if (SOL_BUFFER_NEEDS_NUL_BYTE(buffer)) {
        int err;

        err = sol_buffer_ensure_nul_byte(buffer);
        SOL_INT_CHECK(err, < 0, err);
    }

    return ret;
}
Exemple #10
0
SOL_API int
sol_buffer_insert_from_base16(struct sol_buffer *buf, size_t pos, const struct sol_str_slice slice, enum sol_decode_case decode_case)
{
    char *p;
    size_t new_size;
    ssize_t decoded_size, r;
    const size_t nul_size = nul_byte_size(buf);
    int err;

    SOL_NULL_CHECK(buf, -EINVAL);
    SOL_INT_CHECK(pos, > buf->used, -EINVAL);

    if (slice.len == 0)
        return 0;

    if (pos == buf->used)
        return sol_buffer_append_from_base16(buf, slice, decode_case);

    decoded_size = sol_util_base16_calculate_decoded_len(slice);
    if (decoded_size < 0)
        return decoded_size;

    err = sol_util_size_add(buf->used, decoded_size, &new_size);
    if (err < 0)
        return err;

    if (nul_size) {
        err = sol_util_size_add(new_size, nul_size, &new_size);
        if (err < 0)
            return err;
    }

    err = sol_buffer_ensure(buf, new_size);
    if (err < 0)
        return err;

    p = sol_buffer_at(buf, pos);
    memmove(p + decoded_size, p, buf->used - pos);
    r = sol_util_base16_decode(p, decoded_size, slice, decode_case);
    if (r != decoded_size) {
        memmove(p, p + decoded_size, buf->used - pos);
        if (nul_size)
            sol_buffer_ensure_nul_byte(buf);
        if (r < 0)
            return r;
        else
            return -EINVAL;
    }

    buf->used += decoded_size;

    if (nul_size)
        return sol_buffer_ensure_nul_byte(buf);
    return 0;
}
Exemple #11
0
SOL_API int
sol_buffer_insert_as_base64(struct sol_buffer *buf, size_t pos, const struct sol_str_slice slice, const char base64_map[SOL_STATIC_ARRAY_SIZE(65)])
{
    char *p;
    size_t new_size;
    ssize_t encoded_size, r;
    const size_t nul_size = nul_byte_size(buf);
    int err;

    SOL_NULL_CHECK(buf, -EINVAL);
    SOL_INT_CHECK(pos, > buf->used, -EINVAL);

    if (slice.len == 0)
        return 0;

    if (pos == buf->used)
        return sol_buffer_append_as_base64(buf, slice, base64_map);

    encoded_size = sol_util_base64_calculate_encoded_len(slice, base64_map);
    if (encoded_size < 0)
        return encoded_size;

    err = sol_util_size_add(buf->used, encoded_size, &new_size);
    if (err < 0)
        return err;

    if (nul_size) {
        err = sol_util_size_add(new_size, nul_size, &new_size);
        if (err < 0)
            return err;
    }

    err = sol_buffer_ensure(buf, new_size);
    if (err < 0)
        return err;

    p = sol_buffer_at(buf, pos);
    memmove(p + encoded_size, p, buf->used - pos);
    r = sol_util_base64_encode(p, encoded_size, slice, base64_map);
    if (r != encoded_size) {
        memmove(p, p + encoded_size, buf->used - pos);
        if (nul_size)
            sol_buffer_ensure_nul_byte(buf);
        if (r < 0)
            return r;
        else
            return -EINVAL;
    }

    buf->used += encoded_size;

    if (nul_size)
        return sol_buffer_ensure_nul_byte(buf);
    return 0;
}
Exemple #12
0
static void
test_memory_not_owned(void)
{
    struct sol_buffer buf;
    struct sol_str_slice slice;
    char backend[10];
    int err;

    sol_buffer_init_flags(&buf, backend, sizeof(backend), SOL_BUFFER_FLAGS_MEMORY_NOT_OWNED);

    err = sol_buffer_ensure(&buf, 0);
    ASSERT_INT_EQ(err, 0);

    /* ensure considers null-byte, so we use sizeof - 1 */
    err = sol_buffer_ensure(&buf, sizeof(backend) - 1);
    ASSERT_INT_EQ(err, 0);

    err = sol_buffer_ensure(&buf, sizeof(backend) * 2);
    ASSERT_INT_EQ(err, -ENOMEM);

    err = sol_buffer_resize(&buf, 0);
    ASSERT_INT_EQ(err, -EPERM);

    slice = sol_str_slice_from_str("test");
    err = sol_buffer_append_slice(&buf, slice);
    ASSERT_INT_EQ(err, 0);
    ASSERT_STR_EQ(buf.data, "test");

    slice = sol_str_slice_from_str("other");
    err = sol_buffer_append_slice(&buf, slice);
    ASSERT_INT_EQ(err, 0);
    ASSERT_STR_EQ(buf.data, "testother");

    slice = sol_str_slice_from_str("OVERFLOW");
    err = sol_buffer_append_slice(&buf, slice);
    ASSERT_INT_EQ(err, -ENOMEM);

    sol_buffer_fini(&buf);
}
static void
test_ensure(void)
{
    struct sol_buffer buf = SOL_BUFFER_EMPTY;
    const int size = 1024;
    int i;

    sol_buffer_ensure(&buf, size);

    memset(buf.data, 22, size);

    sol_buffer_ensure(&buf, size * 2);
    for (i = 0; i < size; i++) {
        ASSERT(buf.data[i] == 22);
    }

    sol_buffer_ensure(&buf, size / 2);
    for (i = 0; i < size / 2; i++) {
        ASSERT(buf.data[i] == 22);
    }

    sol_buffer_fini(&buf);
}
Exemple #14
0
SOL_API int
sol_buffer_append_from_base64(struct sol_buffer *buf, const struct sol_str_slice slice, const char base64_map[SOL_STATIC_ARRAY_SIZE(65)])
{
    char *p;
    size_t new_size;
    ssize_t decoded_size, r;
    const size_t nul_size = nul_byte_size(buf);
    int err;

    SOL_NULL_CHECK(buf, -EINVAL);

    if (slice.len == 0)
        return 0;

    decoded_size = sol_util_base64_calculate_decoded_len(slice, base64_map);
    if (decoded_size < 0)
        return decoded_size;

    err = sol_util_size_add(buf->used, decoded_size, &new_size);
    if (err < 0)
        return err;

    if (nul_size) {
        err = sol_util_size_add(new_size, nul_size, &new_size);
        if (err < 0)
            return err;
    }

    err = sol_buffer_ensure(buf, new_size);
    if (err < 0)
        return err;

    p = sol_buffer_at_end(buf);
    r = sol_util_base64_decode(p, decoded_size, slice, base64_map);
    if (r != decoded_size) {
        if (nul_size)
            sol_buffer_ensure_nul_byte(buf);
        if (r < 0)
            return r;
        else
            return -EINVAL;
    }

    buf->used += decoded_size;

    if (nul_size)
        return sol_buffer_ensure_nul_byte(buf);
    return 0;
}
Exemple #15
0
ssize_t
sol_util_fill_buffer(const int fd, struct sol_buffer *buffer, const size_t size)
{
    size_t bytes_read = 0, s;
    unsigned int retry = 0;
    ssize_t ret;

    SOL_NULL_CHECK(buffer, -EINVAL);

    if (sol_util_size_add(buffer->used, size, &s) < 0)
        return -EOVERFLOW;

    ret = sol_buffer_ensure(buffer, s);
    if (ret < 0)
        return ret;

    do {
        ret = read(fd, (char *)buffer->data + buffer->used + bytes_read,
            size - bytes_read);
        if (ret < 0) {
            retry++;
            if (retry >= SOL_UTIL_MAX_READ_ATTEMPTS)
                break;

            if (errno == EINTR || errno == EAGAIN) {
                continue;
            } else
                break;
        }

        retry = 0; //We only count consecutive failures
        bytes_read += (size_t)ret;
    } while (ret && bytes_read < size);

    buffer->used += bytes_read;

    if (ret > 0)
        ret = bytes_read;

    if (!(buffer->flags & SOL_BUFFER_FLAGS_NO_NUL_BYTE)) {
        if (buffer->used == buffer->capacity)
            SOL_WRN("sol_buffer %p asks for terminating NUL byte, but doesn't have space for it",
                buffer);
        else
            *((char *)buffer->data + buffer->used) = '\0';
    }

    return ret;
}
Exemple #16
0
SOL_API int
sol_buffer_append_as_base16(struct sol_buffer *buf, const struct sol_str_slice slice, bool uppercase)
{
    char *p;
    size_t new_size;
    ssize_t encoded_size, r;
    const size_t nul_size = nul_byte_size(buf);
    int err;

    SOL_NULL_CHECK(buf, -EINVAL);

    if (slice.len == 0)
        return 0;

    encoded_size = sol_util_base16_calculate_encoded_len(slice);
    if (encoded_size < 0)
        return encoded_size;

    err = sol_util_size_add(buf->used, encoded_size, &new_size);
    if (err < 0)
        return err;

    if (nul_size) {
        err = sol_util_size_add(new_size, nul_size, &new_size);
        if (err < 0)
            return err;
    }

    err = sol_buffer_ensure(buf, new_size);
    if (err < 0)
        return err;

    p = sol_buffer_at_end(buf);
    r = sol_util_base16_encode(p, encoded_size, slice, uppercase);
    if (r != encoded_size) {
        if (nul_size)
            sol_buffer_ensure_nul_byte(buf);
        if (r < 0)
            return r;
        else
            return -EINVAL;
    }

    buf->used += encoded_size;

    if (nul_size)
        return sol_buffer_ensure_nul_byte(buf);
    return 0;
}
SOL_API int
sol_buffer_set_slice(struct sol_buffer *buf, const struct sol_str_slice slice)
{
    int err;

    SOL_NULL_CHECK(buf, -EINVAL);

    /* Extra room for the ending NUL-byte. */
    if (slice.len >= SIZE_MAX - nul_byte_size(buf))
        return -EOVERFLOW;
    err = sol_buffer_ensure(buf, slice.len + nul_byte_size(buf));
    if (err < 0)
        return err;

    sol_str_slice_copy(buf->data, slice);
    buf->used = slice.len;
    return 0;
}
SOL_API int
sol_buffer_ensure_nul_byte(struct sol_buffer *buf)
{
    SOL_NULL_CHECK(buf, -EINVAL);

    if (buf->flags & SOL_BUFFER_FLAGS_NO_NUL_BYTE)
        return -EINVAL;

    if (buf->used && *((char *)sol_buffer_at_end(buf) - 1) == '\0')
        return 0;

    if (buf->used >= SIZE_MAX - 1 ||
        sol_buffer_ensure(buf, buf->used + 1) < 0)
        return -ENOMEM;

    *((char *)buf->data + buf->used) = '\0';

    return 0;
}
Exemple #19
0
SOL_API int
sol_buffer_expand(struct sol_buffer *buf, size_t bytes)
{
    size_t new_size, available;
    int err;

    SOL_NULL_CHECK(buf, -EINVAL);

    available = buf->capacity - buf->used;

    if (available >= bytes)
        return 0;

    err = sol_util_size_add(buf->capacity, bytes - available, &new_size);
    SOL_INT_CHECK(err, < 0, err);
    err = sol_buffer_ensure(buf, new_size);
    SOL_INT_CHECK(err, < 0, err);

    return 0;
}
SOL_API int
sol_buffer_insert_slice(struct sol_buffer *buf, size_t pos, const struct sol_str_slice slice)
{
    const size_t nul_size = nul_byte_size(buf);
    char *p;
    size_t new_size;
    int err;

    SOL_NULL_CHECK(buf, -EINVAL);
    SOL_INT_CHECK(pos, > buf->used, -EINVAL);

    if (pos == buf->used)
        return sol_buffer_append_slice(buf, slice);

    err = sol_util_size_add(buf->used, slice.len, &new_size);
    if (err < 0)
        return err;

    /* Extra room for the ending NUL-byte. */
    if (new_size >= SIZE_MAX - nul_size)
        return -EOVERFLOW;
    err = sol_buffer_ensure(buf, new_size + nul_size);
    if (err < 0)
        return err;

    p = sol_buffer_at(buf, pos);
    memmove(p + slice.len, p, buf->used - pos);
    memcpy(p, slice.data, slice.len);
    buf->used += slice.len;

    if (nul_size) {
        p = sol_buffer_at_end(buf);
        p[0] = '\0';
    }

    return 0;
}