aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar Hal Canary <halcanary@google.com>2018-03-01 12:32:18 -0500
committerGravatar Skia Commit-Bot <skia-commit-bot@chromium.org>2018-03-01 19:03:19 +0000
commit2d0e1248d6eef36ecc510785e9bf8a28530c56fe (patch)
treeae146e3478a79c02508a466a6a77e8d03440d943
parent44b61204d9f5681b9474db017577d56f42a32d66 (diff)
SkString: fix ::setUTF16
Change-Id: I7ab4af9ae55a43cc05f81b0c236f29a64beac982 Reviewed-on: https://skia-review.googlesource.com/111223 Reviewed-by: Ben Wagner <bungeman@google.com> Commit-Queue: Hal Canary <halcanary@google.com>
-rw-r--r--src/core/SkString.cpp46
-rw-r--r--src/ports/SkOSFile_stdio.cpp50
-rw-r--r--tests/StringTest.cpp48
3 files changed, 96 insertions, 48 deletions
diff --git a/src/core/SkString.cpp b/src/core/SkString.cpp
index 1242b3333d..d388f18ec7 100644
--- a/src/core/SkString.cpp
+++ b/src/core/SkString.cpp
@@ -378,30 +378,34 @@ void SkString::setUTF16(const uint16_t src[]) {
this->setUTF16(src, count);
}
-void SkString::setUTF16(const uint16_t src[], size_t count) {
- count = trim_size_t_to_u32(count);
-
- if (0 == count) {
- this->reset();
- } else if (count <= fRec->fLength) {
- // should we resize if len <<<< fLength, to save RAM? (e.g. len < (fLength>>1))
- if (count < fRec->fLength) {
- this->resize(count);
- }
- char* p = this->writable_str();
- for (size_t i = 0; i < count; i++) {
- p[i] = SkToU8(src[i]);
+static SkString utf8_from_utf16(const uint16_t src[], size_t count) {
+ SkString ret;
+ if (count > 0) {
+ SkASSERT(src);
+ size_t n = 0;
+ const uint16_t* end = src + count;
+ for (const uint16_t* ptr = src; ptr < end;) {
+ const uint16_t* last = ptr;
+ SkUnichar u = SkUTF16_NextUnichar(&ptr);
+ size_t s = SkUTF8_FromUnichar(u);
+ if (n > SK_MaxU32 - s) {
+ end = last; // truncate input string
+ break;
+ }
+ n += s;
}
- p[count] = 0;
- } else {
- SkString tmp(count); // puts a null terminator at the end of the string
- char* p = tmp.writable_str();
-
- for (size_t i = 0; i < count; i++) {
- p[i] = SkToU8(src[i]);
+ ret = SkString(n);
+ char* out = ret.writable_str();
+ for (const uint16_t* ptr = src; ptr < end;) {
+ out += SkUTF8_FromUnichar(SkUTF16_NextUnichar(&ptr), out);
}
- this->swap(tmp);
+ SkASSERT(out == ret.writable_str() + n);
}
+ return ret;
+}
+
+void SkString::setUTF16(const uint16_t src[], size_t count) {
+ *this = utf8_from_utf16(src, count);
}
void SkString::insert(size_t offset, const char text[]) {
diff --git a/src/ports/SkOSFile_stdio.cpp b/src/ports/SkOSFile_stdio.cpp
index 7cdc549df6..d8541c21c0 100644
--- a/src/ports/SkOSFile_stdio.cpp
+++ b/src/ports/SkOSFile_stdio.cpp
@@ -19,14 +19,53 @@
#ifdef _WIN32
#include <direct.h>
#include <io.h>
+#include <vector>
+#include "SkUtils.h"
#endif
#ifdef SK_BUILD_FOR_IOS
#include "SkOSFile_ios.h"
#endif
+#ifdef _WIN32
+static bool is_ascii(const char* s) {
+ while (char v = *s++) {
+ if ((v & 0x80) != 0) {
+ return false;
+ }
+ }
+ return true;
+}
+
+static FILE* fopen_win(const char* utf8path, const char* perm) {
+ if (is_ascii(utf8path)) {
+ return fopen(utf8path, perm);
+ }
+
+ const char* ptr = utf8path;
+ const char* end = utf8path + strlen(utf8path);
+ size_t n = 0;
+ while (ptr < end) {
+ SkUnichar u = SkUTF8_NextUnicharWithError(&ptr, end);
+ if (u < 0) {
+ return nullptr; // malformed UTF-8
+ }
+ n += SkUTF16_FromUnichar(u);
+ }
+ std::vector<uint16_t> wchars(n + 1);
+ uint16_t* out = wchars.data();
+ for (const char* ptr = utf8path; ptr < end;) {
+ out += SkUTF16_FromUnichar(SkUTF8_NextUnicharWithError(&ptr, end), out);
+ }
+ SkASSERT(out == &wchars[n]);
+ *out = 0; // final null
+ wchar_t wperms[4] = {(wchar_t)perm[0], (wchar_t)perm[1], (wchar_t)perm[2], (wchar_t)perm[3]};
+ return _wfopen((wchar_t*)wchars.data(), wperms);
+}
+#endif
+
FILE* sk_fopen(const char path[], SkFILE_Flags flags) {
- char perm[4];
+ char perm[4] = {0, 0, 0, 0};
char* p = perm;
if (flags & kRead_SkFILE_Flag) {
@@ -35,13 +74,14 @@ FILE* sk_fopen(const char path[], SkFILE_Flags flags) {
if (flags & kWrite_SkFILE_Flag) {
*p++ = 'w';
}
- *p++ = 'b';
- *p = 0;
+ *p = 'b';
- //TODO: on Windows fopen is just ASCII or the current code page,
- //convert to utf16 and use _wfopen
FILE* file = nullptr;
+#ifdef _WIN32
+ file = fopen_win(path, perm);
+#else
file = fopen(path, perm);
+#endif
#ifdef SK_BUILD_FOR_IOS
// if not found in default path and read-only, try to open from bundle
if (!file && kRead_SkFILE_Flag == flags) {
diff --git a/tests/StringTest.cpp b/tests/StringTest.cpp
index f9f76e9f21..5ff24125b0 100644
--- a/tests/StringTest.cpp
+++ b/tests/StringTest.cpp
@@ -11,27 +11,6 @@
#include "Test.h"
#include <thread>
-// Windows vsnprintf doesn't 0-terminate safely), but is so far
-// encapsulated in SkString that we can't test it directly.
-
-#ifdef SK_BUILD_FOR_WIN
- #define VSNPRINTF(buffer, size, format, args) \
- vsnprintf_s(buffer, size, _TRUNCATE, format, args)
-#else
- #define VSNPRINTF vsnprintf
-#endif
-
-#define ARGS_TO_BUFFER(format, buffer, size) \
- do { \
- va_list args; \
- va_start(args, format); \
- VSNPRINTF(buffer, size, format, args); \
- va_end(args); \
- } while (0)
-
-static void printfAnalog(char* buffer, int size, const char format[], ...) {
- ARGS_TO_BUFFER(format, buffer, size);
-}
DEF_TEST(String, reporter) {
SkString a;
@@ -188,7 +167,7 @@ DEF_TEST(String, reporter) {
REPORTER_ASSERT(reporter, buffer[18] == 'a');
REPORTER_ASSERT(reporter, buffer[19] == 'a');
REPORTER_ASSERT(reporter, buffer[20] == 'a');
- printfAnalog(buffer, 20, "%30d", 0);
+ snprintf(buffer, 20, "%30d", 0);
REPORTER_ASSERT(reporter, buffer[18] == ' ');
REPORTER_ASSERT(reporter, buffer[19] == 0);
REPORTER_ASSERT(reporter, buffer[20] == 'a');
@@ -325,3 +304,28 @@ DEF_TEST(String_huge, r) {
}
}
+static SkString utf16_to_utf8(const uint16_t* utf16, size_t len) {
+ SkString s;
+ s.setUTF16(utf16, len);
+ return s;
+}
+
+DEF_TEST(String_fromUTF16, r) {
+ // test data produced with `iconv`.
+ const uint16_t test1[] = {
+ 0xD835, 0xDCD0, 0xD835, 0xDCD1, 0xD835, 0xDCD2, 0xD835, 0xDCD3, 0xD835, 0xDCD4, 0x0020,
+ 0xD835, 0xDCD5, 0xD835, 0xDCD6, 0xD835, 0xDCD7, 0xD835, 0xDCD8, 0xD835, 0xDCD9
+ };
+ REPORTER_ASSERT(r, utf16_to_utf8(test1, SK_ARRAY_COUNT(test1)).equals("𝓐𝓑𝓒𝓓𝓔 π“•π“–π“—π“˜π“™"));
+
+ const uint16_t test2[] = {
+ 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0020, 0x0046, 0x0047, 0x0048, 0x0049, 0x004A,
+ };
+ REPORTER_ASSERT(r, utf16_to_utf8(test2, SK_ARRAY_COUNT(test2)).equals("ABCDE FGHIJ"));
+
+ const uint16_t test3[] = {
+ 0x03B1, 0x03B2, 0x03B3, 0x03B4, 0x03B5, 0x0020, 0x03B6, 0x03B7, 0x03B8, 0x03B9, 0x03BA,
+ };
+ REPORTER_ASSERT(r, utf16_to_utf8(test3, SK_ARRAY_COUNT(test3)).equals("αβγδΡ ΢ηθικ"));
+}
+