1 /*
2 * Copyright (c) 2025 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 <cstdarg>
17 #include <cstdint>
18 #include <fstream>
19 #include <sstream>
20 #include <string>
21
22 #include "ani_text_utils.h"
23 #include "typography_style.h"
24
25 namespace OHOS::Text::ANI {
26 constexpr size_t FILE_HEAD_LENGTH = 7; // 7 is the size of "file://"
ThrowBusinessError(ani_env * env,TextErrorCode errorCode,const char * message)27 ani_status AniTextUtils::ThrowBusinessError(ani_env* env, TextErrorCode errorCode, const char* message)
28 {
29 ani_object aniError;
30 ani_status status = AniTextUtils::CreateBusinessError(env, static_cast<int32_t>(errorCode), message, aniError);
31 if (status != ANI_OK) {
32 TEXT_LOGE("Failed to create business, status:%{public}d", static_cast<int32_t>(status));
33 return status;
34 }
35 status = env->ThrowError(static_cast<ani_error>(aniError));
36 if (status != ANI_OK) {
37 TEXT_LOGE("Fail to throw err, status:%{public}d", static_cast<int32_t>(status));
38 return status;
39 }
40 return ANI_OK;
41 }
42
CreateBusinessError(ani_env * env,int32_t error,const char * message,ani_object & err)43 ani_status AniTextUtils::CreateBusinessError(ani_env* env, int32_t error, const char* message, ani_object& err)
44 {
45 ani_class aniClass;
46 ani_status status = env->FindClass("L@ohos/base/BusinessError;", &aniClass);
47 if (status != ANI_OK) {
48 TEXT_LOGE("Failed to find class, status:%{public}d", static_cast<int32_t>(status));
49 return status;
50 }
51 ani_method aniCtor;
52 status = env->Class_FindMethod(aniClass, "<ctor>", "Lstd/core/String;Lescompat/ErrorOptions;:V", &aniCtor);
53 if (status != ANI_OK) {
54 TEXT_LOGE("Failed to find ctor, status:%{public}d", static_cast<int32_t>(status));
55 return status;
56 }
57 ani_string aniMsg = AniTextUtils::CreateAniStringObj(env, message);
58 status = env->Object_New(aniClass, aniCtor, &err, aniMsg, AniTextUtils::CreateAniUndefined(env));
59 if (status != ANI_OK) {
60 TEXT_LOGE("Failed to new err, status:%{public}d", static_cast<int32_t>(status));
61 return status;
62 }
63 status = env->Object_SetPropertyByName_Double(err, "code", static_cast<ani_int>(error));
64 if (status != ANI_OK) {
65 TEXT_LOGE("Failed to set code, status:%{public}d", static_cast<int32_t>(status));
66 return status;
67 }
68 return ANI_OK;
69 }
70
CreateAniUndefined(ani_env * env)71 ani_object AniTextUtils::CreateAniUndefined(ani_env* env)
72 {
73 ani_ref aniRef;
74 env->GetUndefined(&aniRef);
75 return reinterpret_cast<ani_object>(aniRef);
76 }
77
CreateAniArray(ani_env * env,size_t size)78 ani_object AniTextUtils::CreateAniArray(ani_env* env, size_t size)
79 {
80 ani_class arrayCls;
81 if (env->FindClass(ANI_ARRAY, &arrayCls) != ANI_OK) {
82 TEXT_LOGE("Failed to findClass Lescompat/Array;");
83 return CreateAniUndefined(env);
84 }
85 ani_method arrayCtor;
86 if (env->Class_FindMethod(arrayCls, "<ctor>", "I:V", &arrayCtor) != ANI_OK) {
87 TEXT_LOGE("Failed to find <ctor>");
88 return CreateAniUndefined(env);
89 }
90 ani_object arrayObj = nullptr;
91 if (env->Object_New(arrayCls, arrayCtor, &arrayObj, size) != ANI_OK) {
92 TEXT_LOGE("Failed to create object Array");
93 return CreateAniUndefined(env);
94 }
95 return arrayObj;
96 }
97
CreateAniMap(ani_env * env)98 ani_object AniTextUtils::CreateAniMap(ani_env* env)
99 {
100 return AniTextUtils::CreateAniObject(env, ANI_MAP, ":V");
101 }
102
CreateAniEnum(ani_env * env,const char * enum_descriptor,ani_size index)103 ani_enum_item AniTextUtils::CreateAniEnum(ani_env* env, const char* enum_descriptor, ani_size index)
104 {
105 ani_enum enumType;
106 ani_status ret = env->FindEnum(enum_descriptor, &enumType);
107 if (ret != ANI_OK) {
108 TEXT_LOGE("Failed to find enum,%{public}s", enum_descriptor);
109 return nullptr;
110 }
111 ani_enum_item enumItem;
112 env->Enum_GetEnumItemByIndex(enumType, index, &enumItem);
113 return enumItem;
114 }
115
CreateAniDoubleObj(ani_env * env,double val)116 ani_object AniTextUtils::CreateAniDoubleObj(ani_env* env, double val)
117 {
118 return AniTextUtils::CreateAniObject(env, ANI_OBJECT, "D:V", val);
119 }
120
CreateAniIntObj(ani_env * env,int val)121 ani_object AniTextUtils::CreateAniIntObj(ani_env* env, int val)
122 {
123 return AniTextUtils::CreateAniObject(env, ANI_INT, "I:V", val);
124 }
125
CreateAniBooleanObj(ani_env * env,bool val)126 ani_object AniTextUtils::CreateAniBooleanObj(ani_env* env, bool val)
127 {
128 return AniTextUtils::CreateAniObject(env, ANI_BOOLEAN, "Z:V", val);
129 }
130
CreateAniStringObj(ani_env * env,const std::string & str)131 ani_string AniTextUtils::CreateAniStringObj(ani_env* env, const std::string& str)
132 {
133 ani_string result_string{};
134 env->String_NewUTF8(str.c_str(), str.size(), &result_string);
135 return result_string;
136 }
137
CreateAniStringObj(ani_env * env,const std::u16string & str)138 ani_string AniTextUtils::CreateAniStringObj(ani_env* env, const std::u16string& str)
139 {
140 ani_string result_string{};
141 env->String_NewUTF16(reinterpret_cast<const uint16_t*>(str.c_str()), str.size(), &result_string);
142 return result_string;
143 }
144
AniToStdStringUtf8(ani_env * env,const ani_string & str,std::string & utf8Str)145 ani_status AniTextUtils::AniToStdStringUtf8(ani_env* env, const ani_string& str, std::string& utf8Str)
146 {
147 ani_size strSize;
148 ani_status status = env->String_GetUTF8Size(str, &strSize);
149 if (status != ANI_OK) {
150 TEXT_LOGE("Failed to get utf8 str size");
151 return status;
152 }
153
154 strSize++;
155 std::vector<char> buffer(strSize);
156 char* utf8Buffer = buffer.data();
157
158 ani_size bytesWritten = 0;
159 status = env->String_GetUTF8(str, utf8Buffer, strSize, &bytesWritten);
160 if (status != ANI_OK) {
161 TEXT_LOGE("Failed to get utf8 str");
162 return status;
163 }
164
165 utf8Buffer[bytesWritten] = '\0';
166 utf8Str = std::string(utf8Buffer);
167 return ANI_OK;
168 }
169
AniToStdStringUtf16(ani_env * env,const ani_string & str,std::u16string & utf16Str)170 ani_status AniTextUtils::AniToStdStringUtf16(ani_env* env, const ani_string& str, std::u16string& utf16Str)
171 {
172 ani_size strSize;
173 ani_status status = env->String_GetUTF16Size(str, &strSize);
174 if (status != ANI_OK) {
175 TEXT_LOGE("Failed to get utf16 str size");
176 return status;
177 }
178
179 strSize++;
180 std::vector<uint16_t> buffer(strSize);
181 uint16_t* utf16Buffer = buffer.data();
182
183 ani_size bytesWritten = 0;
184 status = env->String_GetUTF16(str, utf16Buffer, strSize, &bytesWritten);
185 if (status != ANI_OK) {
186 TEXT_LOGE("Failed to get utf16 str");
187 return status;
188 }
189 utf16Buffer[bytesWritten] = '\0';
190 utf16Str = std::u16string(reinterpret_cast<const char16_t*>(utf16Buffer), strSize);
191 return ANI_OK;
192 }
193
ReadFile(const std::string & filePath,size_t & dataLen,std::unique_ptr<uint8_t[]> & data)194 bool AniTextUtils::ReadFile(const std::string& filePath, size_t& dataLen, std::unique_ptr<uint8_t[]>& data)
195 {
196 char realPath[PATH_MAX] = {0};
197 if (realpath(filePath.c_str(), realPath) == nullptr) {
198 TEXT_LOGE("Invalid filePath %{public}s", filePath.c_str());
199 return false;
200 }
201
202 std::ifstream file(realPath);
203 if (!file.is_open()) {
204 TEXT_LOGE("Failed to open file:%{public}s", filePath.c_str());
205 return false;
206 }
207 file.seekg(0, std::ios::end);
208 int length = file.tellg();
209 if (length == -1) {
210 TEXT_LOGE("Failed to get file length:%{public}s", filePath.c_str());
211 file.close();
212 return false;
213 }
214 dataLen = static_cast<size_t>(length);
215 data = std::make_unique<uint8_t[]>(dataLen);
216 file.seekg(0, std::ios::beg);
217 file.read(reinterpret_cast<char*>(data.get()), dataLen);
218 file.close();
219 return true;
220 }
221
SplitAbsoluteFontPath(std::string & absolutePath)222 bool AniTextUtils::SplitAbsoluteFontPath(std::string& absolutePath)
223 {
224 auto iter = absolutePath.find_first_of(':');
225 if (iter == std::string::npos) {
226 TEXT_LOGE("Failed to find separator in path:%{public}s", absolutePath.c_str());
227 return false;
228 }
229 std::string head = absolutePath.substr(0, iter);
230 if ((head == "file" && absolutePath.size() > FILE_HEAD_LENGTH)) {
231 absolutePath = absolutePath.substr(iter + 3); // 3 means skip "://"
232 // the file format is like "file://system/fonts...",
233 return true;
234 }
235
236 return false;
237 }
238
ReadOptionalField(ani_env * env,ani_object obj,const char * fieldName,ani_ref & ref)239 ani_status AniTextUtils::ReadOptionalField(ani_env* env, ani_object obj, const char* fieldName, ani_ref& ref)
240 {
241 ani_status ret = env->Object_GetPropertyByName_Ref(obj, fieldName, &ref);
242 if (ret != ANI_OK) {
243 TEXT_LOGE("Failed to get property %{public}s, ret %{public}d", fieldName, ret);
244 return ret;
245 }
246 ani_boolean isUndefined;
247 ret = env->Reference_IsUndefined(ref, &isUndefined);
248 if (ret != ANI_OK) {
249 TEXT_LOGE("Failed to check ref is undefined, ret %{public}d", ret);
250 ref = nullptr;
251 return ret;
252 }
253
254 if (isUndefined) {
255 ref = nullptr;
256 }
257 return ret;
258 }
259
ReadOptionalDoubleField(ani_env * env,ani_object obj,const char * fieldName,double & value)260 ani_status AniTextUtils::ReadOptionalDoubleField(ani_env* env, ani_object obj, const char* fieldName, double& value)
261 {
262 ani_ref ref = nullptr;
263 ani_status result = AniTextUtils::ReadOptionalField(env, obj, fieldName, ref);
264 if (result == ANI_OK && ref != nullptr) {
265 env->Object_CallMethodByName_Double(reinterpret_cast<ani_object>(ref), "unboxed", ":D", &value);
266 }
267 return result;
268 }
269
ReadOptionalStringField(ani_env * env,ani_object obj,const char * fieldName,std::string & str)270 ani_status AniTextUtils::ReadOptionalStringField(ani_env* env, ani_object obj, const char* fieldName, std::string& str)
271 {
272 ani_ref ref = nullptr;
273 ani_status result = AniTextUtils::ReadOptionalField(env, obj, fieldName, ref);
274 if (result == ANI_OK && ref != nullptr) {
275 std::string familyName;
276 ani_status ret = AniTextUtils::AniToStdStringUtf8(env, reinterpret_cast<ani_string>(ref), str);
277 if (ret != ANI_OK) {
278 return result;
279 }
280 }
281 return result;
282 }
283
ReadOptionalU16StringField(ani_env * env,ani_object obj,const char * fieldName,std::u16string & str)284 ani_status AniTextUtils::ReadOptionalU16StringField(
285 ani_env* env, ani_object obj, const char* fieldName, std::u16string& str)
286 {
287 ani_ref ref = nullptr;
288 ani_status result = AniTextUtils::ReadOptionalField(env, obj, fieldName, ref);
289 if (result == ANI_OK && ref != nullptr) {
290 result = AniTextUtils::AniToStdStringUtf16(env, reinterpret_cast<ani_string>(ref), str);
291 }
292 return result;
293 }
294
ReadOptionalBoolField(ani_env * env,ani_object obj,const char * fieldName,bool & value)295 ani_status AniTextUtils::ReadOptionalBoolField(ani_env* env, ani_object obj, const char* fieldName, bool& value)
296 {
297 ani_ref ref = nullptr;
298 ani_status result = AniTextUtils::ReadOptionalField(env, obj, fieldName, ref);
299 if (result == ANI_OK && ref != nullptr) {
300 ani_boolean aniBool;
301 result = env->Object_CallMethodByName_Boolean(reinterpret_cast<ani_object>(ref), "isTrue", ":Z", &aniBool);
302 if (result == ANI_OK) {
303 value = static_cast<bool>(aniBool);
304 }
305 }
306 return result;
307 }
308 } // namespace OHOS::Text::ANI