#include "config.h"
#if ENABLE(BLOB)
#include "FileReader.h"
#include "CrossThreadTask.h"
#include "File.h"
#include "Logging.h"
#include "OperationNotAllowedException.h"
#include "ProgressEvent.h"
#include "ScriptExecutionContext.h"
#include <wtf/ArrayBuffer.h>
#include <wtf/CurrentTime.h>
#include <wtf/text/CString.h>
namespace WebCore {
static const double progressNotificationIntervalMS = 50;
PassRefPtr<FileReader> FileReader::create(ScriptExecutionContext* context)
{
RefPtr<FileReader> fileReader(adoptRef(new FileReader(context)));
fileReader->suspendIfNeeded();
return fileReader.release();
}
FileReader::FileReader(ScriptExecutionContext* context)
: ActiveDOMObject(context, this)
, m_state(EMPTY)
, m_aborting(false)
, m_readType(FileReaderLoader::ReadAsBinaryString)
, m_lastProgressNotificationTimeMS(0)
{
}
FileReader::~FileReader()
{
terminate();
}
const AtomicString& FileReader::interfaceName() const
{
return eventNames().interfaceForFileReader;
}
bool FileReader::hasPendingActivity() const
{
return m_state == LOADING || ActiveDOMObject::hasPendingActivity();
}
bool FileReader::canSuspend() const
{
return false;
}
void FileReader::stop()
{
terminate();
}
void FileReader::readAsArrayBuffer(Blob* blob, ExceptionCode& ec)
{
if (!blob)
return;
LOG(FileAPI, "FileReader: reading as array buffer: %s %s\n", blob->url().string().utf8().data(), blob->isFile() ? static_cast<File*>(blob)->path().utf8().data() : "");
readInternal(blob, FileReaderLoader::ReadAsArrayBuffer, ec);
}
void FileReader::readAsBinaryString(Blob* blob, ExceptionCode& ec)
{
if (!blob)
return;
LOG(FileAPI, "FileReader: reading as binary: %s %s\n", blob->url().string().utf8().data(), blob->isFile() ? static_cast<File*>(blob)->path().utf8().data() : "");
readInternal(blob, FileReaderLoader::ReadAsBinaryString, ec);
}
void FileReader::readAsText(Blob* blob, const String& encoding, ExceptionCode& ec)
{
if (!blob)
return;
LOG(FileAPI, "FileReader: reading as text: %s %s\n", blob->url().string().utf8().data(), blob->isFile() ? static_cast<File*>(blob)->path().utf8().data() : "");
m_encoding = encoding;
readInternal(blob, FileReaderLoader::ReadAsText, ec);
}
void FileReader::readAsText(Blob* blob, ExceptionCode& ec)
{
readAsText(blob, String(), ec);
}
void FileReader::readAsDataURL(Blob* blob, ExceptionCode& ec)
{
if (!blob)
return;
LOG(FileAPI, "FileReader: reading as data URL: %s %s\n", blob->url().string().utf8().data(), blob->isFile() ? static_cast<File*>(blob)->path().utf8().data() : "");
readInternal(blob, FileReaderLoader::ReadAsDataURL, ec);
}
void FileReader::readInternal(Blob* blob, FileReaderLoader::ReadType type, ExceptionCode& ec)
{
if (m_state == LOADING) {
ec = OperationNotAllowedException::NOT_ALLOWED_ERR;
return;
}
m_blob = blob;
m_readType = type;
m_state = LOADING;
m_error = 0;
m_loader = adoptPtr(new FileReaderLoader(m_readType, this));
m_loader->setEncoding(m_encoding);
m_loader->setDataType(m_blob->type());
m_loader->start(scriptExecutionContext(), m_blob.get());
}
static void delayedAbort(ScriptExecutionContext*, FileReader* reader)
{
reader->doAbort();
}
void FileReader::abort()
{
LOG(FileAPI, "FileReader: aborting\n");
if (m_aborting)
return;
m_aborting = true;
scriptExecutionContext()->postTask(
createCallbackTask(&delayedAbort, AllowAccessLater(this)));
}
void FileReader::doAbort()
{
terminate();
m_aborting = false;
m_error = FileError::create(FileError::ABORT_ERR);
fireEvent(eventNames().errorEvent);
fireEvent(eventNames().abortEvent);
fireEvent(eventNames().loadendEvent);
}
void FileReader::terminate()
{
if (m_loader) {
m_loader->cancel();
m_loader = nullptr;
}
m_state = DONE;
}
void FileReader::didStartLoading()
{
fireEvent(eventNames().loadstartEvent);
}
void FileReader::didReceiveData()
{
double now = currentTimeMS();
if (!m_lastProgressNotificationTimeMS)
m_lastProgressNotificationTimeMS = now;
else if (now - m_lastProgressNotificationTimeMS > progressNotificationIntervalMS) {
fireEvent(eventNames().progressEvent);
m_lastProgressNotificationTimeMS = now;
}
}
void FileReader::didFinishLoading()
{
m_state = DONE;
fireEvent(eventNames().loadEvent);
fireEvent(eventNames().loadendEvent);
}
void FileReader::didFail(int errorCode)
{
if (m_aborting)
return;
m_state = DONE;
m_error = FileError::create(static_cast<FileError::ErrorCode>(errorCode));
fireEvent(eventNames().errorEvent);
fireEvent(eventNames().loadendEvent);
}
void FileReader::fireEvent(const AtomicString& type)
{
dispatchEvent(ProgressEvent::create(type, true, m_loader ? m_loader->bytesLoaded() : 0, m_loader ? m_loader->totalBytes() : 0));
}
PassRefPtr<ArrayBuffer> FileReader::arrayBufferResult() const
{
return m_loader ? m_loader->arrayBufferResult() : 0;
}
String FileReader::stringResult()
{
return m_loader ? m_loader->stringResult() : "";
}
}
#endif // ENABLE(BLOB)