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

/*
 * java.lang.reflect.Array
 */
#include "Dalvik.h"
#include "native/InternalNativePriv.h"


/*
 * private static Object createObjectArray(Class<?> componentType,
 *     int length) throws NegativeArraySizeException;
 *
 * Create a one-dimensional array of Objects.
 */
static void Dalvik_java_lang_reflect_Array_createObjectArray(const u4* args,
    JValue* pResult)
{
    ClassObject* elementClass = (ClassObject*) args[0];
    int length = args[1];

    assert(elementClass != NULL);       // tested by caller
    if (length < 0) {
        dvmThrowNegativeArraySizeException(length);
        RETURN_VOID();
    }

    ClassObject* arrayClass =
        dvmFindArrayClassForElement(elementClass);
    ArrayObject* newArray =
        dvmAllocArrayByClass(arrayClass, length, ALLOC_DEFAULT);
    if (newArray == NULL) {
        assert(dvmCheckException(dvmThreadSelf()));
        RETURN_VOID();
    }
    dvmReleaseTrackedAlloc((Object*) newArray, NULL);

    RETURN_PTR(newArray);
}

/*
 * private static Object createMultiArray(Class<?> componentType,
 *     int[] dimensions) throws NegativeArraySizeException;
 *
 * Create a multi-dimensional array of Objects or primitive types.
 *
 * We have to generate the names for X[], X[][], X[][][], and so on.  The
 * easiest way to deal with that is to create the full name once and then
 * subtract pieces off.  Besides, we want to start with the outermost
 * piece and work our way in.
 */
static void Dalvik_java_lang_reflect_Array_createMultiArray(const u4* args,
    JValue* pResult)
{
    ClassObject* elementClass = (ClassObject*) args[0];
    ArrayObject* dimArray = (ArrayObject*) args[1];
    ClassObject* arrayClass;
    ArrayObject* newArray;
    char* acDescriptor;
    int numDim, i;
    int* dimensions;

    LOGV("createMultiArray: '%s' [%d]",
        elementClass->descriptor, dimArray->length);

    assert(elementClass != NULL);       // verified by caller

    /*
     * Verify dimensions.
     *
     * The caller is responsible for verifying that "dimArray" is non-null
     * and has a length > 0 and <= 255.
     */
    assert(dimArray != NULL);           // verified by caller
    numDim = dimArray->length;
    assert(numDim > 0 && numDim <= 255);

    dimensions = (int*)(void*)dimArray->contents;
    for (i = 0; i < numDim; i++) {
        if (dimensions[i] < 0) {
            dvmThrowNegativeArraySizeException(dimensions[i]);
            RETURN_VOID();
        }
        LOGVV("DIM %d: %d", i, dimensions[i]);
    }

    /*
     * Generate the full name of the array class.
     */
    acDescriptor =
        (char*) malloc(strlen(elementClass->descriptor) + numDim + 1);
    memset(acDescriptor, '[', numDim);

    LOGVV("#### element name = '%s'", elementClass->descriptor);
    if (dvmIsPrimitiveClass(elementClass)) {
        assert(elementClass->primitiveType != PRIM_NOT);
        acDescriptor[numDim] = dexGetPrimitiveTypeDescriptorChar(elementClass->primitiveType);
        acDescriptor[numDim+1] = '\0';
    } else {
        strcpy(acDescriptor+numDim, elementClass->descriptor);
    }
    LOGVV("#### array name = '%s'", acDescriptor);

    /*
     * Find/generate the array class.
     */
    arrayClass = dvmFindArrayClass(acDescriptor, elementClass->classLoader);
    if (arrayClass == NULL) {
        LOGW("Unable to find or generate array class '%s'", acDescriptor);
        assert(dvmCheckException(dvmThreadSelf()));
        free(acDescriptor);
        RETURN_VOID();
    }
    free(acDescriptor);

    /* create the array */
    newArray = dvmAllocMultiArray(arrayClass, numDim-1, dimensions);
    if (newArray == NULL) {
        assert(dvmCheckException(dvmThreadSelf()));
        RETURN_VOID();
    }

    dvmReleaseTrackedAlloc((Object*) newArray, NULL);
    RETURN_PTR(newArray);
}

const DalvikNativeMethod dvm_java_lang_reflect_Array[] = {
    { "createObjectArray",  "(Ljava/lang/Class;I)Ljava/lang/Object;",
        Dalvik_java_lang_reflect_Array_createObjectArray },
    { "createMultiArray",   "(Ljava/lang/Class;[I)Ljava/lang/Object;",
        Dalvik_java_lang_reflect_Array_createMultiArray },
    { NULL, NULL, NULL },
};
