| /* |
| * 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(©->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(©->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(©->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); |
| } |
| } |