#include "config.h"
#include "Blob.h"
#include "BlobURL.h"
#include "File.h"
#include "HistogramSupport.h"
#include "ScriptCallStack.h"
#include "ScriptExecutionContext.h"
#include "ThreadableBlobRegistry.h"
#include <wtf/text/CString.h>
namespace WebCore {
namespace {
enum SliceHistogramEnum {
SliceWithoutPrefix,
SliceWithPrefix,
SliceHistogramEnumMax,
};
}
Blob::Blob()
: m_size(0)
{
OwnPtr<BlobData> blobData = BlobData::create();
m_internalURL = BlobURL::createInternalURL();
ThreadableBlobRegistry::registerBlobURL(m_internalURL, blobData.release());
}
Blob::Blob(PassOwnPtr<BlobData> blobData, long long size)
: m_type(blobData->contentType())
, m_size(size)
{
ASSERT(blobData);
m_internalURL = BlobURL::createInternalURL();
ThreadableBlobRegistry::registerBlobURL(m_internalURL, blobData);
}
Blob::Blob(const KURL& srcURL, const String& type, long long size)
: m_type(Blob::normalizedContentType(type))
, m_size(size)
{
m_internalURL = BlobURL::createInternalURL();
ThreadableBlobRegistry::registerBlobURL(0, m_internalURL, srcURL);
}
Blob::~Blob()
{
ThreadableBlobRegistry::unregisterBlobURL(m_internalURL);
}
bool Blob::isValidContentType(const String& contentType)
{
if (contentType.isNull())
return true;
size_t length = contentType.length();
if (contentType.is8Bit()) {
const LChar* characters = contentType.characters8();
for (size_t i = 0; i < length; ++i) {
if (characters[i] < 0x20 || characters[i] > 0x7e)
return false;
}
} else {
const UChar* characters = contentType.characters16();
for (size_t i = 0; i < length; ++i) {
if (characters[i] < 0x20 || characters[i] > 0x7e)
return false;
}
}
return true;
}
String Blob::normalizedContentType(const String& contentType)
{
if (Blob::isValidContentType(contentType))
return contentType.lower();
return emptyString();
}
bool Blob::isNormalizedContentType(const String& contentType)
{
if (contentType.isNull())
return true;
size_t length = contentType.length();
if (contentType.is8Bit()) {
const LChar* characters = contentType.characters8();
for (size_t i = 0; i < length; ++i) {
if (characters[i] < 0x20 || characters[i] > 0x7e)
return false;
if (characters[i] >= 'A' && characters[i] <= 'Z')
return false;
}
} else {
const UChar* characters = contentType.characters16();
for (size_t i = 0; i < length; ++i) {
if (characters[i] < 0x20 || characters[i] > 0x7e)
return false;
if (characters[i] >= 'A' && characters[i] <= 'Z')
return false;
}
}
return true;
}
bool Blob::isNormalizedContentType(const CString& contentType)
{
size_t length = contentType.length();
const char* characters = contentType.data();
for (size_t i = 0; i < length; ++i) {
if (characters[i] < 0x20 || characters[i] > 0x7e)
return false;
if (characters[i] >= 'A' && characters[i] <= 'Z')
return false;
}
return true;
}
#if ENABLE(BLOB)
PassRefPtr<Blob> Blob::slice(long long start, long long end, const String& contentType) const
{
long long size;
double modificationTime;
if (isFile()) {
toFile(this)->captureSnapshot(size, modificationTime);
} else {
ASSERT(m_size != -1);
size = m_size;
}
if (start < 0)
start = start + size;
if (end < 0)
end = end + size;
if (start < 0)
start = 0;
if (end < 0)
end = 0;
if (start >= size) {
start = 0;
end = 0;
} else if (end < start)
end = start;
else if (end > size)
end = size;
long long length = end - start;
OwnPtr<BlobData> blobData = BlobData::create();
blobData->setContentType(Blob::normalizedContentType(contentType));
if (isFile()) {
#if ENABLE(FILE_SYSTEM)
if (!toFile(this)->fileSystemURL().isEmpty())
blobData->appendURL(toFile(this)->fileSystemURL(), start, length, modificationTime);
else
#endif
blobData->appendFile(toFile(this)->path(), start, length, modificationTime);
} else
blobData->appendBlob(m_internalURL, start, length);
return Blob::create(blobData.release(), length);
}
#endif
}