Esempio n. 1
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;
}
Esempio n. 2
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;
}
Esempio n. 3
0
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;
}
SOL_API const char *
sol_network_link_addr_to_str(const struct sol_network_link_addr *addr,
    struct sol_buffer *buf)
{
    char *p;
    int i;
    bool sep = false, skipping = false, treated_zeroes = false;

    SOL_NULL_CHECK(addr, NULL);
    SOL_NULL_CHECK(buf, NULL);

    if (sol_bluetooth_is_family(addr->family))
        return sol_bluetooth_addr_to_str(addr, buf);

    if (addr->family != SOL_NETWORK_FAMILY_INET6)
        return NULL;

    if (buf->capacity - buf->used < SOL_NETWORK_INET_ADDR_STR_LEN)
        return NULL;

    p = sol_buffer_at_end(buf);

    for (i = 0; i < 16; i += 2) {
        uint16_t part;

        part = ((uint16_t)addr->addr.in6[i] << 8) | addr->addr.in6[i + 1];
        if (part && skipping) {
            skipping = false;
            treated_zeroes = true;
            sep = true;
        }
        if (!part && !treated_zeroes) {
            if (!skipping) {
                skipping = true;
                sep = true;
            }
        }
        if (sep) {
            sol_buffer_append_char(buf, ':');
            if (skipping)
                sep = false;
        }
        if (skipping)
            continue;
        sol_buffer_append_printf(buf, "%" PRIx16, part);
        sep = true;
    }
    if (skipping)
        sol_buffer_append_char(buf, ':');

    return p;
}
Esempio n. 5
0
SOL_API int
sol_buffer_append_from_base16(struct sol_buffer *buf, 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);

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

    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_end(buf);
    r = sol_util_base16_decode(p, decoded_size, slice, decode_case);
    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;
}
Esempio n. 6
0
SOL_API int
sol_buffer_append_as_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 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_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_end(buf);
    r = sol_util_base64_encode(p, encoded_size, slice, base64_map);
    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;
}
Esempio n. 7
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;
}
Esempio n. 8
0
SOL_API char *
sol_util_strerror(int errnum, struct sol_buffer *buf)
{
    char *ret;
    int err;

    SOL_NULL_CHECK(buf, NULL);

#define CHUNK_SIZE (512)

#ifdef HAVE_XSI_STRERROR_R
    /* XSI-compliant strerror_r returns int */
    while (1) {
        errno = 0;
        ret = sol_buffer_at_end(buf);
        err = strerror_r(errnum, ret, buf->capacity - buf->used);

        if (err == ERANGE || (err < 0 && errno == ERANGE)) {
            err = sol_buffer_expand(buf, CHUNK_SIZE);
            SOL_INT_CHECK(err, < 0, NULL);
        } else if (err != 0)
Esempio n. 9
0
SOL_API char *
sol_json_escape_string(const char *str, struct sol_buffer *buf)
{
    char *out, *r_str;
    size_t i, escaped_len;
    int r;

    SOL_NULL_CHECK(str, NULL);
    SOL_NULL_CHECK(buf, NULL);

    escaped_len = sol_json_calculate_escaped_string_len(str);

    r = sol_buffer_expand(buf, escaped_len);
    SOL_INT_CHECK(r, < 0, NULL);

    r_str = out = sol_buffer_at_end(buf);

    for (i = 0; *str && i < escaped_len; str++, i++) {
        if (memchr(sol_json_escapable_chars, *str, sizeof(sol_json_escapable_chars))) {
            *out++ = '\\';
            switch (*str) {
            case '"':  *out++ = '"'; break;
            case '\\': *out++ = '\\'; break;
            case '/':  *out++ = '/'; break;
            case '\b': *out++ = 'b'; break;
            case '\f': *out++ = 'f'; break;
            case '\n': *out++ = 'n'; break;
            case '\r': *out++ = 'r'; break;
            case '\t': *out++ = 't'; break;
            }
        } else {
            *out++ = *str;
        }
    }

    *out++ = '\0';
    buf->used += escaped_len - 1;

    return r_str;
}
Esempio n. 10
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;
}
Esempio n. 11
0
    const char *r;

    SOL_NULL_CHECK(addr, NULL);
    SOL_NULL_CHECK(buf, NULL);

    if (addr->family != SOL_NETWORK_FAMILY_INET6)
        return NULL;

    if (buf->capacity - buf->used < IPV6_ADDR_MAX_STR_LEN) {
        int err;

        err = sol_buffer_expand(buf, IPV6_ADDR_MAX_STR_LEN);
        SOL_INT_CHECK(err, < 0, NULL);
    }

    r = ipv6_addr_to_str(sol_buffer_at_end(buf), (ipv6_addr_t *)&addr->addr,
        IPV6_ADDR_MAX_STR_LEN);

    if (r)
        buf->used += strlen(r);

    return r;

#else
    return NULL;
#endif
}

SOL_API const struct sol_network_link_addr *
sol_network_link_addr_from_str(struct sol_network_link_addr *addr, const char *buf)
{