/*
 * Copyright (C) 2017 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.
 */

//#define LOG_NDEBUG 0
#define LOG_TAG "ecm"

#include <inttypes.h>

#include "ecm.h"
#include "ecm_generator.h"
#include "protos/license_protos.pb.h"

#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/MediaErrors.h>
#include <utils/Log.h>

namespace android {
namespace clearkeycas {

Ecm::Ecm()
    : asset_id_(0),
      asset_id_set_(false),
      system_id_(0),
      system_id_set_(false) {}

Ecm::~Ecm() {}

status_t Ecm::Parse(const sp<ABuffer>& buffer_as_binary) {
    if (buffer_as_binary->size() < kSizeBytes) {
        ALOGE("Short Ecm buffer: expected %zu, received %zu.",
                kSizeBytes, buffer_as_binary->size());
        return BAD_VALUE;
    }

    Asset asset;
    ecm_generator::DefaultEcmFields default_fields;
    status_t status = ecm_generator::DecodeECMClearFields(
            buffer_as_binary, &asset, &default_fields);
    if (status != OK) {
        ALOGE("DecodeECMClearFields failed with status %d", status);
        return status;
    }
    set_asset_id(asset.id());
    set_system_id(default_fields.system_id);

    // Save a copy of the buffer_as_binary for a future DecryptEcm call.
    set_buffer(buffer_as_binary);
    return OK;
}

status_t Ecm::Decrypt(
        const sp<ABuffer>& buffer_as_binary,
        const Asset& asset_from_emm) {
    // Invariant: asset has id. These are postconditions for Emm::Decrypt().
    CHECK(asset_from_emm.has_id());

    // DecodeEcm fills in |asset|.id() with the asset_id from the encoded Ecm.
    Asset asset(asset_from_emm);
    ecm_generator::DefaultEcmFields default_fields;
    sp<ABuffer> content_key;
    status_t status = ecm_generator::DecodeECM(
            buffer_as_binary, &asset, &content_key, &default_fields);
    if (status != OK) {
        ALOGE("DecodeECM failed with status %d", status);
        return status;
    }
    if (asset.id() != asset_from_emm.id()) {
        ALOGE("Asset_id from Emm (%" PRIu64 ") does not match asset_id from Ecm (%" PRIu64 ").",
                asset_from_emm.id(), asset.id());
        return CLEARKEY_STATUS_INVALID_PARAMETER;
    }
    set_asset_id(asset.id());
    set_system_id(default_fields.system_id);
    set_content_key(content_key);
    return status;
}

EcmDescriptor::EcmDescriptor() : ecm_set_(false), id_(0), id_set_(false) {}

EcmDescriptor::EcmDescriptor(uint16_t id, const Ecm& ecm)
: ecm_(ecm), ecm_set_(true), id_(id), id_set_(true) {}

EcmDescriptor::~EcmDescriptor() {}

status_t EcmDescriptor::Parse(const sp<ABuffer>& buffer_as_binary) {
    if (buffer_as_binary->size() < kSizeBytes) {
        ALOGE("Short EcmDescriptor buffer: expected %zu, received %zu.",
                kSizeBytes, buffer_as_binary->size());
        return BAD_VALUE;
    }
    sp<ABuffer> id_buffer = new ABuffer(buffer_as_binary->data(), kIdSizeBytes);
    const uint8_t *id_bytes = id_buffer->data();
    uint16_t id = (id_bytes[0] << 8) | id_bytes[1];
    set_id(id);

    // Unmarshall the contained Ecm.
    sp<ABuffer> ecm_buffer = new ABuffer(
            buffer_as_binary->data() + kIdSizeBytes, Ecm::kSizeBytes);
    status_t status = mutable_ecm()->Parse(ecm_buffer);
    if (status != OK) {
        return status;
    }
    return OK;
}

EcmContainer::EcmContainer() : count_(0), count_set_(false) {}

EcmContainer::~EcmContainer() {}

status_t EcmContainer::Add(const EcmDescriptor& descriptor) {
    switch (count_) {
    case 0:
        descriptor_[0] = descriptor;
        count_ = 1;
        break;
    case 1:
        descriptor_[1] = descriptor;
        count_ = 2;
        break;
    case 2:
        descriptor_[0] = descriptor_[1];
        descriptor_[1] = descriptor;
        break;
    default:
        ALOGE("Bad state.");
        return INVALID_OPERATION;
    }
    count_set_ = true;
    return OK;
}

status_t EcmContainer::Parse(const sp<ABuffer>& buffer_as_binary) {
    // EcmContainer can contain 1 or 2 EcmDescriptors so this is a check for
    // minimum size.
    if (buffer_as_binary->size() < kMinimumSizeBytes) {
        ALOGE("Short EcmContainer buffer: expected >= %zu, received %zu.",
                kMinimumSizeBytes, buffer_as_binary->size());
        return BAD_VALUE;
    }

    sp<ABuffer> count_buffer = new ABuffer(
            buffer_as_binary->data(), kCountSizeBytes);
    const uint8_t *count_bytes = count_buffer->data();
    size_t count = (count_bytes[0] << 8) | count_bytes[1];
    // Check that count is a legal value.
    if (!CountLegal(count)) {
        ALOGE("Invalid descriptor count: expected %zu <= count <= %zu, received %zu.",
                kMinDescriptorCount, kMaxDescriptorCount, count);
        return ERROR_OUT_OF_RANGE;
    }
    // If needed, check that buffer_as_binary can hold 2 EcmDescriptors.
    if (count > kMinDescriptorCount) {
        size_t expected_bytes =
                kCountSizeBytes + (count * EcmDescriptor::kSizeBytes);
        if (buffer_as_binary->size() < expected_bytes) {
            ALOGE("Short EcmContainer buffer: expected %zu, received %zu.",
                    expected_bytes, buffer_as_binary->size());
            return BAD_VALUE;
        }
    }
    set_count(count);
    // Unmarshall the contained EcmDescriptors.
    size_t offset = kCountSizeBytes;
    for (size_t i = 0; i < count_; ++i) {
        sp<ABuffer> descriptor_buffer = new ABuffer(
                buffer_as_binary->data() + offset, EcmDescriptor::kSizeBytes);
        status_t status = mutable_descriptor(i)->Parse(descriptor_buffer);
        if (status != OK) {
            return status;
        }
        offset += EcmDescriptor::kSizeBytes;
    }
    return OK;
}

}  // namespace clearkeycas
}  // namespace android
