1 // Copyright Joyent, Inc. and other Node contributors.
3 // Permission is hereby granted, free of charge, to any person obtaining a
4 // copy of this software and associated documentation files (the
5 // "Software"), to deal in the Software without restriction, including
6 // without limitation the rights to use, copy, modify, merge, publish,
7 // distribute, sublicense, and/or sell copies of the Software, and to permit
8 // persons to whom the Software is furnished to do so, subject to the
9 // following conditions:
11 // The above copyright notice and this permission notice shall be included
12 // in all copies or substantial portions of the Software.
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
17 // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
18 // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
19 // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
20 // USE OR OTHER DEALINGS IN THE SOFTWARE.
22 #ifndef NAN_STRING_BYTES_H_
23 #define NAN_STRING_BYTES_H_
25 // Decodes a v8::Local<v8::String> or Buffer to a raw char*
37 #define base64_encoded_size(size) ((size + 2 - ((size + 2) % 3)) / 3 * 4)
43 static bool contains_non_ascii_slow(const char* buf, size_t len) {
44 for (size_t i = 0; i < len; ++i) {
45 if (buf[i] & 0x80) return true;
51 static bool contains_non_ascii(const char* src, size_t len) {
53 return contains_non_ascii_slow(src, len);
56 const unsigned bytes_per_word = sizeof(void*);
57 const unsigned align_mask = bytes_per_word - 1;
58 const unsigned unaligned = reinterpret_cast<uintptr_t>(src) & align_mask;
61 const unsigned n = bytes_per_word - unaligned;
62 if (contains_non_ascii_slow(src, n)) return true;
68 #if defined(__x86_64__) || defined(_WIN64)
69 const uintptr_t mask = 0x8080808080808080ll;
71 const uintptr_t mask = 0x80808080l;
74 const uintptr_t* srcw = reinterpret_cast<const uintptr_t*>(src);
76 for (size_t i = 0, n = len / bytes_per_word; i < n; ++i) {
77 if (srcw[i] & mask) return true;
80 const unsigned remainder = len & align_mask;
82 const size_t offset = len - remainder;
83 if (contains_non_ascii_slow(src + offset, remainder)) return true;
90 static void force_ascii_slow(const char* src, char* dst, size_t len) {
91 for (size_t i = 0; i < len; ++i) {
92 dst[i] = src[i] & 0x7f;
97 static void force_ascii(const char* src, char* dst, size_t len) {
99 force_ascii_slow(src, dst, len);
103 const unsigned bytes_per_word = sizeof(void*);
104 const unsigned align_mask = bytes_per_word - 1;
105 const unsigned src_unalign = reinterpret_cast<uintptr_t>(src) & align_mask;
106 const unsigned dst_unalign = reinterpret_cast<uintptr_t>(dst) & align_mask;
108 if (src_unalign > 0) {
109 if (src_unalign == dst_unalign) {
110 const unsigned unalign = bytes_per_word - src_unalign;
111 force_ascii_slow(src, dst, unalign);
116 force_ascii_slow(src, dst, len);
121 #if defined(__x86_64__) || defined(_WIN64)
122 const uintptr_t mask = ~0x8080808080808080ll;
124 const uintptr_t mask = ~0x80808080l;
127 const uintptr_t* srcw = reinterpret_cast<const uintptr_t*>(src);
128 uintptr_t* dstw = reinterpret_cast<uintptr_t*>(dst);
130 for (size_t i = 0, n = len / bytes_per_word; i < n; ++i) {
131 dstw[i] = srcw[i] & mask;
134 const unsigned remainder = len & align_mask;
136 const size_t offset = len - remainder;
137 force_ascii_slow(src + offset, dst + offset, remainder);
142 static size_t base64_encode(const char* src,
146 // We know how much we'll write, just make sure that there's space.
147 assert(dlen >= base64_encoded_size(slen) &&
148 "not enough space provided for base64 encode");
150 dlen = base64_encoded_size(slen);
159 static const char table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
160 "abcdefghijklmnopqrstuvwxyz"
168 a = src[i + 0] & 0xff;
169 b = src[i + 1] & 0xff;
170 c = src[i + 2] & 0xff;
172 dst[k + 0] = table[a >> 2];
173 dst[k + 1] = table[((a & 3) << 4) | (b >> 4)];
174 dst[k + 2] = table[((b & 0x0f) << 2) | (c >> 6)];
175 dst[k + 3] = table[c & 0x3f];
184 a = src[i + 0] & 0xff;
185 dst[k + 0] = table[a >> 2];
186 dst[k + 1] = table[(a & 3) << 4];
192 a = src[i + 0] & 0xff;
193 b = src[i + 1] & 0xff;
194 dst[k + 0] = table[a >> 2];
195 dst[k + 1] = table[((a & 3) << 4) | (b >> 4)];
196 dst[k + 2] = table[(b & 0x0f) << 2];
206 static size_t hex_encode(const char* src, size_t slen, char* dst, size_t dlen) {
207 // We know how much we'll write, just make sure that there's space.
208 assert(dlen >= slen * 2 &&
209 "not enough space provided for hex encode");
212 for (uint32_t i = 0, k = 0; k < dlen; i += 1, k += 2) {
213 static const char hex[] = "0123456789abcdef";
214 uint8_t val = static_cast<uint8_t>(src[i]);
215 dst[k + 0] = hex[val >> 4];
216 dst[k + 1] = hex[val & 15];
224 static Local<Value> Encode(const char* buf,
226 enum Encoding encoding) {
227 assert(buflen <= node::Buffer::kMaxLength);
228 if (!buflen && encoding != BUFFER)
229 return New("").ToLocalChecked();
234 return CopyBuffer(buf, buflen).ToLocalChecked();
237 if (contains_non_ascii(buf, buflen)) {
238 char* out = new char[buflen];
239 force_ascii(buf, out, buflen);
240 val = New<String>(out, buflen).ToLocalChecked();
243 val = New<String>(buf, buflen).ToLocalChecked();
248 val = New<String>(buf, buflen).ToLocalChecked();
252 // TODO(isaacs) use ExternalTwoByteString?
253 const unsigned char *cbuf = reinterpret_cast<const unsigned char*>(buf);
254 uint16_t * twobytebuf = new uint16_t[buflen];
255 for (size_t i = 0; i < buflen; i++) {
256 // XXX is the following line platform independent?
257 twobytebuf[i] = cbuf[i];
259 val = New<String>(twobytebuf, buflen).ToLocalChecked();
265 size_t dlen = base64_encoded_size(buflen);
266 char* dst = new char[dlen];
268 size_t written = base64_encode(buf, buflen, dst, dlen);
269 assert(written == dlen);
271 val = New<String>(dst, dlen).ToLocalChecked();
277 const uint16_t* data = reinterpret_cast<const uint16_t*>(buf);
278 val = New<String>(data, buflen / 2).ToLocalChecked();
283 size_t dlen = buflen * 2;
284 char* dst = new char[dlen];
285 size_t written = hex_encode(buf, buflen, dst, dlen);
286 assert(written == dlen);
288 val = New<String>(dst, dlen).ToLocalChecked();
294 assert(0 && "unknown encoding");
301 #undef base64_encoded_size
303 } // end of namespace imp
305 #endif // NAN_STRING_BYTES_H_