blob: a798f7a959a0cd254f5b49670b90a4b9afda4e78 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to you under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
* implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include "avro_private.h"
#include "avro/allocation.h"
#include "avro/data.h"
#include "avro/refcount.h"
struct avro_wrapped_copy {
volatile int refcount;
size_t allocated_size;
};
static void
avro_wrapped_copy_free(avro_wrapped_buffer_t *self)
{
struct avro_wrapped_copy *copy = (struct avro_wrapped_copy *) self->user_data;
if (avro_refcount_dec(&copy->refcount)) {
avro_free(copy, copy->allocated_size);
}
}
static int
avro_wrapped_copy_copy(avro_wrapped_buffer_t *dest,
const avro_wrapped_buffer_t *src,
size_t offset, size_t length)
{
struct avro_wrapped_copy *copy = (struct avro_wrapped_copy *) src->user_data;
avro_refcount_inc(&copy->refcount);
dest->buf = (char *) src->buf + offset;
dest->size = length;
dest->user_data = copy;
dest->free = avro_wrapped_copy_free;
dest->copy = avro_wrapped_copy_copy;
dest->slice = NULL;
return 0;
}
int
avro_wrapped_buffer_new_copy(avro_wrapped_buffer_t *dest,
const void *buf, size_t length)
{
size_t allocated_size = sizeof(struct avro_wrapped_copy) + length;
struct avro_wrapped_copy *copy = (struct avro_wrapped_copy *) avro_malloc(allocated_size);
if (copy == NULL) {
return ENOMEM;
}
dest->buf = ((char *) copy) + sizeof(struct avro_wrapped_copy);
dest->size = length;
dest->user_data = copy;
dest->free = avro_wrapped_copy_free;
dest->copy = avro_wrapped_copy_copy;
dest->slice = NULL;
avro_refcount_set(&copy->refcount, 1);
copy->allocated_size = allocated_size;
memcpy((void *) dest->buf, buf, length);
return 0;
}
int
avro_wrapped_buffer_new(avro_wrapped_buffer_t *dest,
const void *buf, size_t length)
{
dest->buf = buf;
dest->size = length;
dest->user_data = NULL;
dest->free = NULL;
dest->copy = NULL;
dest->slice = NULL;
return 0;
}
void
avro_wrapped_buffer_move(avro_wrapped_buffer_t *dest,
avro_wrapped_buffer_t *src)
{
memcpy(dest, src, sizeof(avro_wrapped_buffer_t));
memset(src, 0, sizeof(avro_wrapped_buffer_t));
}
int
avro_wrapped_buffer_copy(avro_wrapped_buffer_t *dest,
const avro_wrapped_buffer_t *src,
size_t offset, size_t length)
{
if (offset > src->size) {
avro_set_error("Invalid offset when slicing buffer");
return EINVAL;
}
if ((offset+length) > src->size) {
avro_set_error("Invalid length when slicing buffer");
return EINVAL;
}
if (src->copy == NULL) {
return avro_wrapped_buffer_new_copy(dest, (char *) src->buf + offset, length);
} else {
return src->copy(dest, src, offset, length);
}
}
int
avro_wrapped_buffer_slice(avro_wrapped_buffer_t *self,
size_t offset, size_t length)
{
if (offset > self->size) {
avro_set_error("Invalid offset when slicing buffer");
return EINVAL;
}
if ((offset+length) > self->size) {
avro_set_error("Invalid length when slicing buffer");
return EINVAL;
}
if (self->slice == NULL) {
self->buf = (char *) self->buf + offset;
self->size = length;
return 0;
} else {
return self->slice(self, offset, length);
}
}