EncodedJSValue JSC_HOST_CALL COMMethodCall::call(ExecState* execState) {
    COMMethodCall* callee = jsCast<COMMethodCall*>(execState->callee());
    if (execState->argumentCount() != callee->_parameterCells.size()) {
        // TODO: error
        CRASH();
    }

    COMInterop* interop = jsCast<GlobalObject*>(execState->lexicalGlobalObject())->interop();

    size_t numberOfABIParameters = callee->_parameterCells.size() + (callee->_isVoid ? 1 : 2);

    HRESULT hr;

    Microsoft::WRL::ComPtr<IUnknown> self;
    hr = interop->wrap(execState->thisValue(), callee->_methodInterface, self.GetAddressOf());

    void** vtable = *reinterpret_cast<void***>(self.Get());
    void* fn = vtable[callee->_methodIndex];

    WTF::Vector<void*> arguments;
    arguments.reserveCapacity(numberOfABIParameters);

    IUnknown* thisValue = self.Get();
    arguments.append(&thisValue);

    for (int i = 0; i < callee->_parameterCells.size(); i++) {
        JSCell* type = callee->_parameterCells[i].get();
        void* buffer = _alloca(std::max(sizeof(ffi_arg), callee->_parameterTypes[i + 1]->size));
        getFFIMethodTable(type)->marshalJSToNative(type, execState, execState->uncheckedArgument(i), buffer);
        arguments.append(buffer);
    }

    void* returnBuffer = nullptr;
    if (!callee->_isVoid) {
        returnBuffer = _alloca(std::max(sizeof(ffi_arg), callee->_parameterTypes[numberOfABIParameters - 1]->size));
        arguments.append(&returnBuffer);
    }

    ffi_call(&callee->_cif, FFI_FN(fn), &hr, arguments.data());

    JSValue jsResult;
    if (!SUCCEEDED(hr)) {
        _com_error error(hr, nullptr);
        jsResult = execState->vm().throwException(execState, createError(execState, error.ErrorMessage()));
    } else if (!callee->_isVoid) {
        JSCell* returnType = callee->_returnType.get();
        jsResult = getFFIMethodTable(returnType)->marshalNativeToJS(returnType, execState, returnBuffer);
    } else {
        jsResult = jsUndefined();
    }

    return JSValue::encode(jsResult);
}
void WebHistory::Flatten(JNIEnv* env, WTF::Vector<char>& vector, WebCore::HistoryItem* item)
{
    if (!item)
        return;

    // Reserve a vector of chars with an initial size of HISTORY_MIN_SIZE.
    vector.reserveCapacity(HISTORY_MIN_SIZE);

    // Write the top-level history item and then write all the children
    // recursively.
    ALOG_ASSERT(item->bridge(), "Why don't we have a bridge object here?");
    writeItem(vector, item);
    writeChildrenRecursive(vector, item);
}
Example #3
0
jbyteArray WebHistory::Flatten(JNIEnv* env, WTF::Vector<char>& v, WebCore::HistoryItem* item)
{
    if (!item)
        return NULL;

    // Reserve a vector of chars with an initial size of HISTORY_MIN_SIZE.
    v.reserveCapacity(HISTORY_MIN_SIZE);

    // Write the top-level history item and then write all the children
    // recursively.
    LOG_ASSERT(item->bridge(), "Why don't we have a bridge object here?");
    write_item(v, item);
    write_children_recursive(v, item);

//SAMSUNG - CRASH FIX BEGIN

    int size = v.size();
    if (size > 0) 
    {
        long availableMemory = GetVmAvailableMemory(env);

        if(size > availableMemory)
        {
            LOGV("WebHistory::Flatten(): load size=%d, availableMemory=%ld, still larger, return NULL", size, availableMemory);		
            return NULL;
        }

        checkException(env);
    }

//SAMSUNG - CRASH FIX END
    // Try to create a new java byte array.
    jbyteArray b = env->NewByteArray(v.size());
    if (!b)
    {
//SAMSUNG - CRASH FIX BEGIN
        if (checkException(env))
        {
            LOGV("WebHistory::Flatten(): env exception happened while allocating %d bytes, clear pending exception", v.size());
            env->ExceptionClear();
        }
//SAMSUNG - CRASH FIX END
        return NULL;
    }

    // Write our flattened data to the java array.
    env->SetByteArrayRegion(b, 0, v.size(), (const jbyte*)v.data());
    return b;
}
// ReverseBidi is a trimmed-down version of GraphicsContext::drawBidiText()
void ReverseBidi(UChar* chars, int len) {
    using namespace WTF::Unicode;
    WTF::Vector<UChar> result;
    result.reserveCapacity(len);
    TextRun run(chars, len);
    BidiResolver<TextRunIterator, BidiCharacterRun> bidiResolver;
    BidiRunList<BidiCharacterRun>& bidiRuns = bidiResolver.runs();
    bidiResolver.setStatus(BidiStatus(LeftToRight, LeftToRight, LeftToRight,
        BidiContext::create(0, LeftToRight, false)));
    bidiResolver.setPosition(TextRunIterator(&run, 0));
    bidiResolver.createBidiRunsForLine(TextRunIterator(&run, len));
    if (!bidiRuns.runCount())
        return;
    BidiCharacterRun* bidiRun = bidiRuns.firstRun();
    while (bidiRun) {
        int bidiStart = bidiRun->start();
        int bidiStop = bidiRun->stop();
        int size = result.size();
        int bidiCount = bidiStop - bidiStart;
        result.append(chars + bidiStart, bidiCount);
        if (bidiRun->level() % 2) {
            UChar* start = &result[size];
            UChar* end = start + bidiCount;
            // reverse the order of any RTL substrings
            while (start < end) {
                UChar temp = *start;
                *start++ = *--end;
                *end = temp;
            }
            start = &result[size];
            end = start + bidiCount - 1;
            // if the RTL substring had a surrogate pair, restore its order
            while (start < end) {
                UChar trail = *start++;
                if (!U16_IS_SURROGATE(trail))
                    continue;
                start[-1] = *start; // lead
                *start++ = trail;
            }
        }
        bidiRun = bidiRun->next();
    }
    bidiRuns.deleteRuns();
    memcpy(chars, &result[0], len * sizeof(UChar));
}
jbyteArray WebHistory::Flatten(JNIEnv* env, WTF::Vector<char>& v, WebCore::HistoryItem* item)
{
    if (!item)
        return NULL;

    // Reserve a vector of chars with an initial size of HISTORY_MIN_SIZE.
    v.reserveCapacity(HISTORY_MIN_SIZE);

    // Write the top-level history item and then write all the children
    // recursively.
    LOG_ASSERT(item->bridge(), "Why don't we have a bridge object here?");
    write_item(v, item);
    write_children_recursive(v, item);

    // Try to create a new java byte array.
    jbyteArray b = env->NewByteArray(v.size());
    if (!b)
        return NULL;

    // Write our flattened data to the java array.
    env->SetByteArrayRegion(b, 0, v.size(), (const jbyte*)v.data());
    return b;
}
static bool read_item_recursive(WebCore::HistoryItem* newItem,
        const char** pData, int length)
{
    if (!pData || length < HISTORY_MIN_SIZE)
        return false;

    const WebCore::TextEncoding& e = WebCore::UTF8Encoding();
    const char* data = *pData;
    const char* end = data + length;
    int sizeofUnsigned = (int)sizeof(unsigned);

    // Read the original url
    // Read the expected length of the string.
    int l;
    memcpy(&l, data, sizeofUnsigned);
    // Increment data pointer by the size of an unsigned int.
    data += sizeofUnsigned;
    if (l) {
        LOGV("Original url    %d %.*s", l, l, data);
        // If we have a length, check if that length exceeds the data length
        // and return null if there is not enough data.
        if (data + l < end)
            newItem->setOriginalURLString(e.decode(data, l));
        else
            return false;
        // Increment the data pointer by the length of the string.
        data += l;
    }
    // Check if we have enough data left to continue.
    if (end - data < sizeofUnsigned)
        return false;

    // Read the url
    memcpy(&l, data, sizeofUnsigned);
    data += sizeofUnsigned;
    if (l) {
        LOGV("Url             %d %.*s", l, l, data);
        if (data + l < end)
            newItem->setURLString(e.decode(data, l));
        else
            return false;
        data += l;
    }
    if (end - data < sizeofUnsigned)
        return false;

    // Read the title
    memcpy(&l, data, sizeofUnsigned);
    data += sizeofUnsigned;
    if (l) {
        LOGV("Title           %d %.*s", l, l, data);
        if (data + l < end)
            newItem->setTitle(e.decode(data, l));
        else
            return false;
        data += l;
    }
    if (end - data < sizeofUnsigned)
        return false;

    // Generate a new ResourceRequest object for populating form information.
    WebCore::String formContentType;
    WTF::PassRefPtr<WebCore::FormData> formData = NULL;

    // Read the form content type
    memcpy(&l, data, sizeofUnsigned);
    data += sizeofUnsigned;
    if (l) {
        LOGV("Content type    %d %.*s", l, l, data);
        if (data + l < end)
            formContentType = e.decode(data, l);
        else
            return false;
        data += l;
    }
    if (end - data < sizeofUnsigned)
        return false;

    // Read the form data
    memcpy(&l, data, sizeofUnsigned);
    data += sizeofUnsigned;
    if (l) {
        LOGV("Form data       %d %.*s", l, l, data);
        if (data + l < end)
            formData = WebCore::FormData::create(data, l);
        else
            return false;
        data += l;
        // Read the identifier
        {
            int64_t id;
            int size = (int)sizeof(int64_t);
            memcpy(&id, data, size);
            data += size;
            if (id)
                formData->setIdentifier(id);
        }
    }
    if (end - data < sizeofUnsigned)
        return false;

    // Set up the form info
    if (formData != NULL) {
        WebCore::ResourceRequest r;
        r.setHTTPMethod("POST");
        r.setHTTPContentType(formContentType);
        r.setHTTPBody(formData);
        newItem->setFormInfoFromRequest(r);
    }

    // Read the target
    memcpy(&l, data, sizeofUnsigned);
    data += sizeofUnsigned;
    if (l) {
        LOGV("Target          %d %.*s", l, l, data);
        if (data + l < end)
            newItem->setTarget(e.decode(data, l));
        else
            return false;
        data += l;
    }
    if (end - data < sizeofUnsigned)
        return false;

    AndroidWebHistoryBridge* bridge = newItem->bridge();
    LOG_ASSERT(bridge, "There should be a bridge object during inflate");
    // Read the screen scale
    memcpy(&l, data, sizeofUnsigned);
    LOGV("Screen scale    %d", l);
    bridge->setScale(l);
    data += sizeofUnsigned;
    memcpy(&l, data, sizeofUnsigned);
    LOGV("Screen width scale    %d", l);
    bridge->setScreenWidthScale(l);
    data += sizeofUnsigned;

    if (end - data < sizeofUnsigned)
        return false;

    // Read the document state
    memcpy(&l, data, sizeofUnsigned);
    LOGV("Document state  %d", l);
    data += sizeofUnsigned;
    if (l) {
        // Check if we have enough data to at least parse the sizes of each
        // document state string.
        if (data + l * sizeofUnsigned >= end)
            return false;
        // Create a new vector and reserve enough space for the document state.
        WTF::Vector<WebCore::String> docState;
        docState.reserveCapacity(l);
        while (l--) {
            // Check each time if we have enough to parse the length of the next
            // string.
            if (end - data < sizeofUnsigned)
                return false;
            int strLen;
            memcpy(&strLen, data, sizeofUnsigned);
            data += sizeofUnsigned;
            if (data + strLen < end)
                docState.append(e.decode(data, strLen));
            else
                return false;
            LOGV("\t\t%d %.*s", strLen, strLen, data);
            data += strLen;
        }
        newItem->setDocumentState(docState);
    }
    // Check if we have enough to read the next byte
    if (data >= end)
        return false;

    // Read is target item
    // Cast the value to unsigned char in order to make a negative value larger
    // than 1. A value that is not 0 or 1 is a failure.
    unsigned char c = (unsigned char)data[0];
    if (c > 1)
        return false;
    LOGV("Target item     %d", c);
    newItem->setIsTargetItem((bool)c);
    data++;
    if (end - data < sizeofUnsigned)
        return false;

    // Read the child count
    memcpy(&l, data, sizeofUnsigned);
    LOGV("Child count     %d", l);
    data += sizeofUnsigned;
    *pData = data;
    if (l) {
        // Check if we have the minimum amount need to parse l children.
        if (data + l * HISTORY_MIN_SIZE >= end)
            return false;
        while (l--) {
            // No need to check the length each time because read_item_recursive
            // will return null if there isn't enough data left to parse.
            WTF::PassRefPtr<WebCore::HistoryItem> child = WebCore::HistoryItem::create();
            // Set a bridge that will not call into java.
            child->setBridge(new WebHistoryItem(static_cast<WebHistoryItem*>(bridge)));
            // Read the child item.
            if (!read_item_recursive(child.get(), pData, end - data)) {
                child.clear();
                return false;
            }
            child->bridge()->setActive();
            newItem->addChildItem(child);
        }
    }
    return true;
}
static bool readItemRecursive(WebCore::HistoryItem* newItem,
        const char** pData, int length)
{
    if (!pData || length < HISTORY_MIN_SIZE) {
        ALOGW("readItemRecursive() bad params; pData=%p length=%d", pData, length);
        return false;
    }

    const char* data = *pData;
    const char* end = data + length;
    String content;

    // Read the original url
    if (readString(data, end, content, "Original url"))
        newItem->setOriginalURLString(content);
    else
        return false;

    // Read the url
    if (readString(data, end, content, "Url"))
        newItem->setURLString(content);
    else
        return false;

    // Read the title
    if (readString(data, end, content, "Title"))
        newItem->setTitle(content);
    else
        return false;

    // Generate a new ResourceRequest object for populating form information.
    // Read the form content type
    WTF::String formContentType;
    if (!readString(data, end, formContentType, "Content type"))
        return false;

    // Read the form data size
    unsigned formDataSize;
    if (!readUnsigned(data, end, formDataSize, "Form data size"))
        return false;

    // Read the form data
    WTF::RefPtr<WebCore::FormData> formData;
    if (formDataSize) {
        ALOGV("Reading Form data       %d %.*s", formDataSize, formDataSize, data);
        if ((end < data) || ((size_t)(end - data) < formDataSize)) {
            ALOGW("\tNot enough data to read form data; returning");
            return false;
        }
        formData = WebCore::FormData::create(data, formDataSize);
        data += formDataSize;
        // Read the identifier
        int64_t id;
        if (!readInt64(data, end, id, "Form id"))
            return false;
        if (id)
            formData->setIdentifier(id);
    }

    // Set up the form info
    if (formData != NULL) {
        WebCore::ResourceRequest r;
        r.setHTTPMethod("POST");
        r.setHTTPContentType(formContentType);
        r.setHTTPBody(formData);
        newItem->setFormInfoFromRequest(r);
    }

    // Read the target
    if (readString(data, end, content, "Target"))
        newItem->setTarget(content);
    else
        return false;

    AndroidWebHistoryBridge* bridge = newItem->bridge();
    ALOG_ASSERT(bridge, "There should be a bridge object during inflate");

    // Read the screen scale
    float fValue;
    if (readFloat(data, end, fValue, "Screen scale"))
        bridge->setScale(fValue);
    else
        return false;

    // Read the text wrap scale
    if (readFloat(data, end, fValue, "Text wrap scale"))
        bridge->setTextWrapScale(fValue);
    else
        return false;

    // Read scroll position.
    int scrollX;
    if (!readInt(data, end, scrollX, "Scroll pos x"))
        return false;
    int scrollY;
    if (!readInt(data, end, scrollY, "Scroll pos y"))
        return false;
    newItem->setScrollPoint(IntPoint(scrollX, scrollY));

    // Read the document state
    unsigned docStateCount;
    if (!readUnsigned(data, end, docStateCount, "Doc state count"))
        return false;
    if (docStateCount) {
        // Create a new vector and reserve enough space for the document state.
        WTF::Vector<WTF::String> docState;
        docState.reserveCapacity(docStateCount);
        while (docStateCount--) {
            // Read a document state string
            if (readString(data, end, content, "Document state"))
                docState.append(content);
            else
                return false;
        }
        newItem->setDocumentState(docState);
    }

    // Read is target item
    bool c;
    if (readBool(data, end, c, "Target item"))
        newItem->setIsTargetItem(c);
    else
        return false;

    // Read the child count
    unsigned count;
    if (!readUnsigned(data, end, count, "Child count"))
        return false;
    *pData = data;
    if (count) {
        while (count--) {
            // No need to check the length each time because read_item_recursive
            // will return null if there isn't enough data left to parse.
            WTF::RefPtr<WebCore::HistoryItem> child = WebCore::HistoryItem::create();
            // Set a bridge that will not call into java.
            child->setBridge(new WebHistoryItem(static_cast<WebHistoryItem*>(bridge)));
            // Read the child item.
            if (!readItemRecursive(child.get(), pData, end - data))
                return false;
            child->bridge()->setActive();
            newItem->addChildItem(child);
        }
    }
    return true;
}