#include "config.h"
#include "AtomicString.h"
#include "KURL.h"
#include "LinkHash.h"
#include "PlatformString.h"
#include "StringHash.h"
#include "StringImpl.h"
namespace WebCore {
static inline int findSlashDotDotSlash(const UChar* characters, size_t length)
{
if (length < 4)
return -1;
unsigned loopLimit = length - 3;
for (unsigned i = 0; i < loopLimit; ++i) {
if (characters[i] == '/' && characters[i + 1] == '.' && characters[i + 2] == '.' && characters[i + 3] == '/')
return i;
}
return -1;
}
static inline int findSlashSlash(const UChar* characters, size_t length, int position)
{
if (length < 2)
return -1;
unsigned loopLimit = length - 1;
for (unsigned i = position; i < loopLimit; ++i) {
if (characters[i] == '/' && characters[i + 1] == '/')
return i;
}
return -1;
}
static inline int findSlashDotSlash(const UChar* characters, size_t length)
{
if (length < 3)
return -1;
unsigned loopLimit = length - 2;
for (unsigned i = 0; i < loopLimit; ++i) {
if (characters[i] == '/' && characters[i + 1] == '.' && characters[i + 2] == '/')
return i;
}
return -1;
}
static inline bool containsColonSlashSlash(const UChar* characters, unsigned length)
{
if (length < 3)
return false;
unsigned loopLimit = length - 2;
for (unsigned i = 0; i < loopLimit; ++i) {
if (characters[i] == ':' && characters[i + 1] == '/' && characters[i + 2] == '/')
return true;
}
return false;
}
static inline void cleanPath(Vector<UChar, 512>& path)
{
int pos;
while ((pos = findSlashDotDotSlash(path.data(), path.size())) != -1) {
int prev = reverseFind(path.data(), path.size(), '/', pos - 1);
if (prev < 0 || (prev > 3 && path[prev - 2] == ':' && path[prev - 1] == '/'))
path.remove(pos, 3);
else
path.remove(prev, pos - prev + 3);
}
pos = 0;
int refPos = -2;
while ((pos = findSlashSlash(path.data(), path.size(), pos)) != -1) {
if (refPos == -2)
refPos = find(path.data(), path.size(), '#');
if (refPos > 0 && pos >= refPos)
break;
if (pos == 0 || path[pos - 1] != ':')
path.remove(pos);
else
pos += 2;
}
while ((pos = findSlashDotSlash(path.data(), path.size())) != -1)
path.remove(pos, 2);
}
static inline bool matchLetter(UChar c, UChar lowercaseLetter)
{
return (c | 0x20) == lowercaseLetter;
}
static inline bool needsTrailingSlash(const UChar* characters, unsigned length)
{
if (length < 6)
return false;
if (!matchLetter(characters[0], 'h')
|| !matchLetter(characters[1], 't')
|| !matchLetter(characters[2], 't')
|| !matchLetter(characters[3], 'p'))
return false;
if (!(characters[4] == ':'
|| (matchLetter(characters[4], 's') && characters[5] == ':')))
return false;
unsigned pos = characters[4] == ':' ? 5 : 6;
if (pos + 1 < length && characters[pos] == '/' && characters[pos + 1] == '/')
pos += 2;
while (pos < length && characters[pos] != '/')
++pos;
return pos == length;
}
static ALWAYS_INLINE LinkHash visitedLinkHashInline(const UChar* url, unsigned length)
{
return AlreadyHashed::avoidDeletedValue(StringImpl::computeHash(url, length));
}
LinkHash visitedLinkHash(const UChar* url, unsigned length)
{
return visitedLinkHashInline(url, length);
}
static ALWAYS_INLINE void visitedURLInline(const KURL& base, const AtomicString& attributeURL, Vector<UChar, 512>& buffer)
{
if (attributeURL.isNull())
return;
const UChar* characters = attributeURL.characters();
unsigned length = attributeURL.length();
bool hasColonSlashSlash = containsColonSlashSlash(characters, length);
if (hasColonSlashSlash && !needsTrailingSlash(characters, length)) {
buffer.append(attributeURL.characters(), attributeURL.length());
return;
}
if (hasColonSlashSlash) {
buffer.append(characters, length);
buffer.append('/');
return;
}
if (!length)
buffer.append(base.string().characters(), base.string().length());
else {
switch (characters[0]) {
case '/':
buffer.append(base.string().characters(), base.pathStart());
break;
case '#':
buffer.append(base.string().characters(), base.pathEnd());
break;
default:
buffer.append(base.string().characters(), base.pathAfterLastSlash());
break;
}
}
buffer.append(characters, length);
cleanPath(buffer);
if (needsTrailingSlash(buffer.data(), buffer.size())) {
buffer.append('/');
}
return;
}
void visitedURL(const KURL& base, const AtomicString& attributeURL, Vector<UChar, 512>& buffer)
{
return visitedURLInline(base, attributeURL, buffer);
}
LinkHash visitedLinkHash(const KURL& base, const AtomicString& attributeURL)
{
Vector<UChar, 512> url;
visitedURLInline(base, attributeURL, url);
if (url.isEmpty())
return 0;
return visitedLinkHashInline(url.data(), url.size());
}
}