Skip to content

Commit

Permalink
[Chromoting] Handle CR-LF correctly when transferring text items to a…
Browse files Browse the repository at this point in the history
…nd from the clipboard on a Windows host.

When reading from the clipboard, CR-LF pairs are replaced by LF.
When writing to the clipboard, each LF is replaced by CR-LF.

BUG=117473


Review URL: https://chromiumcodereview.appspot.com/10441131

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@140206 0039d316-1c4b-4281-b951-d872f2087c98
  • Loading branch information
simonmorris@chromium.org committed Jun 2, 2012
1 parent d65e15b commit a93c8c8
Show file tree
Hide file tree
Showing 4 changed files with 116 additions and 2 deletions.
38 changes: 38 additions & 0 deletions remoting/base/util.cc
Original file line number Diff line number Diff line change
Expand Up @@ -265,4 +265,42 @@ void CopyRGB32Rect(const uint8* source_buffer,
SkIRect::MakeWH(dest_rect.width(), dest_rect.height()));
}

std::string ReplaceLfByCrLf(const std::string& in) {
std::string out;
out.resize(2 * in.size());
char* out_p_begin = &out[0];
char* out_p = out_p_begin;
const char* in_p_begin = &in[0];
const char* in_p_end = &in[in.size()];
for (const char* in_p = in_p_begin; in_p < in_p_end; ++in_p) {
char c = *in_p;
if (c == '\n') {
*out_p++ = '\r';
}
*out_p++ = c;
}
out.resize(out_p - out_p_begin);
return out;
}

std::string ReplaceCrLfByLf(const std::string& in) {
std::string out;
out.resize(in.size());
char* out_p_begin = &out[0];
char* out_p = out_p_begin;
const char* in_p_begin = &in[0];
const char* in_p_end = &in[in.size()];
for (const char* in_p = in_p_begin; in_p < in_p_end; ++in_p) {
char c = *in_p;
if ((c == '\r') && (in_p + 1 < in_p_end) && (*(in_p + 1) == '\n')) {
*out_p++ = '\n';
++in_p;
} else {
*out_p++ = c;
}
}
out.resize(out_p - out_p_begin);
return out;
}

} // namespace remoting
6 changes: 6 additions & 0 deletions remoting/base/util.h
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,12 @@ void CopyRGB32Rect(const uint8* source_buffer,
const SkIRect& dest_buffer_rect,
const SkIRect& dest_rect);

// Replaces every occurrence of "\n" in a string by "\r\n".
std::string ReplaceLfByCrLf(const std::string& in);

// Replaces every occurrence of "\r\n" in a string by "\n".
std::string ReplaceCrLfByLf(const std::string& in);

} // namespace remoting

#endif // REMOTING_BASE_UTIL_H_
69 changes: 69 additions & 0 deletions remoting/base/util_unittest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -184,4 +184,73 @@ TEST(YuvToRgbTest, ClippingAndScaling) {
}
}

TEST(ReplaceLfByCrLfTest, Basic) {
EXPECT_EQ("ab", ReplaceLfByCrLf("ab"));
EXPECT_EQ("\r\nab", ReplaceLfByCrLf("\nab"));
EXPECT_EQ("\r\nab\r\n", ReplaceLfByCrLf("\nab\n"));
EXPECT_EQ("\r\nab\r\ncd", ReplaceLfByCrLf("\nab\ncd"));
EXPECT_EQ("\r\nab\r\ncd\r\n", ReplaceLfByCrLf("\nab\ncd\n"));
EXPECT_EQ("\r\n\r\nab\r\n\r\ncd\r\n\r\n",
ReplaceLfByCrLf("\n\nab\n\ncd\n\n"));
}

