#ifndef DecodeEscapeSequences_h
#define DecodeEscapeSequences_h
#include "wtf/ASCIICType.h"
#include "wtf/Assertions.h"
#include "wtf/text/StringBuilder.h"
#include "wtf/text/TextEncoding.h"
namespace WebCore {
struct Unicode16BitEscapeSequence {
enum { sequenceSize = 6 };
static size_t findInString(const String& string, size_t startPosition) { return string.find("%u", startPosition); }
static size_t findEndOfRun(const String& string, size_t startPosition, size_t endPosition)
{
size_t runEnd = startPosition;
while (endPosition - runEnd >= sequenceSize && string[runEnd] == '%' && string[runEnd + 1] == 'u'
&& isASCIIHexDigit(string[runEnd + 2]) && isASCIIHexDigit(string[runEnd + 3])
&& isASCIIHexDigit(string[runEnd + 4]) && isASCIIHexDigit(string[runEnd + 5])) {
runEnd += sequenceSize;
}
return runEnd;
}
template<typename CharType>
static String decodeRun(const CharType* run, size_t runLength, const WTF::TextEncoding&)
{
size_t numberOfSequences = runLength / sequenceSize;
StringBuilder builder;
builder.reserveCapacity(numberOfSequences);
while (numberOfSequences--) {
UChar codeUnit = (toASCIIHexValue(run[2]) << 12) | (toASCIIHexValue(run[3]) << 8) | (toASCIIHexValue(run[4]) << 4) | toASCIIHexValue(run[5]);
builder.append(codeUnit);
run += sequenceSize;
}
return builder.toString();
}
};
struct URLEscapeSequence {
enum { sequenceSize = 3 };
static size_t findInString(const String& string, size_t startPosition) { return string.find('%', startPosition); }
static size_t findEndOfRun(const String& string, size_t startPosition, size_t endPosition)
{
size_t runEnd = startPosition;
int numberOfTrailingCharacters = 0;
while (runEnd < endPosition) {
if (string[runEnd] == '%') {
if (endPosition - runEnd >= sequenceSize && isASCIIHexDigit(string[runEnd + 1]) && isASCIIHexDigit(string[runEnd + 2])) {
runEnd += sequenceSize;
numberOfTrailingCharacters = 0;
} else
break;
} else if (string[runEnd] >= 0x40 && string[runEnd] <= 0x7F && numberOfTrailingCharacters < 2) {
runEnd += 1;
numberOfTrailingCharacters += 1;
} else
break;
}
return runEnd;
}
template<typename CharType>
static String decodeRun(const CharType* run, size_t runLength, const WTF::TextEncoding& encoding)
{
Vector<char, 512> buffer;
buffer.resize(runLength);
char* p = buffer.data();
const CharType* runEnd = run + runLength;
while (run < runEnd) {
if (run[0] == '%') {
*p++ = (toASCIIHexValue(run[1]) << 4) | toASCIIHexValue(run[2]);
run += sequenceSize;
} else {
*p++ = run[0];
run += 1;
}
}
ASSERT(buffer.size() >= static_cast<size_t>(p - buffer.data()));
return (encoding.isValid() ? encoding : UTF8Encoding()).decode(buffer.data(), p - buffer.data());
}
};
template<typename EscapeSequence>
String decodeEscapeSequences(const String& string, const WTF::TextEncoding& encoding)
{
StringBuilder result;
size_t length = string.length();
size_t decodedPosition = 0;
size_t searchPosition = 0;
size_t encodedRunPosition;
while ((encodedRunPosition = EscapeSequence::findInString(string, searchPosition)) != kNotFound) {
size_t encodedRunEnd = EscapeSequence::findEndOfRun(string, encodedRunPosition, length);
searchPosition = encodedRunEnd;
if (encodedRunEnd == encodedRunPosition) {
++searchPosition;
continue;
}
String decoded = string.is8Bit() ?
EscapeSequence::decodeRun(string.characters8() + encodedRunPosition, encodedRunEnd - encodedRunPosition, encoding) :
EscapeSequence::decodeRun(string.characters16() + encodedRunPosition, encodedRunEnd - encodedRunPosition, encoding);
if (decoded.isEmpty())
continue;
result.append(string, decodedPosition, encodedRunPosition - decodedPosition);
result.append(decoded);
decodedPosition = encodedRunEnd;
}
result.append(string, decodedPosition, length - decodedPosition);
return result.toString();
}
}
#endif