|
31 | 31 | #include "v8-profiler.h"
|
32 | 32 | #include "v8.h"
|
33 | 33 |
|
| 34 | +#include <unicode/unistr.h> |
| 35 | + |
34 | 36 | #include <cstring>
|
35 | 37 | #include <climits>
|
36 | 38 |
|
|
56 | 58 | namespace node {
|
57 | 59 | namespace Buffer {
|
58 | 60 |
|
| 61 | +using v8::Array; |
59 | 62 | using v8::ArrayBuffer;
|
60 | 63 | using v8::ArrayBufferCreationMode;
|
61 | 64 | using v8::ArrayBufferView;
|
@@ -1051,6 +1054,117 @@ static void EncodeUtf8String(const FunctionCallbackInfo<Value>& args) {
|
1051 | 1054 | }
|
1052 | 1055 |
|
1053 | 1056 |
|
| 1057 | +static void EncodeInto(const FunctionCallbackInfo<Value>& args) { |
| 1058 | + Environment* env = Environment::GetCurrent(args); |
| 1059 | + Isolate* isolate = env->isolate(); |
| 1060 | + Local<Context> context = env->context(); |
| 1061 | + CHECK_GE(args.Length(), 2); |
| 1062 | + CHECK(args[0]->IsString()); |
| 1063 | + CHECK(args[1]->IsUint8Array()); |
| 1064 | + |
| 1065 | + size_t read = 0; |
| 1066 | + size_t written = 0; |
| 1067 | + |
| 1068 | + Utf8Value src(isolate, args[0]); |
| 1069 | + const char* p = *src; |
| 1070 | + |
| 1071 | + Local<Uint8Array> dest = args[1].As<Uint8Array>(); |
| 1072 | + Local<ArrayBuffer> buf = dest->Buffer(); |
| 1073 | + char* write_result = |
| 1074 | + static_cast<char*>(buf->GetContents().Data()) + dest->ByteOffset(); |
| 1075 | + size_t dest_length = dest->ByteLength(); |
| 1076 | + |
| 1077 | + for (size_t i = 0; i < src.length(); ) { |
| 1078 | + uint32_t code = 0; |
| 1079 | + |
| 1080 | + if ((p[i] & 0x80) == 0) { |
| 1081 | + code = p[i]; |
| 1082 | + i += 1; |
| 1083 | + } else if ((p[i] & 0xE0) == 0xC0 && (i + 1 < src.length())) { |
| 1084 | + code = (p[i] & 0x1F) << 6; |
| 1085 | + code |= (p[i+1] & 0x3F); |
| 1086 | + i += 2; |
| 1087 | + } else if ((p[i] & 0xF0) == 0xE0 && (i + 2 < src.length())) { |
| 1088 | + code = (p[i] & 0xF) << 12; |
| 1089 | + code |= (p[i+1] & 0x3F) << 6; |
| 1090 | + code |= (p[i+2] & 0x3F); |
| 1091 | + i += 3; |
| 1092 | + } else if ((p[i] & 0xF8) == 0xF0 && (i + 3 < src.length())) { |
| 1093 | + code = (p[i] & 0x7) << 18; |
| 1094 | + code |= (p[i+1] & 0x3F) << 12; |
| 1095 | + code |= (p[i+2] & 0x3F) << 6; |
| 1096 | + code |= (p[i+3] & 0x3F); |
| 1097 | + i += 4; |
| 1098 | + } else if ((p[i] & 0xFC) == 0xF8 && (i + 4 < src.length())) { |
| 1099 | + code = (p[i] & 0x3) << 24; |
| 1100 | + code |= (p[i+1] & 0x3F) << 18; |
| 1101 | + code |= (p[i+2] & 0x3F) << 12; |
| 1102 | + code |= (p[i+3] & 0x3F) << 6; |
| 1103 | + code |= (p[i+4] & 0x3F); |
| 1104 | + i += 5; |
| 1105 | + } else if ((p[i] & 0xFE) == 0xFC && (i + 5 < src.length())) { |
| 1106 | + code = (p[i] & 0x1) << 30; |
| 1107 | + code |= (p[i+1] & 0x3F) << 24; |
| 1108 | + code |= (p[i+2] & 0x3F) << 18; |
| 1109 | + code |= (p[i+3] & 0x3F) << 12; |
| 1110 | + code |= (p[i+4] & 0x3F) << 6; |
| 1111 | + code |= (p[i+5] & 0x3F); |
| 1112 | + i += 6; |
| 1113 | + } |
| 1114 | + |
| 1115 | + if (code <= 0x7F) { |
| 1116 | + if (dest_length < 1) break; |
| 1117 | + |
| 1118 | + *write_result++ = static_cast<char>(code); |
| 1119 | + read += 1; |
| 1120 | + written += 1; |
| 1121 | + dest_length -= 1; |
| 1122 | + } else if (code <= 0x7FF) { |
| 1123 | + if (dest_length < 2) break; |
| 1124 | + |
| 1125 | + *write_result++ = (0xC0 | (code >> 6)); |
| 1126 | + *write_result++ = (0x80 | (code & 0x3F)); |
| 1127 | + read += 1; |
| 1128 | + written += 2; |
| 1129 | + dest_length -= 2; |
| 1130 | + } else if (code <= 0xFFFF) { |
| 1131 | + if (dest_length < 3) break; |
| 1132 | + |
| 1133 | + *write_result++ = (0xE0 | (code >> 12)); |
| 1134 | + *write_result++ = (0x80 | ((code >> 6) & 0x3F)); |
| 1135 | + *write_result++ = (0x80 | (code & 0x3F)); |
| 1136 | + read += 1; |
| 1137 | + written += 3; |
| 1138 | + dest_length -= 3; |
| 1139 | + } else if (code <= 0x1FFFFF) { |
| 1140 | + if (dest_length < 4) break; |
| 1141 | + |
| 1142 | + *write_result++ = (0xF0 | (code >> 18)); |
| 1143 | + *write_result++ = (0x80 | ((code >> 12) & 0x3F)); |
| 1144 | + *write_result++ = (0x80 | ((code >> 6) & 0x3F)); |
| 1145 | + *write_result++ = (0x80 | (code & 0x3F)); |
| 1146 | + read += 2; |
| 1147 | + written += 4; |
| 1148 | + dest_length -= 4; |
| 1149 | + } else { |
| 1150 | + // invalid unicode |
| 1151 | + } |
| 1152 | + } |
| 1153 | + |
| 1154 | + Local<Object> result = Object::New(isolate); |
| 1155 | + if (result->Set(context, |
| 1156 | + env->encoding_read_string(), |
| 1157 | + Integer::New(isolate, read)).IsNothing() || |
| 1158 | + result->Set(context, |
| 1159 | + env->encoding_written_string(), |
| 1160 | + Integer::New(isolate, written)).IsNothing()) { |
| 1161 | + return; |
| 1162 | + } |
| 1163 | + |
| 1164 | + args.GetReturnValue().Set(result); |
| 1165 | +} |
| 1166 | + |
| 1167 | + |
1054 | 1168 | void SetBufferPrototype(const FunctionCallbackInfo<Value>& args) {
|
1055 | 1169 | Environment* env = Environment::GetCurrent(args);
|
1056 | 1170 |
|
@@ -1082,6 +1196,7 @@ void Initialize(Local<Object> target,
|
1082 | 1196 | env->SetMethod(target, "swap32", Swap32);
|
1083 | 1197 | env->SetMethod(target, "swap64", Swap64);
|
1084 | 1198 |
|
| 1199 | + env->SetMethod(target, "encodeInto", EncodeInto); |
1085 | 1200 | env->SetMethodNoSideEffect(target, "encodeUtf8String", EncodeUtf8String);
|
1086 | 1201 |
|
1087 | 1202 | target->Set(env->context(),
|
|
0 commit comments