#include "config.h"
#include "LineEnding.h"
#include <wtf/text/CString.h>
#include <wtf/text/WTFString.h>
namespace {
class OutputBuffer {
public:
virtual uint8_t* allocate(size_t size) = 0;
virtual void copy(const CString&) = 0;
virtual ~OutputBuffer() { }
};
class CStringBuffer : public OutputBuffer {
public:
CStringBuffer(CString& buffer)
: m_buffer(buffer)
{
}
virtual ~CStringBuffer() { }
uint8_t* allocate(size_t size) override
{
char* ptr;
m_buffer = CString::newUninitialized(size, ptr);
return reinterpret_cast<uint8_t*>(ptr);
}
void copy(const CString& source) override
{
m_buffer = source;
}
const CString& buffer() const { return m_buffer; }
private:
CString m_buffer;
};
#if OS(WINDOWS)
class VectorCharAppendBuffer : public OutputBuffer {
public:
VectorCharAppendBuffer(Vector<uint8_t>& buffer)
: m_buffer(buffer)
{
}
virtual ~VectorCharAppendBuffer() { }
uint8_t* allocate(size_t size) override
{
size_t oldSize = m_buffer.size();
m_buffer.grow(oldSize + size);
return m_buffer.data() + oldSize;
}
void copy(const CString& source) override
{
m_buffer.append(source.data(), source.length());
}
private:
Vector<uint8_t>& m_buffer;
};
#endif
void internalNormalizeLineEndingsToCRLF(const CString& from, OutputBuffer& buffer)
{
if (!from.length())
return;
size_t newLen = 0;
const char* p = from.data();
while (p < from.data() + from.length()) {
char c = *p++;
if (c == '\r') {
if (*p != '\n') {
newLen += 2;
}
} else if (c == '\n') {
newLen += 2;
} else {
newLen += 1;
}
}
if (newLen < from.length())
return;
if (newLen == from.length()) {
buffer.copy(from);
return;
}
p = from.data();
uint8_t* q = buffer.allocate(newLen);
while (p < from.data() + from.length()) {
char c = *p++;
if (c == '\r') {
if (*p != '\n') {
*q++ = '\r';
*q++ = '\n';
}
} else if (c == '\n') {
*q++ = '\r';
*q++ = '\n';
} else {
*q++ = c;
}
}
}
};
namespace WebCore {
static void normalizeToCROrLF(const CString& from, Vector<uint8_t>& result, bool toCR)
{
size_t newLen = 0;
bool needFix = false;
const char* p = from.data();
char fromEndingChar = toCR ? '\n' : '\r';
char toEndingChar = toCR ? '\r' : '\n';
while (p < from.data() + from.length()) {
char c = *p++;
if (c == '\r' && *p == '\n') {
p++;
needFix = true;
} else if (c == fromEndingChar) {
needFix = true;
}
newLen += 1;
}
p = from.data();
size_t oldResultSize = result.size();
result.grow(oldResultSize + newLen);
uint8_t* q = result.data() + oldResultSize;
if (!needFix) {
memcpy(q, p, from.length());
return;
}
while (p < from.data() + from.length()) {
char c = *p++;
if (c == '\r' && *p == '\n') {
p++;
*q++ = toEndingChar;
} else if (c == fromEndingChar) {
*q++ = toEndingChar;
} else {
*q++ = c;
}
}
}
CString normalizeLineEndingsToCRLF(const CString& from)
{
CString result;
CStringBuffer buffer(result);
internalNormalizeLineEndingsToCRLF(from, buffer);
return buffer.buffer();
}
void normalizeLineEndingsToNative(const CString& from, Vector<uint8_t>& result)
{
#if OS(WINDOWS)
VectorCharAppendBuffer buffer(result);
internalNormalizeLineEndingsToCRLF(from, buffer);
#else
normalizeToCROrLF(from, result, false);
#endif
}
}