// Copyright 2010 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "src/extensions/externalize-string-extension.h"

#include "src/api.h"
#include "src/handles.h"
#include "src/isolate.h"
#include "src/objects-inl.h"

namespace v8 {
namespace internal {

template <typename Char, typename Base>
class SimpleStringResource : public Base {
 public:
  // Takes ownership of |data|.
  SimpleStringResource(Char* data, size_t length)
      : data_(data),
        length_(length) {}

  virtual ~SimpleStringResource() { delete[] data_; }

  virtual const Char* data() const { return data_; }

  virtual size_t length() const { return length_; }

 private:
  Char* const data_;
  const size_t length_;
};


typedef SimpleStringResource<char, v8::String::ExternalOneByteStringResource>
    SimpleOneByteStringResource;
typedef SimpleStringResource<uc16, v8::String::ExternalStringResource>
    SimpleTwoByteStringResource;

const char* const ExternalizeStringExtension::kSource =
    "native function externalizeString();"
    "native function isOneByteString();"
    "function x() { return 1; }";

v8::Local<v8::FunctionTemplate>
ExternalizeStringExtension::GetNativeFunctionTemplate(
    v8::Isolate* isolate, v8::Local<v8::String> str) {
  if (strcmp(*v8::String::Utf8Value(isolate, str), "externalizeString") == 0) {
    return v8::FunctionTemplate::New(isolate,
                                     ExternalizeStringExtension::Externalize);
  } else {
    DCHECK_EQ(strcmp(*v8::String::Utf8Value(isolate, str), "isOneByteString"),
              0);
    return v8::FunctionTemplate::New(isolate,
                                     ExternalizeStringExtension::IsOneByte);
  }
}


void ExternalizeStringExtension::Externalize(
    const v8::FunctionCallbackInfo<v8::Value>& args) {
  if (args.Length() < 1 || !args[0]->IsString()) {
    args.GetIsolate()->ThrowException(
        v8::String::NewFromUtf8(
            args.GetIsolate(),
            "First parameter to externalizeString() must be a string.",
            NewStringType::kNormal).ToLocalChecked());
    return;
  }
  bool force_two_byte = false;
  if (args.Length() >= 2) {
    if (args[1]->IsBoolean()) {
      force_two_byte =
          args[1]
              ->BooleanValue(args.GetIsolate()->GetCurrentContext())
              .FromJust();
    } else {
      args.GetIsolate()->ThrowException(
          v8::String::NewFromUtf8(
              args.GetIsolate(),
              "Second parameter to externalizeString() must be a boolean.",
              NewStringType::kNormal).ToLocalChecked());
      return;
    }
  }
  bool result = false;
  Handle<String> string = Utils::OpenHandle(*args[0].As<v8::String>());
  if (string->IsExternalString()) {
    args.GetIsolate()->ThrowException(
        v8::String::NewFromUtf8(args.GetIsolate(),
                                "externalizeString() can't externalize twice.",
                                NewStringType::kNormal).ToLocalChecked());
    return;
  }
  if (string->IsOneByteRepresentation() && !force_two_byte) {
    uint8_t* data = new uint8_t[string->length()];
    String::WriteToFlat(*string, data, 0, string->length());
    SimpleOneByteStringResource* resource = new SimpleOneByteStringResource(
        reinterpret_cast<char*>(data), string->length());
    result = string->MakeExternal(resource);
    if (result) {
      i::Isolate* isolate = reinterpret_cast<i::Isolate*>(args.GetIsolate());
      isolate->heap()->RegisterExternalString(*string);
    }
    if (!result) delete resource;
  } else {
    uc16* data = new uc16[string->length()];
    String::WriteToFlat(*string, data, 0, string->length());
    SimpleTwoByteStringResource* resource = new SimpleTwoByteStringResource(
        data, string->length());
    result = string->MakeExternal(resource);
    if (result) {
      i::Isolate* isolate = reinterpret_cast<i::Isolate*>(args.GetIsolate());
      isolate->heap()->RegisterExternalString(*string);
    }
    if (!result) delete resource;
  }
  if (!result) {
    args.GetIsolate()->ThrowException(
        v8::String::NewFromUtf8(args.GetIsolate(),
                                "externalizeString() failed.",
                                NewStringType::kNormal).ToLocalChecked());
    return;
  }
}


void ExternalizeStringExtension::IsOneByte(
    const v8::FunctionCallbackInfo<v8::Value>& args) {
  if (args.Length() != 1 || !args[0]->IsString()) {
    args.GetIsolate()->ThrowException(
        v8::String::NewFromUtf8(
            args.GetIsolate(),
            "isOneByteString() requires a single string argument.",
            NewStringType::kNormal).ToLocalChecked());
    return;
  }
  bool is_one_byte =
      Utils::OpenHandle(*args[0].As<v8::String>())->IsOneByteRepresentation();
  args.GetReturnValue().Set(is_one_byte);
}

}  // namespace internal
}  // namespace v8
