Codebase list mozc / 7306a9d chrome / skk / skk_util.cc
7306a9d

Tree @7306a9d (Download .tar.gz)

skk_util.cc @7306a9draw · history · blame

// Copyright 2010-2012, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#include "chrome/skk/skk_util.h"

#include <algorithm>
#include <set>

#include "base/scoped_ptr.h"
#include "converter/node_allocator.h"
#include "dictionary/system/system_dictionary.h"
#include "third_party/jsoncpp/json.h"

namespace mozc {

namespace chrome {
namespace skk {

const size_t kMaxPredictions = 128;

// JSON message field names.
const char *kStatusDebug = "DEBUG";
const char *kStatusError = "ERROR";
const char *kStatusOK = "OK";

const char *kMethodLookup = "LOOKUP";

const char *kMessageBodyField = "body";
const char *kMessageIdField = "id";
const char *kMessageMethodField = "method";
const char *kMessageStatusField = "status";

const char *kMessageBaseField = "base";
const char *kMessageStemField = "stem";

const char *kMessageCandidatesField = "candidates";
const char *kMessagePredictionsField = "predictions";
const char *kMessageMessageField = "message";

}  // namespace skk
}  // namespace chrome

namespace {

bool NodeWcostLessThan(const mozc::Node *node1, const mozc::Node *node2) {
  return node1->wcost < node2->wcost;
}

}  // namespace

bool SkkUtil::IsSupportedMethod(const string &method) {
  return method == chrome::skk::kMethodLookup;
}

// Doesn't use unique() because candidates is not sorted in lexical order
void SkkUtil::RemoveDuplicateEntry(vector<string> *candidates) {
  set<string> seen_entries;
  for (vector<string>::iterator iter = candidates->begin();
       iter != candidates->end();
       /* empty */) {
    if (seen_entries.count(*iter) > 0) {
      iter = candidates->erase(iter);
    } else {
      seen_entries.insert(*iter);
      ++iter;
    }
  }
}

bool SkkUtil::ValidateMessage(const Json::Value &json_message,
                              string *error_message) {
  error_message->clear();

  if (!json_message.isObject()) {
    *error_message = "Message is not a object";
    return false;
  }

  if (json_message[chrome::skk::kMessageIdField].isNull()) {
    *error_message = "Required parameter \"id\" is unspecified";
    return false;
  }

  Json::Value method = json_message[chrome::skk::kMessageMethodField];
  if (!method.isString()
      || !IsSupportedMethod(method.asString())) {
    *error_message
        = "Required parameter \"method\" is unspecified or invalid";
    return false;
  }

  if (method.asString() == chrome::skk::kMethodLookup) {
    Json::Value base = json_message[chrome::skk::kMessageBaseField];
    if (!base.isString()) {
      *error_message
          = "Required parameter \"base\" is unspecified or invalid";
      return false;
    }

    Json::Value stem = json_message[chrome::skk::kMessageStemField];
    if (!stem.isString()) {
      *error_message
          = "Required parameter \"stem\" is unspecified or invalid";
      return false;
    }
  }

  // TODO(sekia): More strict check

  return true;
}

// This method keeps existing elements in |candidates| and |predictions|.
// Because when the word looking up for can be conjugated, this method will be
// called multiple times.
void SkkUtil::LookupEntry(mozc::SystemDictionary *dictionary,
                          const string &reading,
                          vector<string> *candidates,
                          vector<string> *predictions) {
  scoped_ptr<mozc::NodeAllocator> allocator(new mozc::NodeAllocator());
  mozc::Node *node = dictionary->LookupPredictive(
      reading.c_str(), reading.size(), allocator.get());
  vector<mozc::Node *> candidate_nodes;
  vector<mozc::Node *> prediction_nodes;
  for (; node != NULL; node = node->bnext) {
    if (node->key == reading) {
      candidate_nodes.push_back(node);
    } else {
      prediction_nodes.push_back(node);
    }
  }

  sort(candidate_nodes.begin(), candidate_nodes.end(), NodeWcostLessThan);
  for (vector<mozc::Node *>::const_iterator iter =
       candidate_nodes.begin();
       iter != candidate_nodes.end();
       ++iter) {
    candidates->push_back((*iter)->value);
  }
  sort(prediction_nodes.begin(), prediction_nodes.end(),
            NodeWcostLessThan);
  for (vector<mozc::Node *>::const_iterator iter =
       prediction_nodes.begin();
       iter != prediction_nodes.end() &&
       predictions->size() <= chrome::skk::kMaxPredictions;
       ++iter) {
    predictions->push_back((*iter)->value);
  }
}

}  // namespace mozc