EncodedJSValue JSC_HOST_CALL constructJSFile(ExecState& exec) { auto* constructor = jsCast<DOMConstructorObject*>(exec.callee()); ScriptExecutionContext* context = constructor->scriptExecutionContext(); if (!context) return throwVMError(&exec, createReferenceError(&exec, "File constructor associated document is unavailable")); JSValue arg = exec.argument(0); if (arg.isUndefinedOrNull()) return throwVMTypeError(&exec, ASCIILiteral("First argument to File constructor must be a valid sequence, was undefined or null")); unsigned blobPartsLength = 0; JSObject* blobParts = toJSSequence(exec, arg, blobPartsLength); if (exec.hadException()) return JSValue::encode(jsUndefined()); ASSERT(blobParts); arg = exec.argument(1); if (arg.isUndefined()) return throwVMTypeError(&exec, ASCIILiteral("Second argument to File constructor must be a valid string, was undefined")); String filename = arg.toWTFString(&exec).replace('/', ':'); if (exec.hadException()) return JSValue::encode(jsUndefined()); String normalizedType; Optional<int64_t> lastModified; arg = exec.argument(2); if (!arg.isUndefinedOrNull()) { JSObject* filePropertyBagObject = arg.getObject(); if (!filePropertyBagObject) return throwVMTypeError(&exec, ASCIILiteral("Third argument of the constructor is not of type Object")); // Create the dictionary wrapper from the initializer object. JSDictionary dictionary(&exec, filePropertyBagObject); // Attempt to get the type property. String type; dictionary.get("type", type); if (exec.hadException()) return JSValue::encode(jsUndefined()); normalizedType = Blob::normalizedContentType(type); // Only try to parse the lastModified date if there was not an invalid type argument. if (type.isEmpty() || !normalizedType.isEmpty()) { dictionary.get("lastModified", lastModified); if (exec.hadException()) return JSValue::encode(jsUndefined()); } } if (!lastModified) lastModified = currentTimeMS(); BlobBuilder blobBuilder; for (unsigned i = 0; i < blobPartsLength; ++i) { JSValue item = blobParts->get(&exec, i); if (exec.hadException()) return JSValue::encode(jsUndefined()); if (ArrayBuffer* arrayBuffer = toArrayBuffer(item)) blobBuilder.append(arrayBuffer); else if (RefPtr<ArrayBufferView> arrayBufferView = toArrayBufferView(item)) blobBuilder.append(WTFMove(arrayBufferView)); else if (Blob* blob = JSBlob::toWrapped(item)) blobBuilder.append(blob); else { String string = item.toWTFString(&exec); if (exec.hadException()) return JSValue::encode(jsUndefined()); blobBuilder.append(string, ASCIILiteral("transparent")); } } auto file = File::create(blobBuilder.finalize(), filename, normalizedType, lastModified.value()); return JSValue::encode(CREATE_DOM_WRAPPER(constructor->globalObject(), File, WTFMove(file))); }
EncodedJSValue JSC_HOST_CALL JSBlobConstructor::constructJSBlob(ExecState* exec) { JSBlobConstructor* jsConstructor = jsCast<JSBlobConstructor*>(exec->callee()); ScriptExecutionContext* context = jsConstructor->scriptExecutionContext(); if (!context) return throwVMError(exec, createReferenceError(exec, "Blob constructor associated document is unavailable")); if (!exec->argumentCount()) { RefPtr<Blob> blob = Blob::create(); return JSValue::encode(CREATE_DOM_WRAPPER(jsConstructor->globalObject(), Blob, blob.get())); } unsigned blobPartsLength = 0; JSObject* blobParts = toJSSequence(exec, exec->argument(0), blobPartsLength); if (exec->hadException()) return JSValue::encode(jsUndefined()); ASSERT(blobParts); String type; String endings = ASCIILiteral("transparent"); if (exec->argumentCount() > 1) { JSValue blobPropertyBagValue = exec->argument(1); if (!blobPropertyBagValue.isObject()) return throwVMError(exec, createTypeError(exec, "Second argument of the constructor is not of type Object")); // Given the above test, this will always yield an object. JSObject* blobPropertyBagObject = blobPropertyBagValue.toObject(exec); // Create the dictionary wrapper from the initializer object. JSDictionary dictionary(exec, blobPropertyBagObject); // Attempt to get the endings property and validate it. bool containsEndings = dictionary.get("endings", endings); if (exec->hadException()) return JSValue::encode(jsUndefined()); if (containsEndings) { if (endings != "transparent" && endings != "native") return throwVMError(exec, createTypeError(exec, "The endings property must be either \"transparent\" or \"native\"")); } // Attempt to get the type property. dictionary.get("type", type); if (exec->hadException()) return JSValue::encode(jsUndefined()); } ASSERT(endings == "transparent" || endings == "native"); BlobBuilder blobBuilder; for (unsigned i = 0; i < blobPartsLength; ++i) { JSValue item = blobParts->get(exec, i); if (exec->hadException()) return JSValue::encode(jsUndefined()); #if ENABLE(BLOB) if (ArrayBuffer* arrayBuffer = toArrayBuffer(item)) blobBuilder.append(arrayBuffer); else if (RefPtr<ArrayBufferView> arrayBufferView = toArrayBufferView(item)) blobBuilder.append(arrayBufferView.release()); else #endif if (Blob* blob = toBlob(item)) blobBuilder.append(blob); else { String string = item.toString(exec)->value(exec); if (exec->hadException()) return JSValue::encode(jsUndefined()); blobBuilder.append(string, endings); } } RefPtr<Blob> blob = Blob::create(blobBuilder.finalize(), Blob::normalizedContentType(type)); return JSValue::encode(CREATE_DOM_WRAPPER(jsConstructor->globalObject(), Blob, blob.get())); }