/*
 * Copyright 2014 The Android Open Source Project
 *
 * Licensed 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 <keymaster/serializable.h>

#include <assert.h>

#include <new>

#include <keymaster/android_keymaster_utils.h>

namespace keymaster {

uint8_t* append_to_buf(uint8_t* buf, const uint8_t* end, const void* data, size_t data_len) {
    if (__pval(buf) + data_len < __pval(buf))  // Pointer wrap check
        return buf;

    if (buf + data_len <= end) {
        memcpy(buf, data, data_len);
        return buf + data_len;
    }
    return buf;
}

bool copy_from_buf(const uint8_t** buf_ptr, const uint8_t* end, void* dest, size_t size) {
    if (__pval(*buf_ptr) + size < __pval(*buf_ptr))  // Pointer wrap check
        return false;

    if (end < *buf_ptr + size)
        return false;
    memcpy(dest, *buf_ptr, size);
    *buf_ptr += size;
    return true;
}

bool copy_size_and_data_from_buf(const uint8_t** buf_ptr, const uint8_t* end, size_t* size,
                                 UniquePtr<uint8_t[]>* dest) {
    if (!copy_uint32_from_buf(buf_ptr, end, size))
        return false;

    if (__pval(*buf_ptr) + *size < __pval(*buf_ptr))  // Pointer wrap check
        return false;

    if (*buf_ptr + *size > end)
        return false;

    if (*size == 0) {
        dest->reset();
        return true;
    }
    dest->reset(new (std::nothrow) uint8_t[*size]);
    if (!dest->get())
        return false;
    return copy_from_buf(buf_ptr, end, dest->get(), *size);
}

bool Buffer::reserve(size_t size) {
    if (available_write() < size) {
        size_t new_size = buffer_size_ + size - available_write();
        uint8_t* new_buffer = new (std::nothrow) uint8_t[new_size];
        if (!new_buffer)
            return false;
        memcpy(new_buffer, buffer_.get() + read_position_, available_read());
        memset_s(buffer_.get(), 0, buffer_size_);
        buffer_.reset(new_buffer);
        buffer_size_ = new_size;
        write_position_ -= read_position_;
        read_position_ = 0;
    }
    return true;
}

bool Buffer::Reinitialize(size_t size) {
    Clear();
    buffer_.reset(new (std::nothrow) uint8_t[size]);
    if (!buffer_.get())
        return false;
    buffer_size_ = size;
    read_position_ = 0;
    write_position_ = 0;
    return true;
}

bool Buffer::Reinitialize(const void* data, size_t data_len) {
    Clear();
    if (__pval(data) + data_len < __pval(data))  // Pointer wrap check
        return false;
    buffer_.reset(new (std::nothrow) uint8_t[data_len]);
    if (!buffer_.get())
        return false;
    buffer_size_ = data_len;
    memcpy(buffer_.get(), data, data_len);
    read_position_ = 0;
    write_position_ = buffer_size_;
    return true;
}

size_t Buffer::available_write() const {
    assert(buffer_size_ >= write_position_);
    return buffer_size_ - write_position_;
}

size_t Buffer::available_read() const {
    assert(buffer_size_ >= write_position_);
    assert(write_position_ >= read_position_);
    return write_position_ - read_position_;
}

bool Buffer::write(const uint8_t* src, size_t write_length) {
    if (available_write() < write_length)
        return false;
    memcpy(buffer_.get() + write_position_, src, write_length);
    write_position_ += write_length;
    return true;
}

bool Buffer::read(uint8_t* dest, size_t read_length) {
    if (available_read() < read_length)
        return false;
    memcpy(dest, buffer_.get() + read_position_, read_length);
    read_position_ += read_length;
    return true;
}

size_t Buffer::SerializedSize() const {
    return sizeof(uint32_t) + available_read();
}

uint8_t* Buffer::Serialize(uint8_t* buf, const uint8_t* end) const {
    return append_size_and_data_to_buf(buf, end, peek_read(), available_read());
}

bool Buffer::Deserialize(const uint8_t** buf_ptr, const uint8_t* end) {
    Clear();
    if (!copy_size_and_data_from_buf(buf_ptr, end, &buffer_size_, &buffer_)) {
        buffer_.reset();
        buffer_size_ = 0;
        return false;
    }
    write_position_ = buffer_size_;
    return true;
}

void Buffer::Clear() {
    memset_s(buffer_.get(), 0, buffer_size_);
    buffer_.reset();
    read_position_ = 0;
    write_position_ = 0;
    buffer_size_ = 0;
}

}  // namespace keymaster