TEST(ReplaceLfByCrLfTest, Speed) {
int kLineSize = 128;
std::string line(kLineSize, 'a');
line[kLineSize - 1] = '\n';
// Make a 10M string.
int kLineNum = 10 * 1024 * 1024 / kLineSize;
std::string buffer;
buffer.resize(kLineNum * kLineSize);
for (int i = 0; i < kLineNum; ++i) {
memcpy(&buffer[i * kLineSize], &line[0], kLineSize);
}
// Convert the string.
buffer = ReplaceLfByCrLf(buffer);
// Check the converted string.
EXPECT_EQ(static_cast<size_t>((kLineSize + 1) * kLineNum), buffer.size());
const char* p = &buffer[0];
for (int i = 0; i < kLineNum; ++i) {
EXPECT_EQ(0, memcmp(&line[0], p, kLineSize - 1));
p += kLineSize - 1;
EXPECT_EQ('\r', *p++);
EXPECT_EQ('\n', *p++);
}
}

TEST(ReplaceCrLfByLfTest, Basic) {
EXPECT_EQ("ab", ReplaceCrLfByLf("ab"));
EXPECT_EQ("\nab", ReplaceCrLfByLf("\r\nab"));
EXPECT_EQ("\nab\n", ReplaceCrLfByLf("\r\nab\r\n"));
EXPECT_EQ("\nab\ncd", ReplaceCrLfByLf("\r\nab\r\ncd"));
EXPECT_EQ("\nab\ncd\n", ReplaceCrLfByLf("\r\nab\r\ncd\n"));
EXPECT_EQ("\n\nab\n\ncd\n\n",
ReplaceCrLfByLf("\r\n\r\nab\r\n\r\ncd\r\n\r\n"));
EXPECT_EQ("\rab\rcd\r", ReplaceCrLfByLf("\rab\rcd\r"));
}

TEST(ReplaceCrLfByLfTest, Speed) {
int kLineSize = 128;
std::string line(kLineSize, 'a');
line[kLineSize - 2] = '\r';
line[kLineSize - 1] = '\n';
// Make a 10M string.
int kLineNum = 10 * 1024 * 1024 / kLineSize;
std::string buffer;
buffer.resize(kLineNum * kLineSize);
for (int i = 0; i < kLineNum; ++i) {
memcpy(&buffer[i * kLineSize], &line[0], kLineSize);
}
// Convert the string.
buffer = ReplaceCrLfByLf(buffer);
// Check the converted string.
EXPECT_EQ(static_cast<size_t>((kLineSize - 1) * kLineNum), buffer.size());
const char* p = &buffer[0];
for (int i = 0; i < kLineNum; ++i) {
EXPECT_EQ(0, memcmp(&line[0], p, kLineSize - 2));
p += kLineSize - 2;
EXPECT_EQ('\n', *p++);
}
}

} // namespace remoting
5 changes: 3 additions & 2 deletions remoting/host/clipboard_win.cc
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include "base/win/windows_version.h"
#include "base/win/wrapped_window_proc.h"
#include "remoting/base/constants.h"
#include "remoting/base/util.h"
#include "remoting/proto/event.pb.h"
#include "remoting/protocol/clipboard_stub.h"

Expand Down Expand Up @@ -202,7 +203,7 @@ void ClipboardWin::InjectClipboardEvent(
if (event.mime_type().compare(kMimeTypeTextUtf8)) {
return;
}
string16 text = UTF8ToUTF16(event.data());
string16 text = UTF8ToUTF16(ReplaceLfByCrLf(event.data()));

ScopedClipboard clipboard;
if (!clipboard.Init(hwnd_)) {
Expand Down Expand Up @@ -259,7 +260,7 @@ void ClipboardWin::OnClipboardUpdate() {

protocol::ClipboardEvent event;
event.set_mime_type(kMimeTypeTextUtf8);
event.set_data(UTF16ToUTF8(text));
event.set_data(ReplaceCrLfByLf(UTF16ToUTF8(text)));

if (client_clipboard_.get()) {
client_clipboard_->InjectClipboardEvent(event);
Expand Down

0 comments on commit a93c8c8

Please sign in to comment.