1 /*
2  * Copyright (c) 2022 Huawei Device Co., Ltd.
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  *     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,
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 
16 #include "hilog_module.h"
17 #include "hilog_wrapper.h"
18 #include "securec.h"
19 
20 namespace OHOS {
21 namespace ACELite {
22 namespace {
23 #define DEFAULT_LOG_TYPE LOG_TYPE_MIN
24 // log content prefix:"%c %05X/%s: " %05X->domain %s->tag
25 static const int32_t DOMAIN_LEN = 5;
26 static const int32_t FIX_LEN = 5;
27 static const int32_t MIN_DOMAIN = 0x0;
28 static const int32_t MAX_DOMAIN = 0xFFFF;
29 static const int32_t MAX_TAG = 32;
30 static const int32_t MAX_FORMAT = 1024;
31 static const int32_t MIN_NUMBER = 3;
32 static const int32_t MAX_NUMBER = 16;
33 static const int32_t PUBLIC_LEN = 6;
34 static const int32_t PRIVATE_LEN = 7;
35 static const int32_t PROPERTY_POS = 2;
36 static const char PRIV_STR[10] = "<private>";
37 static const int32_t FIRST = 0;
38 static const int32_t SECOND = 1;
39 static const int32_t THIRD = 2;
40 static const int32_t FOURTH = 3;
41 static const int32_t FIFTH = 4;
42 }
43 
ParseLogContent(const HilogString * formatStr,const HilogVector * params,HilogString * logContent)44 void HilogModule::ParseLogContent(const HilogString *formatStr, const HilogVector *params, HilogString *logContent)
45 {
46     if (formatStr == nullptr || params == nullptr || logContent == nullptr) {
47         return;
48     }
49     size_t size = HilogVector::Size(params);
50     if (size == 0) {
51         HilogString::Puts(HilogString::Get(formatStr), logContent);
52         return;
53     }
54     char *format = HilogString::Get(formatStr);
55     size_t len = HilogString::Length(formatStr);
56     size_t pos = 0;
57     size_t count = 0;
58 
59     for (; pos < len; ++pos) {
60         bool showPriv = true;
61         if (count > size) {
62             break;
63         }
64         if (format[pos] != '%') {
65             HilogString::Putc(format[pos], logContent);
66             continue;
67         }
68 
69         if (((pos + PUBLIC_LEN + PROPERTY_POS) < len) &&
70             (strncmp(format + pos + PROPERTY_POS, "public", PUBLIC_LEN) == 0)) {
71             pos += (PUBLIC_LEN + PROPERTY_POS);
72             showPriv = false;
73         } else if (((pos + PRIVATE_LEN + PROPERTY_POS) < len) &&
74             (strncmp(format + pos + PROPERTY_POS, "private", PRIVATE_LEN) == 0)) {
75             pos += (PRIVATE_LEN + PROPERTY_POS);
76         }
77 
78         if (pos + 1 >= len) {
79             break;
80         }
81         AddLogContentOutParams outParams = {
82             .pos = &pos,
83             .count = &count,
84             .logContent = logContent,
85         };
86         AddLogContent(format, params, showPriv, &outParams);
87     }
88     if (pos < len) {
89         HilogString::Puts(format + pos, logContent, len - pos);
90     }
91     return;
92 }
93 
AddLogContent(const char * format,const HilogVector * params,bool showPriv,const AddLogContentOutParams * outParams)94 void HilogModule::AddLogContent(const char *format, const HilogVector *params, bool showPriv,
95     const AddLogContentOutParams *outParams)
96 {
97     if (format == nullptr || outParams == nullptr || params == nullptr || outParams->pos == nullptr ||
98         outParams->count == nullptr || outParams->logContent == nullptr) {
99         return;
100     }
101     if ((*(outParams->pos) + 1) >= strlen(format)) {
102         return;
103     }
104 
105     switch (format[*(outParams->pos) + 1]) {
106         case 'i':
107         case 'd':
108             if (HilogVector::GetType(params, *(outParams->count)) == INT_TYPE) {
109                 HilogString::Puts(
110                     showPriv ? PRIV_STR : HilogVector::GetStr(params, *(outParams->count)), outParams->logContent);
111             }
112             (*(outParams->count))++;
113             ++(*(outParams->pos));
114             break;
115         case 's':
116             if (HilogVector::GetType(params, *(outParams->count)) == STRING_TYPE) {
117                 HilogString::Puts(
118                     showPriv ? PRIV_STR : HilogVector::GetStr(params, *(outParams->count)), outParams->logContent);
119             }
120             (*(outParams->count))++;
121             ++(*(outParams->pos));
122             break;
123         case 'O':
124         case 'o':
125             if (HilogVector::GetType(params, *(outParams->count)) == OBJECT_TYPE) {
126                 HilogString::Puts(
127                     showPriv ? PRIV_STR : HilogVector::GetStr(params, *(outParams->count)), outParams->logContent);
128             }
129             (*(outParams->count))++;
130             ++(*(outParams->pos));
131             break;
132         case '%':
133             HilogString::Putc(format[*(outParams->pos)], outParams->logContent);
134             ++(*(outParams->pos));
135             break;
136         default:
137             HilogString::Putc(format[*(outParams->pos)], outParams->logContent);
138             break;
139     }
140 }
141 
Debug(const JSIValue thisVal,const JSIValue * args,uint8_t argsNum)142 JSIValue HilogModule::Debug(const JSIValue thisVal, const JSIValue *args, uint8_t argsNum)
143 {
144     return HilogModule::HilogImpl(thisVal, args, argsNum, LogLevel::LOG_DEBUG);
145 }
146 
Info(const JSIValue thisVal,const JSIValue * args,uint8_t argsNum)147 JSIValue HilogModule::Info(const JSIValue thisVal, const JSIValue *args, uint8_t argsNum)
148 {
149     return HilogModule::HilogImpl(thisVal, args, argsNum, LogLevel::LOG_INFO);
150 }
151 
Error(const JSIValue thisVal,const JSIValue * args,uint8_t argsNum)152 JSIValue HilogModule::Error(const JSIValue thisVal, const JSIValue *args, uint8_t argsNum)
153 {
154     return HilogModule::HilogImpl(thisVal, args, argsNum, LogLevel::LOG_ERROR);
155 }
156 
Warn(const JSIValue thisVal,const JSIValue * args,uint8_t argsNum)157 JSIValue HilogModule::Warn(const JSIValue thisVal, const JSIValue *args, uint8_t argsNum)
158 {
159     return HilogModule::HilogImpl(thisVal, args, argsNum, LogLevel::LOG_WARN);
160 }
161 
Fatal(const JSIValue thisVal,const JSIValue * args,uint8_t argsNum)162 JSIValue HilogModule::Fatal(const JSIValue thisVal, const JSIValue *args, uint8_t argsNum)
163 {
164     return HilogModule::HilogImpl(thisVal, args, argsNum, LogLevel::LOG_FATAL);
165 }
166 
HiLogIsLoggable(int32_t domain,const char * tag,LogLevel level)167 bool HiLogIsLoggable(int32_t domain, const char *tag, LogLevel level)
168 {
169     if ((level < LOG_DEBUG) || (level > LOG_FATAL) || tag == nullptr ||
170         domain > MAX_DOMAIN || domain < MIN_DOMAIN) {
171         return false;
172     }
173     return true;
174 }
175 
IsLoggable(const JSIValue thisVal,const JSIValue * args,uint8_t argsNum)176 JSIValue HilogModule::IsLoggable(const JSIValue thisVal, const JSIValue *args, uint8_t argsNum)
177 {
178     if ((args == nullptr) || (argsNum < MIN_NUMBER) || JSI::ValueIsUndefined(args[FIRST]) ||
179          JSI::ValueIsUndefined(args[SECOND]) || JSI::ValueIsUndefined(args[THIRD])) {
180         HILOG_HILOGE("IsLoggable: args is invalid.");
181         return JSI::CreateBoolean(false);
182     }
183     if (JSI::ValueIsNull(args[FIRST]) || JSI::ValueIsNull(args[SECOND]) ||
184         JSI::ValueIsNull(args[THIRD])) {
185         HILOG_HILOGE("IsLoggable: args type is null.");
186         return JSI::CreateBoolean(false);
187     }
188     if (!JSI::ValueIsNumber(args[FIRST]) || !JSI::ValueIsString(args[SECOND]) ||
189         !JSI::ValueIsNumber(args[THIRD])) {
190         HILOG_HILOGE("IsLoggable: args type is invalid.");
191         return JSI::CreateBoolean(false);
192     }
193 
194     int32_t domain = static_cast<int32_t>(JSI::ValueToNumber(args[FIRST]));
195     if (domain > MAX_DOMAIN || domain < MIN_DOMAIN) {
196         HILOG_HILOGE("IsLoggable: domain is invalid.");
197         return JSI::CreateBoolean(false);
198     }
199     char *tag = JSI::ValueToString(args[SECOND]);
200     if (tag == nullptr || strlen(tag) > MAX_TAG) {
201         HILOG_HILOGE("IsLoggable: tag is null or tag > %{public}d.", MAX_TAG);
202         return JSI::CreateBoolean(false);
203     }
204     int32_t level = static_cast<int32_t>(JSI::ValueToNumber(args[THIRD]));
205     if (level > LOG_FATAL || level < LOG_DEBUG) {
206         HILOG_HILOGE("IsLoggable:level is error.");
207         JSI::ReleaseString(tag);
208         return JSI::CreateBoolean(false);
209     }
210     bool res = HiLogIsLoggable(domain, tag, static_cast<LogLevel>(level));
211     JSI::ReleaseString(tag);
212     return JSI::CreateBoolean(res);
213 }
214 
ParseNapiValue(const JSIValue thisVal,const JSIValue * element,HilogVector * params)215 void HilogModule::ParseNapiValue(const JSIValue thisVal, const JSIValue *element,  HilogVector *params)
216 {
217     if (element == nullptr || params == nullptr) {
218         HILOG_HILOGE("ParseNapiValue: element or params is nullptr.");
219         return;
220     }
221     if (JSI::ValueIsNumber(element[0])) {
222         char *value = JSI::JSIValueToString(element[0]);
223         HilogVector::Push(params, value, INT_TYPE);
224         JSI::ReleaseString(value);
225     } else if (JSI::ValueIsString(element[0])) {
226         char *value = JSI::ValueToString(element[0]);
227         HilogVector::Push(params, value, STRING_TYPE);
228         JSI::ReleaseString(value);
229     } else if (JSI::ValueIsObject(element[0])) {
230         char *value = JSI::JSIValueToString(element[0]);
231         HilogVector::Push(params, value, OBJECT_TYPE);
232         JSI::ReleaseString(value);
233     } else {
234         HILOG_HILOGE("ParseNapiValue: type mismatch.");
235     }
236     return;
237 }
238 
HilogImpl(const JSIValue thisVal,const JSIValue * args,uint8_t argsNum,int level)239 JSIValue HilogModule::HilogImpl(const JSIValue thisVal, const JSIValue *args, uint8_t argsNum, int level)
240 {
241     JSIValue undefValue = JSI::CreateUndefined();
242     if ((args == nullptr) || (argsNum < MIN_NUMBER) || (argsNum > MAX_NUMBER) ||
243         JSI::ValueIsUndefined(args[FIRST]) || JSI::ValueIsUndefined(args[SECOND]) ||
244         JSI::ValueIsUndefined(args[THIRD]) || JSI::ValueIsNull(args[FIRST]) ||
245         JSI::ValueIsNull(args[SECOND]) || JSI::ValueIsNull(args[THIRD])) {
246         HILOG_HILOGE("HilogImpl: args is invalid.");
247         return undefValue;
248     }
249 
250     int32_t domain = static_cast<int32_t>(JSI::ValueToNumber(args[FIRST]));
251     if (domain > MAX_DOMAIN || domain < MIN_DOMAIN) {
252         HILOG_HILOGE("HilogImpl: domain is invalid.");
253         return undefValue;
254     }
255     char *tag = JSI::ValueToString(args[SECOND]);
256     if (tag == nullptr || strlen(tag) > MAX_TAG) {
257         HILOG_HILOGE("HilogImpl: tag is null or tag > %{public}d.", MAX_TAG);
258         return undefValue;
259     }
260     char *fmtString = JSI::ValueToString(args[THIRD]);
261     if (fmtString == nullptr || strlen(fmtString) > MAX_FORMAT) {
262         HILOG_HILOGE("HilogImpl: fmtString is null or fmtString > %{public}d.", MAX_FORMAT);
263         JSI::ReleaseString(tag);
264         return undefValue;
265     }
266 
267     HilogVector params;
268     bool result = HilogImplParseValue(thisVal, args, argsNum, &params);
269     if (!result) {
270         JSI::ReleaseString(fmtString);
271         JSI::ReleaseString(tag);
272         return undefValue;
273     }
274     HilogString fmtStringBuffer;
275     HilogString logContent;
276     HilogString::Puts(fmtString, &fmtStringBuffer);
277     ParseLogContent(&fmtStringBuffer, &params, &logContent);
278     if ((HilogString::Length(&logContent) + DOMAIN_LEN + FIX_LEN) + strlen(tag) > (MAX_FORMAT - 1)) {
279         HILOG_HILOGE("HilogImpl: log length > %{public}d.", MAX_FORMAT - DOMAIN_LEN - FIX_LEN - strlen(tag) - 1);
280         JSI::ReleaseString(fmtString);
281         JSI::ReleaseString(tag);
282         return undefValue;
283     }
284     HiLogPrint(DEFAULT_LOG_TYPE, static_cast<LogLevel>(level), domain, tag, HilogString::Get(&logContent), "");
285     JSI::ReleaseString(fmtString);
286     JSI::ReleaseString(tag);
287     return undefValue;
288 }
289 
HilogImplParseValue(const JSIValue thisVal,const JSIValue * args,uint8_t argsNum,HilogVector * params)290 bool HilogModule::HilogImplParseValue(
291     const JSIValue thisVal, const JSIValue *args, uint8_t argsNum, HilogVector *params)
292 {
293     if (params == nullptr || args == nullptr) {
294         return false;
295     }
296     if (argsNum > MIN_NUMBER && !JSI::ValueIsUndefined(args[FOURTH]) && !JSI::ValueIsNull(args[FOURTH])) {
297         if (!JSI::ValueIsArray(args[FOURTH])) {
298             for (size_t i = MIN_NUMBER; i < argsNum; i++) {
299                 ParseNapiValue(thisVal, &args[i], params);
300             }
301         } else {
302             if (argsNum != MIN_NUMBER + 1) {
303                 HILOG_HILOGE("HilogImplParseValue: args mismatch.");
304                 return false;
305             }
306             for (uint32_t i = 0; i < JSI::GetArrayLength(args[FOURTH]); i++) {
307                 JSIValue element = JSI::GetPropertyByIndex(args[FOURTH], i);
308                 ParseNapiValue(thisVal, &element, params);
309             }
310         }
311     }
312     return true;
313 }
314 
InitLogLevelType(JSIValue target)315 void InitLogLevelType(JSIValue target)
316 {
317     JSIValue logLevel = JSI::CreateObject();
318     JSI::SetNumberProperty(logLevel, "DEBUG", LogLevel::LOG_DEBUG);
319     JSI::SetNumberProperty(logLevel, "INFO", LogLevel::LOG_INFO);
320     JSI::SetNumberProperty(logLevel, "WARN", LogLevel::LOG_WARN);
321     JSI::SetNumberProperty(logLevel, "ERROR", LogLevel::LOG_ERROR);
322     JSI::SetNumberProperty(logLevel, "FATAL", LogLevel::LOG_FATAL);
323     JSI::SetNamedProperty(target, "LogLevel", logLevel);
324 }
325 
InitHilogModule(JSIValue exports)326 void InitHilogModule(JSIValue exports)
327 {
328     HILOG_HILOGI("InitHilogModule start");
329 
330     InitLogLevelType(exports);
331     JSI::SetModuleAPI(exports, "debug", HilogModule::Debug);
332     JSI::SetModuleAPI(exports, "info", HilogModule::Info);
333     JSI::SetModuleAPI(exports, "error", HilogModule::Error);
334     JSI::SetModuleAPI(exports, "warn", HilogModule::Warn);
335     JSI::SetModuleAPI(exports, "fatal", HilogModule::Fatal);
336     JSI::SetModuleAPI(exports, "isLoggable", HilogModule::IsLoggable);
337 
338     HILOG_HILOGI("InitHilogModule end");
339 }
340 } // ACELite
341 } // OHOS