Shaka Player Embedded
console.cc
Go to the documentation of this file.
1 // Copyright 2016 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // https://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,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "src/js/console.h"
16 
17 #include <algorithm> // std::min and std::sort
18 #include <cstdio>
19 #include <vector>
20 
21 #include "src/js/js_error.h"
22 
23 namespace shaka {
24 namespace js {
25 
26 namespace {
27 
28 // Limit the number of children we are willing to print. This will limit the
29 // number of elements printed from arrays and the number of members printed
30 // from objects.
31 constexpr const size_t kMaxChildren = 20;
32 
33 std::string ConvertToPrettyString(Handle<JsValue> value, bool allow_long);
34 
35 std::string to_string(Console::LogLevel level) {
36  switch (level) {
37  case Console::kError:
38  return "Error";
39  case Console::kWarn:
40  return "Warn";
41  case Console::kInfo:
42  return "Info";
43  case Console::kLog:
44  return "Log";
45  case Console::kDebug:
46  return "Debug";
47  }
48 }
49 
50 std::string ConvertStringToPrettyString(const std::string& string) {
51  std::string buffer;
52  buffer.push_back('"');
53  for (const char c : string) {
54  // Using https://en.wikipedia.org/wiki/Escape_sequences_in_C to determine
55  // characters need to be escaped.
56  switch (c) {
57  // Alert
58  case '\a':
59  buffer += R"(\a)";
60  break;
61  // Backspace
62  case '\b':
63  buffer += R"(\b)";
64  break;
65  // Newline
66  case '\n':
67  buffer += R"(\n)";
68  break;
69  // Carriage Return
70  case '\r':
71  buffer += R"(\r)";
72  break;
73  // Horizontal Tab
74  case '\t':
75  buffer += R"(\t)";
76  break;
77  // Backslash
78  case '\\':
79  buffer += R"(\\)";
80  break;
81  // Single Quotation Mark
82  case '\'':
83  buffer += R"(\')";
84  break;
85  // Double Quotation Mark
86  case '"':
87  buffer += R"(\")";
88  break;
89  // Question Mark
90  case '\?':
91  buffer += R"(\?)";
92  break;
93  default:
94  buffer.push_back(c);
95  break;
96  }
97  }
98  buffer.push_back('"');
99  return buffer;
100 }
101 
102 std::string ConvertArrayToLongPrettyString(Handle<JsValue> value) {
103  const LocalVar<JsObject> array = UnsafeJsCast<JsObject>(value);
104  const size_t array_length = ArrayLength(array);
105  const size_t min_length = std::min(kMaxChildren, array_length);
106 
107  // TODO: Use a string buffer to build strings to avoid having to create
108  // strings just to concatenate them.
109  std::string array_as_string = "[";
110 
111  for (size_t i = 0; i < min_length; i++) {
112  const LocalVar<JsValue> index_value = GetArrayIndexRaw(array, i);
113 
114  array_as_string += i ? ", " : "";
115  array_as_string += ConvertToPrettyString(index_value, false);
116  }
117 
118  // If there are more elements than we want to print, tell the user by
119  // appending a tail.
120  if (array_length > min_length) {
121  array_as_string += ", ...";
122  }
123 
124  array_as_string += "]";
125 
126  return array_as_string;
127 }
128 
129 std::string ConvertObjectToLongPrettyString(Handle<JsObject> object) {
130  // Get the member names in sorted order so that it will be easier to
131  // see which member are different between to objects when viewing the
132  // output.
133  std::vector<std::string> member_names = GetMemberNames(object);
134  std::sort(member_names.begin(), member_names.end());
135 
136  const size_t min_length = std::min(kMaxChildren, member_names.size());
137 
138  std::string object_as_string = "{";
139 
140  for (size_t i = 0; i < min_length; i++) {
141  const std::string& member_name = member_names[i];
142  const LocalVar<JsValue> member_value = GetMemberRaw(object, member_name);
143 
144  object_as_string += i ? ", " : "";
145  object_as_string += member_name;
146  object_as_string += ":";
147  object_as_string += ConvertToPrettyString(member_value, false);
148  }
149 
150  // If there are more members than we want to print, tell the user by
151  // appending a tail.
152  if (member_names.size() > min_length) {
153  object_as_string += ", ...";
154  }
155 
156  object_as_string += "}";
157  return object_as_string;
158 }
159 
160 std::string ConvertToPrettyString(Handle<JsValue> value, bool allow_long) {
161  const proto::ValueType type = GetValueType(value);
162 
163  switch (type) {
168  return ConvertToString(value);
169 
171  return "function() {...}";
172 
174  const std::string string = ConvertToString(value);
175  return ConvertStringToPrettyString(string);
176  }
178  return allow_long ? ConvertArrayToLongPrettyString(value) : "[...]";
179 
181  return "Symbol(" + ConvertToString(value) + ")";
183  return "Boolean(" + ConvertToString(value) + ")";
185  return "Number(" + ConvertToString(value) + ")";
187  return "String(" + ConvertStringToPrettyString(ConvertToString(value)) +
188  ")";
189 
190  default:
191  if (!IsObject(value))
192  return ConvertToString(value);
193 
194  LocalVar<JsObject> object = UnsafeJsCast<JsObject>(value);
195  if (IsBuiltInObject(object))
196  return ConvertToString(value);
197  return allow_long ? ConvertObjectToLongPrettyString(object) : "{...}";
198  }
199 }
200 
201 } // namespace
202 
204 // \cond Doxygen_Skip
205 Console::~Console() {}
206 // \endcond Doxygen_Skip
207 
208 void Console::Assert(Any cond, const CallbackArguments& arguments) const {
209  if (!cond.IsTruthy()) {
210  LogReal(kError, arguments, "Assertion failed: ", 1);
211  std::printf("%s\n", JsError::GetJsStack().c_str());
212  }
213 }
214 
215 void Console::Error(const CallbackArguments& arguments) const {
216  LogReal(kError, arguments);
217 }
218 
219 void Console::Warn(const CallbackArguments& arguments) const {
220  LogReal(kWarn, arguments);
221 }
222 
223 void Console::Info(const CallbackArguments& arguments) const {
224  LogReal(kInfo, arguments);
225 }
226 
227 void Console::Log(const CallbackArguments& arguments) const {
228  LogReal(kLog, arguments);
229 }
230 
231 void Console::Debug(const CallbackArguments& arguments) const {
232  LogReal(kDebug, arguments);
233 }
234 
235 std::string Console::ConvertToPrettyString(Handle<JsValue> value) {
236  return shaka::js::ConvertToPrettyString(value, true);
237 }
238 
239 void Console::LogReal(LogLevel level, const CallbackArguments& arguments,
240  const char* prefix, size_t skip_count) const {
241  // TODO: Consider using glog for logging.
242  std::printf("[%s]: ", to_string(level).c_str());
243  if (prefix)
244  std::printf("%s", prefix);
245  const size_t length = ArgumentCount(arguments);
246  for (size_t i = skip_count; i < length; ++i) {
247  if (i > skip_count)
248  std::printf("\t");
249  std::printf("%s", ConvertToPrettyString(arguments[i]).c_str());
250  }
251  std::printf("\n");
252 }
253 
255  AddMemberFunction("assert", &Console::Assert);
256  AddMemberFunction("error", &Console::Error);
257  AddMemberFunction("warn", &Console::Warn);
258  AddMemberFunction("info", &Console::Info);
259  AddMemberFunction("log", &Console::Log);
260  AddMemberFunction("debug", &Console::Debug);
261 }
262 
263 } // namespace js
264 } // namespace shaka
Definition: any.h:31
bool IsObject(Handle< JsValue > value)
Definition: js_wrappers.cc:315
std::vector< std::string > GetMemberNames(Handle< JsObject > object)
Definition: js_wrappers.cc:118
ReturnVal< JsValue > GetArrayIndexRaw(Handle< JsObject > object, size_t index, LocalVar< JsValue > *exception=nullptr)
Definition: js_wrappers.cc:142
size_t ArgumentCount(const CallbackArguments &arguments)
Definition: js_wrappers.h:209
void Info(const CallbackArguments &arguments) const
Definition: console.cc:223
static std::string GetJsStack()
Definition: js_error.cc:47
void Warn(const CallbackArguments &arguments) const
Definition: console.cc:219
bool IsTruthy() const
Definition: any.cc:32
std::string to_string(VideoReadyState state)
Definition: media_player.cc:32
ExceptionCode type
void Log(const CallbackArguments &arguments) const
Definition: console.cc:227
void Debug(const CallbackArguments &arguments) const
Definition: console.cc:231
proto::ValueType GetValueType(Handle< JsValue > value)
Definition: js_wrappers.cc:329
std::string ConvertToString(Handle< JsValue > value)
Definition: js_wrappers.cc:203
void Error(const CallbackArguments &arguments) const
Definition: console.cc:215
size_t ArrayLength(Handle< JsObject > value)
Definition: js_wrappers.h:418
static std::string ConvertToPrettyString(Handle< JsValue > value)
Definition: console.cc:235
void Assert(Any cond, const CallbackArguments &arguments) const
Definition: console.cc:208
ReturnVal< JsValue > GetMemberRaw(Handle< JsObject > object, const std::string &name, LocalVar< JsValue > *exception=nullptr)
Definition: js_wrappers.cc:136
bool IsBuiltInObject(Handle< JsObject > object)
Definition: js_wrappers.cc:319