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); }
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; }