• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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