Add device_type to SharedPageState as a prelude to removing user_agent_type from...
[chromium-blink-merge.git] / third_party / liblouis / nacl_wrapper / liblouis_instance.cc
blob7346a0f3daa89c7f8f98aaf0fcc6bf52d9ee2311
1 // Copyright 2013 Google Inc.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
13 // the License.
15 #include "liblouis_instance.h"
17 #include <cstdio>
18 #include <cstring>
19 #include <sys/mount.h>
20 #include <vector>
22 #include "nacl_io/nacl_io.h"
23 #include "ppapi/c/pp_errors.h"
24 #include "ppapi/cpp/module.h"
26 #include "translation_result.h"
28 namespace {
30 static const char kHexadecimalChars[] = "0123456789abcdef";
32 // Converts a vector of bytes into a (lowercase) hexadecimal string.
33 static void BytesToHexString(const std::vector<unsigned char>& bytes,
34 std::string* out) {
35 std::string hex;
36 hex.reserve(bytes.size() * 2);
37 for (size_t i = 0; i < bytes.size(); ++i) {
38 unsigned char byte = bytes[i];
39 hex.push_back(kHexadecimalChars[byte >> 4]);
40 hex.push_back(kHexadecimalChars[byte & 0x0f]);
42 out->swap(hex);
45 // Converts a hexadecimal string to a vector of bytes.
46 // Returns false on failure.
47 static bool HexStringToBytes(const std::string& hex,
48 std::vector<unsigned char>* out) {
49 if (hex.size() % 2 != 0) {
50 return false;
53 std::vector<unsigned char> bytes;
54 bytes.reserve(hex.size() / 2);
55 for (size_t i = 0; i < hex.size(); i += 2) {
56 unsigned char byte;
57 char ch = hex[i];
58 if ('0' <= ch && ch <= '9') {
59 byte = (ch - '0') << 4;
60 } else if ('a' <= ch && ch <= 'f') {
61 byte = (ch - 'a' + 10) << 4;
62 } else if ('A' <= ch && ch <= 'F') {
63 byte = (ch - 'A' + 10) << 4;
64 } else {
65 return false;
67 ch = hex[i+1];
68 if ('0' <= ch && ch <= '9') {
69 byte |= ch - '0';
70 } else if ('a' <= ch && ch <= 'f') {
71 byte |= ch - 'a' + 10;
72 } else if ('A' <= ch && ch <= 'F') {
73 byte |= ch - 'A' + 10;
74 } else {
75 return false;
77 bytes.push_back(byte);
79 out->swap(bytes);
80 return true;
83 template <typename T>
84 static void CopyVectorToJson(const std::vector<T>& vec, Json::Value* out) {
85 Json::Value result(Json::arrayValue);
86 result.resize(vec.size());
87 for (size_t i = 0; i < vec.size(); ++i) {
88 result[i] = vec[i];
90 out->swap(result);
93 } // namespace
96 namespace liblouis_nacl {
98 // Well-known strings used for configuration.
99 static const char kTablesDirKey[] = "tablesdir";
100 static const char kTablesDirDefault[] = "tables";
102 // Well-known strings used in JSON messages.
103 static const char kCommandKey[] = "command";
104 static const char kMessageIdKey[] = "message_id";
105 static const char kInReplyToKey[] = "in_reply_to";
106 static const char kErrorKey[] = "error";
107 static const char kTableNamesKey[] = "table_names";
108 static const char kSuccessKey[] = "success";
109 static const char kTextKey[] = "text";
110 static const char kCellsKey[] = "cells";
111 static const char kCursorPositionKey[] = "cursor_position";
112 static const char kTextToBrailleKey[] = "text_to_braille";
113 static const char kBrailleToTextKey[] = "braille_to_text";
114 static const char kCheckTableCommand[] = "CheckTable";
115 static const char kTranslateCommand[] = "Translate";
116 static const char kBackTranslateCommand[] = "BackTranslate";
118 LibLouisInstance::LibLouisInstance(PP_Instance instance)
119 : pp::Instance(instance), liblouis_thread_(this), cc_factory_(this) {}
121 LibLouisInstance::~LibLouisInstance() {}
123 bool LibLouisInstance::Init(uint32_t argc, const char* argn[],
124 const char* argv[]) {
125 const char* tables_dir = kTablesDirDefault;
126 for (size_t i = 0; i < argc; ++i) {
127 if (strcmp(argn[i], kTablesDirKey) == 0) {
128 tables_dir = argv[i];
132 nacl_io_init_ppapi(pp_instance(),
133 pp::Module::Get()->get_browser_interface());
134 if (mount(tables_dir, liblouis_.tables_dir(), "httpfs", 0, "") != 0) {
135 // TODO(jbroman): report this error.
136 return false;
139 return liblouis_thread_.Start();
142 void LibLouisInstance::HandleMessage(const pp::Var& var_message) {
143 if (!var_message.is_string()) {
144 PostError("expected message to be a JSON string");
145 return;
148 Json::Value message;
149 Json::Reader reader;
150 bool parsed = reader.parse(var_message.AsString(),
151 message, false /* collectComments */);
152 if (!parsed) {
153 PostError("expected message to be a JSON string");
154 return;
157 Json::Value message_id = message[kMessageIdKey];
158 if (!message_id.isString()) {
159 PostError("expected message_id string");
160 return;
162 std::string message_id_str = message_id.asString();
164 Json::Value command = message[kCommandKey];
165 if (!command.isString()) {
166 PostError("expected command string", message_id_str);
167 return;
170 std::string command_str = command.asString();
171 if (command_str == kCheckTableCommand) {
172 HandleCheckTable(message, message_id_str);
173 } else if (command_str == kTranslateCommand) {
174 HandleTranslate(message, message_id_str);
175 } else if (command_str == kBackTranslateCommand) {
176 HandleBackTranslate(message, message_id_str);
177 } else {
178 PostError("unknown command", message_id_str);
182 void LibLouisInstance::PostReply(Json::Value reply,
183 const std::string& in_reply_to) {
184 Json::FastWriter writer;
185 reply[kInReplyToKey] = in_reply_to;
186 pp::Var var_reply(writer.write(reply));
187 PostMessage(var_reply);
190 void LibLouisInstance::PostError(const std::string& error_message) {
191 Json::FastWriter writer;
192 Json::Value reply(Json::objectValue);
193 reply[kErrorKey] = error_message;
194 pp::Var var_reply(writer.write(reply));
195 PostMessage(var_reply);
198 void LibLouisInstance::PostError(const std::string& error_message,
199 const std::string& in_reply_to) {
200 Json::FastWriter writer;
201 Json::Value reply(Json::objectValue);
202 reply[kErrorKey] = error_message;
203 reply[kInReplyToKey] = in_reply_to;
204 reply[kSuccessKey] = false;
205 pp::Var var_reply(writer.write(reply));
206 PostMessage(var_reply);
209 void LibLouisInstance::HandleCheckTable(const Json::Value& message,
210 const std::string& message_id) {
211 Json::Value table_names = message[kTableNamesKey];
212 if (!table_names.isString()) {
213 PostError("expected table_names to be a string", message_id);
214 return;
216 PostWorkToBackground(cc_factory_.NewCallback(
217 &LibLouisInstance::CheckTableInBackground,
218 table_names.asString(), message_id));
221 void LibLouisInstance::CheckTableInBackground(int32_t result,
222 const std::string& table_names, const std::string& message_id) {
223 if (result != PP_OK) {
224 PostError("failed to transfer call to background thread", message_id);
225 return;
227 bool success = liblouis_.CheckTable(table_names);
228 Json::Value reply(Json::objectValue);
229 reply[kSuccessKey] = success;
230 PostReply(reply, message_id);
233 void LibLouisInstance::HandleTranslate(const Json::Value& message,
234 const std::string& message_id) {
235 Json::Value table_names = message[kTableNamesKey];
236 Json::Value text = message[kTextKey];
237 Json::Value cursor_position = message[kCursorPositionKey];
238 if (!table_names.isString()) {
239 PostError("expected table_names to be a string", message_id);
240 return;
241 } else if (!text.isString()) {
242 PostError("expected text to be a string", message_id);
243 return;
244 } else if (!cursor_position.isNull() && !cursor_position.isIntegral()) {
245 PostError("expected cursor_position to be null or integral", message_id);
246 return;
248 TranslationParams params;
249 params.table_names = table_names.asString();
250 params.text = text.asString();
251 params.cursor_position = cursor_position.isIntegral() ?
252 cursor_position.asInt() : -1;
253 PostWorkToBackground(cc_factory_.NewCallback(
254 &LibLouisInstance::TranslateInBackground,
255 params, message_id));
258 void LibLouisInstance::TranslateInBackground(int32_t result,
259 const TranslationParams& params, const std::string& message_id) {
260 if (result != PP_OK) {
261 PostError("failed to transfer call to background thread", message_id);
262 return;
264 TranslationResult translation_result;
265 bool success = liblouis_.Translate(params, &translation_result);
266 Json::Value reply(Json::objectValue);
267 reply[kSuccessKey] = success;
268 if (success) {
269 std::string hex_cells;
270 Json::Value text_to_braille;
271 Json::Value braille_to_text;
272 BytesToHexString(translation_result.cells, &hex_cells);
273 CopyVectorToJson(translation_result.text_to_braille, &text_to_braille);
274 CopyVectorToJson(translation_result.braille_to_text, &braille_to_text);
275 reply[kCellsKey] = hex_cells;
276 reply[kTextToBrailleKey] = text_to_braille;
277 reply[kBrailleToTextKey] = braille_to_text;
278 if (translation_result.cursor_position >= 0) {
279 reply[kCursorPositionKey] = translation_result.cursor_position;
282 PostReply(reply, message_id);
285 void LibLouisInstance::HandleBackTranslate(const Json::Value& message,
286 const std::string& message_id) {
287 Json::Value table_names = message[kTableNamesKey];
288 Json::Value cells = message[kCellsKey];
289 if (!table_names.isString()) {
290 PostError("expected table_names to be a string", message_id);
291 return;
292 } else if (!cells.isString()) {
293 PostError("expected cells to be a string", message_id);
294 return;
296 std::vector<unsigned char> cells_vector;
297 if (!HexStringToBytes(cells.asString(), &cells_vector)) {
298 PostError("expected cells to be a valid hexadecimal string", message_id);
299 return;
301 PostWorkToBackground(cc_factory_.NewCallback(
302 &LibLouisInstance::BackTranslateInBackground,
303 table_names.asString(), cells_vector, message_id));
306 void LibLouisInstance::BackTranslateInBackground(int32_t result,
307 const std::string& table_names, const std::vector<unsigned char>& cells,
308 const std::string& message_id) {
309 if (result != PP_OK) {
310 PostError("failed to transfer call to background thread", message_id);
311 return;
313 std::string text;
314 bool success = liblouis_.BackTranslate(table_names, cells, &text);
315 Json::Value reply(Json::objectValue);
316 reply[kSuccessKey] = success;
317 if (success) {
318 reply[kTextKey] = text;
320 PostReply(reply, message_id);
323 } // namespace liblouis_nacl