| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent db2b23f commit dda81b4
3 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -7,22 +7,14 @@ | |||
| 7 | 7 | #include "node.h" | |
| 8 | 8 | #include "env.h" | |
| 9 | 9 | #include "env-inl.h" | |
| 10 | + #include "util.h" | ||
| 10 | 11 | ||
| 11 | 12 | namespace node { | |
| 12 | 13 | ||
| 13 | 14 | class StringBytes { | |
| 14 | 15 | public: | |
| 15 | - class InlineDecoder { | ||
| 16 | + class InlineDecoder : public MaybeStackBuffer<char> { | ||
| 16 | 17 | public: | |
| 17 | - InlineDecoder() : out_(nullptr) { | ||
| 18 | - } | ||
| 19 | - | ||
| 20 | - ~InlineDecoder() { | ||
| 21 | - if (out_ != out_st_) | ||
| 22 | - delete[] out_; | ||
| 23 | - out_ = nullptr; | ||
| 24 | - } | ||
| 25 | - | ||
| 26 | 18 | inline bool Decode(Environment* env, | |
| 27 | 19 | v8::Local<v8::String> string, | |
| 28 | 20 | v8::Local<v8::Value> encoding, | |
@@ -33,28 +25,22 @@ class StringBytes { | |||
| 33 | 25 | return false; | |
| 34 | 26 | } | |
| 35 | 27 | ||
| 36 | - size_t buflen = StringBytes::StorageSize(env->isolate(), string, enc); | ||
| 37 | - if (buflen > sizeof(out_st_)) | ||
| 38 | - out_ = new char[buflen]; | ||
| 39 | - else | ||
| 40 | - out_ = out_st_; | ||
| 41 | - size_ = StringBytes::Write(env->isolate(), | ||
| 42 | - out_, | ||
| 43 | - buflen, | ||
| 44 | - string, | ||
| 45 | - enc); | ||
| 28 | + const size_t storage = StringBytes::StorageSize(env->isolate(), | ||
| 29 | + string, | ||
| 30 | + enc); | ||
| 31 | + AllocateSufficientStorage(storage); | ||
| 32 | + const size_t length = StringBytes::Write(env->isolate(), | ||
| 33 | + out(), | ||
| 34 | + storage, | ||
| 35 | + string, | ||
| 36 | + enc); | ||
| 37 | + | ||
| 38 | + // No zero terminator is included when using this method. | ||
| 39 | + SetLength(length); | ||
| 46 | 40 | return true; | |
| 47 | 41 | } | |
| 48 | 42 | ||
| 49 | - inline const char* out() const { return out_; } | ||
| 50 | - inline size_t size() const { return size_; } | ||
| 51 | - | ||
| 52 | - private: | ||
| 53 | - static const int kStorageSize = 1024; | ||
| 54 | - | ||
| 55 | - char out_st_[kStorageSize]; | ||
| 56 | - char* out_; | ||
| 57 | - size_t size_; | ||
| 43 | + inline size_t size() const { return length(); } | ||
| 58 | 44 | }; | |
| 59 | 45 | ||
| 60 | 46 | // Does the string match the encoding? Quick but non-exhaustive. | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1,32 +1,78 @@ | |||
| 1 | 1 | #include "util.h" | |
| 2 | + #include "node_buffer.h" | ||
| 2 | 3 | #include "string_bytes.h" | |
| 3 | 4 | ||
| 4 | 5 | namespace node { | |
| 5 | 6 | ||
| 6 | - Utf8Value::Utf8Value(v8::Isolate* isolate, v8::Local<v8::Value> value) | ||
| 7 | - : length_(0), str_(str_st_) { | ||
| 8 | - // Make sure result is always zero-terminated, even if conversion to string | ||
| 9 | - // fails. | ||
| 10 | - str_st_[0] = '\0'; | ||
| 7 | + using v8::Isolate; | ||
| 8 | + using v8::Local; | ||
| 9 | + using v8::String; | ||
| 10 | + using v8::Value; | ||
| 11 | 11 | ||
| 12 | + template <typename T> | ||
| 13 | + static void MakeUtf8String(Isolate* isolate, | ||
| 14 | + Local<Value> value, | ||
| 15 | + T* target) { | ||
| 16 | + Local<String> string = value->ToString(isolate); | ||
| 17 | + if (string.IsEmpty()) | ||
| 18 | + return; | ||
| 19 | + | ||
| 20 | + const size_t storage = StringBytes::StorageSize(isolate, string, UTF8) + 1; | ||
| 21 | + target->AllocateSufficientStorage(storage); | ||
| 22 | + const int flags = | ||
| 23 | + String::NO_NULL_TERMINATION | String::REPLACE_INVALID_UTF8; | ||
| 24 | + const int length = string->WriteUtf8(target->out(), storage, 0, flags); | ||
| 25 | + target->SetLengthAndZeroTerminate(length); | ||
| 26 | + } | ||
| 27 | + | ||
| 28 | + Utf8Value::Utf8Value(Isolate* isolate, Local<Value> value) { | ||
| 12 | 29 | if (value.IsEmpty()) | |
| 13 | 30 | return; | |
| 14 | 31 | ||
| 32 | + MakeUtf8String(isolate, value, this); | ||
| 33 | + } | ||
| 34 | + | ||
| 35 | + | ||
| 36 | + TwoByteValue::TwoByteValue(Isolate* isolate, Local<Value> value) { | ||
| 37 | + if (value.IsEmpty()) { | ||
| 38 | + return; | ||
| 39 | + } | ||
| 40 | + | ||
| 15 | 41 | v8::Local<v8::String> string = value->ToString(isolate); | |
| 16 | 42 | if (string.IsEmpty()) | |
| 17 | 43 | return; | |
| 18 | 44 | ||
| 19 | 45 | // Allocate enough space to include the null terminator | |
| 20 | - size_t len = StringBytes::StorageSize(isolate, string, UTF8) + 1; | ||
| 21 | - if (len > sizeof(str_st_)) { | ||
| 22 | - str_ = static_cast<char*>(malloc(len)); | ||
| 23 | - CHECK_NE(str_, nullptr); | ||
| 24 | - } | ||
| 46 | + const size_t storage = string->Length() + 1; | ||
| 47 | + AllocateSufficientStorage(storage); | ||
| 25 | 48 | ||
| 26 | 49 | const int flags = | |
| 27 | - v8::String::NO_NULL_TERMINATION | v8::String::REPLACE_INVALID_UTF8; | ||
| 28 | - length_ = string->WriteUtf8(str_, len, 0, flags); | ||
| 29 | - str_[length_] = '\0'; | ||
| 50 | + String::NO_NULL_TERMINATION | String::REPLACE_INVALID_UTF8; | ||
| 51 | + const int length = string->Write(out(), 0, storage, flags); | ||
| 52 | + SetLengthAndZeroTerminate(length); | ||
| 53 | + } | ||
| 54 | + | ||
| 55 | + BufferValue::BufferValue(Isolate* isolate, Local<Value> value) { | ||
| 56 | + // Slightly different take on Utf8Value. If value is a String, | ||
| 57 | + // it will return a Utf8 encoded string. If value is a Buffer, | ||
| 58 | + // it will copy the data out of the Buffer as is. | ||
| 59 | + if (value.IsEmpty()) { | ||
| 60 | + // Dereferencing this object will return nullptr. | ||
| 61 | + Invalidate(); | ||
| 62 | + return; | ||
| 63 | + } | ||
| 64 | + | ||
| 65 | + if (value->IsString()) { | ||
| 66 | + MakeUtf8String(isolate, value, this); | ||
| 67 | + } else if (Buffer::HasInstance(value)) { | ||
| 68 | + const size_t len = Buffer::Length(value); | ||
| 69 | + // Leave place for the terminating '\0' byte. | ||
| 70 | + AllocateSufficientStorage(len + 1); | ||
| 71 | + memcpy(out(), Buffer::Data(value), len); | ||
| 72 | + SetLengthAndZeroTerminate(len); | ||
| 73 | + } else { | ||
| 74 | + Invalidate(); | ||
| 75 | + } | ||
| 30 | 76 | } | |
| 31 | 77 | ||
| 32 | 78 | } // namespace node | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -184,31 +184,102 @@ inline char ToLower(char c); | |||
| 184 | 184 | // strcasecmp() is locale-sensitive. Use StringEqualNoCase() instead. | |
| 185 | 185 | inline bool StringEqualNoCase(const char* a, const char* b); | |
| 186 | 186 | ||
| 187 | - class Utf8Value { | ||
| 187 | + // Allocates an array of member type T. For up to kStackStorageSize items, | ||
| 188 | + // the stack is used, otherwise malloc(). | ||
| 189 | + template <typename T, size_t kStackStorageSize = 1024> | ||
| 190 | + class MaybeStackBuffer { | ||
| 188 | 191 | public: | |
| 189 | - explicit Utf8Value(v8::Isolate* isolate, v8::Local<v8::Value> value); | ||
| 192 | + const T* out() const { | ||
| 193 | + return buf_; | ||
| 194 | + } | ||
| 190 | 195 | ||
| 191 | - ~Utf8Value() { | ||
| 192 | - if (str_ != str_st_) | ||
| 193 | - free(str_); | ||
| 196 | + T* out() { | ||
| 197 | + return buf_; | ||
| 194 | 198 | } | |
| 195 | 199 | ||
| 196 | - char* operator*() { | ||
| 197 | - return str_; | ||
| 198 | - }; | ||
| 200 | + // operator* for compatibility with `v8::String::(Utf8)Value` | ||
| 201 | + T* operator*() { | ||
| 202 | + return buf_; | ||
| 203 | + } | ||
| 199 | 204 | ||
| 200 | - const char* operator*() const { | ||
| 201 | - return str_; | ||
| 202 | - }; | ||
| 205 | + const T* operator*() const { | ||
| 206 | + return buf_; | ||
| 207 | + } | ||
| 203 | 208 | ||
| 204 | 209 | size_t length() const { | |
| 205 | 210 | return length_; | |
| 206 | - }; | ||
| 211 | + } | ||
| 212 | + | ||
| 213 | + // Call to make sure enough space for `storage` entries is available. | ||
| 214 | + // There can only be 1 call to AllocateSufficientStorage or Invalidate | ||
| 215 | + // per instance. | ||
| 216 | + void AllocateSufficientStorage(size_t storage) { | ||
| 217 | + if (storage <= kStackStorageSize) { | ||
| 218 | + buf_ = buf_st_; | ||
| 219 | + } else { | ||
| 220 | + // Guard against overflow. | ||
| 221 | + CHECK_LE(storage, sizeof(T) * storage); | ||
| 222 | + | ||
| 223 | + buf_ = static_cast<T*>(malloc(sizeof(T) * storage)); | ||
| 224 | + CHECK_NE(buf_, nullptr); | ||
| 225 | + } | ||
| 226 | + | ||
| 227 | + // Remember how much was allocated to check against that in SetLength(). | ||
| 228 | + length_ = storage; | ||
| 229 | + } | ||
| 230 | + | ||
| 231 | + void SetLength(size_t length) { | ||
| 232 | + // length_ stores how much memory was allocated. | ||
| 233 | + CHECK_LE(length, length_); | ||
| 234 | + length_ = length; | ||
| 235 | + } | ||
| 236 | + | ||
| 237 | + void SetLengthAndZeroTerminate(size_t length) { | ||
| 238 | + // length_ stores how much memory was allocated. | ||
| 239 | + CHECK_LE(length + 1, length_); | ||
| 240 | + SetLength(length); | ||
| 241 | + | ||
| 242 | + // T() is 0 for integer types, nullptr for pointers, etc. | ||
| 243 | + buf_[length] = T(); | ||
| 244 | + } | ||
| 245 | + | ||
| 246 | + // Make derefencing this object return nullptr. | ||
| 247 | + // Calling this is mutually exclusive with calling | ||
| 248 | + // AllocateSufficientStorage. | ||
| 249 | + void Invalidate() { | ||
| 250 | + CHECK_EQ(buf_, buf_st_); | ||
| 251 | + length_ = 0; | ||
| 252 | + buf_ = nullptr; | ||
| 253 | + } | ||
| 207 | 254 | ||
| 255 | + MaybeStackBuffer() : length_(0), buf_(buf_st_) { | ||
| 256 | + // Default to a zero-length, null-terminated buffer. | ||
| 257 | + buf_[0] = T(); | ||
| 258 | + } | ||
| 259 | + | ||
| 260 | + ~MaybeStackBuffer() { | ||
| 261 | + if (buf_ != buf_st_) | ||
| 262 | + free(buf_); | ||
| 263 | + } | ||
| 208 | 264 | private: | |
| 209 | 265 | size_t length_; | |
| 210 | - char* str_; | ||
| 211 | - char str_st_[1024]; | ||
| 266 | + T* buf_; | ||
| 267 | + T buf_st_[kStackStorageSize]; | ||
| 268 | + }; | ||
| 269 | + | ||
| 270 | + class Utf8Value : public MaybeStackBuffer<char> { | ||
| 271 | + public: | ||
| 272 | + explicit Utf8Value(v8::Isolate* isolate, v8::Local<v8::Value> value); | ||
| 273 | + }; | ||
| 274 | + | ||
| 275 | + class TwoByteValue : public MaybeStackBuffer<uint16_t> { | ||
| 276 | + public: | ||
| 277 | + explicit TwoByteValue(v8::Isolate* isolate, v8::Local<v8::Value> value); | ||
| 278 | + }; | ||
| 279 | + | ||
| 280 | + class BufferValue : public MaybeStackBuffer<char> { | ||
| 281 | + public: | ||
| 282 | + explicit BufferValue(v8::Isolate* isolate, v8::Local<v8::Value> value); | ||
| 212 | 283 | }; | |
| 213 | 284 | ||
| 214 | 285 | } // namespace node | |
| Back | FazBrowse Home | New Git URL |
0 commit comments