1bc2ed2b3Sopenharmony_ci/*
2bc2ed2b3Sopenharmony_ci * Copyright (C) 2022 Huawei Device Co., Ltd.
3bc2ed2b3Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
4bc2ed2b3Sopenharmony_ci * you may not use this file except in compliance with the License.
5bc2ed2b3Sopenharmony_ci * You may obtain a copy of the License at
6bc2ed2b3Sopenharmony_ci *
7bc2ed2b3Sopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
8bc2ed2b3Sopenharmony_ci *
9bc2ed2b3Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
10bc2ed2b3Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
11bc2ed2b3Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12bc2ed2b3Sopenharmony_ci * See the License for the specific language governing permissions and
13bc2ed2b3Sopenharmony_ci * limitations under the License.
14bc2ed2b3Sopenharmony_ci */
15bc2ed2b3Sopenharmony_ci#include "ndef_message.h"
16bc2ed2b3Sopenharmony_ci#include "loghelper.h"
17bc2ed2b3Sopenharmony_ci#include "nfc_sdk_common.h"
18bc2ed2b3Sopenharmony_ci
19bc2ed2b3Sopenharmony_cinamespace OHOS {
20bc2ed2b3Sopenharmony_cinamespace NFC {
21bc2ed2b3Sopenharmony_cinamespace KITS {
22bc2ed2b3Sopenharmony_ciusing KITS::NfcSdkCommon;
23bc2ed2b3Sopenharmony_ciNdefMessage::NdefMessage(std::vector<std::shared_ptr<NdefRecord>> ndefRecords)
24bc2ed2b3Sopenharmony_ci    : ndefRecordList_(std::move(ndefRecords))
25bc2ed2b3Sopenharmony_ci{
26bc2ed2b3Sopenharmony_ci}
27bc2ed2b3Sopenharmony_ci
28bc2ed2b3Sopenharmony_ciNdefMessage::~NdefMessage()
29bc2ed2b3Sopenharmony_ci{
30bc2ed2b3Sopenharmony_ci    ndefRecordList_.clear();
31bc2ed2b3Sopenharmony_ci}
32bc2ed2b3Sopenharmony_ci
33bc2ed2b3Sopenharmony_cistd::shared_ptr<NdefMessage> NdefMessage::GetNdefMessage(const std::string& data)
34bc2ed2b3Sopenharmony_ci{
35bc2ed2b3Sopenharmony_ci    std::vector<std::shared_ptr<NdefRecord>> ndefRecords = ParseRecord(data, false);
36bc2ed2b3Sopenharmony_ci    if (ndefRecords.empty()) {
37bc2ed2b3Sopenharmony_ci        ErrorLog("GetNdefMessage, ndefRecords invalid.");
38bc2ed2b3Sopenharmony_ci        return std::shared_ptr<NdefMessage>();
39bc2ed2b3Sopenharmony_ci    }
40bc2ed2b3Sopenharmony_ci    return GetNdefMessage(ndefRecords);
41bc2ed2b3Sopenharmony_ci}
42bc2ed2b3Sopenharmony_ci
43bc2ed2b3Sopenharmony_cistd::shared_ptr<NdefMessage> NdefMessage::GetNdefMessage(std::vector<std::shared_ptr<NdefRecord>> ndefRecords)
44bc2ed2b3Sopenharmony_ci{
45bc2ed2b3Sopenharmony_ci    return std::make_shared<NdefMessage>(std::move(ndefRecords));
46bc2ed2b3Sopenharmony_ci}
47bc2ed2b3Sopenharmony_ci
48bc2ed2b3Sopenharmony_cistd::string NdefMessage::GetTagRtdType(EmRtdType rtdtype)
49bc2ed2b3Sopenharmony_ci{
50bc2ed2b3Sopenharmony_ci    std::string rtd;
51bc2ed2b3Sopenharmony_ci    switch (rtdtype) {
52bc2ed2b3Sopenharmony_ci        case EmRtdType::RTD_TEXT:
53bc2ed2b3Sopenharmony_ci            rtd = "T";  // 0x54
54bc2ed2b3Sopenharmony_ci            break;
55bc2ed2b3Sopenharmony_ci        case EmRtdType::RTD_URI:
56bc2ed2b3Sopenharmony_ci            rtd = "U";  // 0x55
57bc2ed2b3Sopenharmony_ci            break;
58bc2ed2b3Sopenharmony_ci        case EmRtdType::RTD_SMART_POSTER:
59bc2ed2b3Sopenharmony_ci            rtd = "Sp";  // 0x53, 0x70
60bc2ed2b3Sopenharmony_ci            break;
61bc2ed2b3Sopenharmony_ci        case EmRtdType::RTD_ALTERNATIVE_CARRIER:
62bc2ed2b3Sopenharmony_ci            rtd = "ac";  // 0x61, 0x63
63bc2ed2b3Sopenharmony_ci            break;
64bc2ed2b3Sopenharmony_ci        case EmRtdType::RTD_HANDOVER_CARRIER:
65bc2ed2b3Sopenharmony_ci            rtd = "Hc";  // 0x48, 0x63
66bc2ed2b3Sopenharmony_ci            break;
67bc2ed2b3Sopenharmony_ci        case EmRtdType::RTD_HANDOVER_REQUEST:
68bc2ed2b3Sopenharmony_ci            rtd = "Hr";  // 0x48, 0x72
69bc2ed2b3Sopenharmony_ci            break;
70bc2ed2b3Sopenharmony_ci        case EmRtdType::RTD_HANDOVER_SELECT:
71bc2ed2b3Sopenharmony_ci            rtd = "Hs";  // 0x48, 0x73
72bc2ed2b3Sopenharmony_ci            break;
73bc2ed2b3Sopenharmony_ci        case EmRtdType::RTD_OHOS_APP:
74bc2ed2b3Sopenharmony_ci            rtd = "ohos.com:pkg";  // "ohos.com:pkg"
75bc2ed2b3Sopenharmony_ci            break;
76bc2ed2b3Sopenharmony_ci        default:
77bc2ed2b3Sopenharmony_ci            rtd.clear();
78bc2ed2b3Sopenharmony_ci            break;
79bc2ed2b3Sopenharmony_ci    }
80bc2ed2b3Sopenharmony_ci    return rtd;
81bc2ed2b3Sopenharmony_ci}
82bc2ed2b3Sopenharmony_ci
83bc2ed2b3Sopenharmony_cistd::vector<std::shared_ptr<NdefRecord>> NdefMessage::GetNdefRecords() const
84bc2ed2b3Sopenharmony_ci{
85bc2ed2b3Sopenharmony_ci    return ndefRecordList_;
86bc2ed2b3Sopenharmony_ci}
87bc2ed2b3Sopenharmony_ci
88bc2ed2b3Sopenharmony_cistd::shared_ptr<NdefRecord> NdefMessage::MakeUriRecord(const std::string& uriString)
89bc2ed2b3Sopenharmony_ci{
90bc2ed2b3Sopenharmony_ci    if (uriString.empty()) {
91bc2ed2b3Sopenharmony_ci        ErrorLog("MakeUriRecord, uriString invalid.");
92bc2ed2b3Sopenharmony_ci        return std::shared_ptr<NdefRecord>();
93bc2ed2b3Sopenharmony_ci    }
94bc2ed2b3Sopenharmony_ci
95bc2ed2b3Sopenharmony_ci    std::string payload = "00";
96bc2ed2b3Sopenharmony_ci    std::string uri = uriString;
97bc2ed2b3Sopenharmony_ci    for (size_t i = 1; i < g_uriPrefix.size() - 1; i++) {
98bc2ed2b3Sopenharmony_ci        if (!uriString.compare(0, g_uriPrefix[i].size(), g_uriPrefix[i])) {
99bc2ed2b3Sopenharmony_ci            payload = NfcSdkCommon::UnsignedCharToHexString(i & 0xFF);
100bc2ed2b3Sopenharmony_ci            uri = uriString.substr(g_uriPrefix[i].size());
101bc2ed2b3Sopenharmony_ci            break;
102bc2ed2b3Sopenharmony_ci        }
103bc2ed2b3Sopenharmony_ci    }
104bc2ed2b3Sopenharmony_ci
105bc2ed2b3Sopenharmony_ci    payload += NfcSdkCommon::StringToHexString(uri);
106bc2ed2b3Sopenharmony_ci
107bc2ed2b3Sopenharmony_ci    std::string id = "";
108bc2ed2b3Sopenharmony_ci    std::string tagRtdType = NfcSdkCommon::StringToHexString(GetTagRtdType(EmRtdType::RTD_URI));
109bc2ed2b3Sopenharmony_ci    return CreateNdefRecord(TNF_WELL_KNOWN, id, payload, tagRtdType);
110bc2ed2b3Sopenharmony_ci}
111bc2ed2b3Sopenharmony_ci
112bc2ed2b3Sopenharmony_cistd::shared_ptr<NdefRecord> NdefMessage::MakeTextRecord(const std::string& text, const std::string& locale)
113bc2ed2b3Sopenharmony_ci{
114bc2ed2b3Sopenharmony_ci    std::string tagRtdType = NfcSdkCommon::StringToHexString(GetTagRtdType(EmRtdType::RTD_TEXT));
115bc2ed2b3Sopenharmony_ci    std::string id = "";
116bc2ed2b3Sopenharmony_ci    int localeLen = locale.size() & 0xFF;
117bc2ed2b3Sopenharmony_ci    std::string payload = NfcSdkCommon::UnsignedCharToHexString(localeLen);
118bc2ed2b3Sopenharmony_ci    payload += NfcSdkCommon::StringToHexString(locale);
119bc2ed2b3Sopenharmony_ci    payload += NfcSdkCommon::StringToHexString(text);
120bc2ed2b3Sopenharmony_ci    return CreateNdefRecord(TNF_WELL_KNOWN, id, payload, tagRtdType);
121bc2ed2b3Sopenharmony_ci}
122bc2ed2b3Sopenharmony_ci
123bc2ed2b3Sopenharmony_cistd::shared_ptr<NdefRecord> NdefMessage::MakeMimeRecord(const std::string& mimeType, const std::string& mimeData)
124bc2ed2b3Sopenharmony_ci{
125bc2ed2b3Sopenharmony_ci    if (mimeType.empty() || mimeData.empty()) {
126bc2ed2b3Sopenharmony_ci        ErrorLog("MakeMimeRecord, mimeType or mimeData invalid.");
127bc2ed2b3Sopenharmony_ci        return std::shared_ptr<NdefRecord>();
128bc2ed2b3Sopenharmony_ci    }
129bc2ed2b3Sopenharmony_ci    std::string id = "";
130bc2ed2b3Sopenharmony_ci    size_t t = mimeType.find_first_of('/');
131bc2ed2b3Sopenharmony_ci    if (t == 0 || t == (mimeType.size() - 1)) {
132bc2ed2b3Sopenharmony_ci        ErrorLog("MakeMimeRecord, mimeType should have major and minor type if '/' exists.");
133bc2ed2b3Sopenharmony_ci        return std::shared_ptr<NdefRecord>();
134bc2ed2b3Sopenharmony_ci    }
135bc2ed2b3Sopenharmony_ci    return CreateNdefRecord(TNF_MIME_MEDIA, id, mimeData, NfcSdkCommon::StringToHexString(mimeType));
136bc2ed2b3Sopenharmony_ci}
137bc2ed2b3Sopenharmony_ci
138bc2ed2b3Sopenharmony_cistd::shared_ptr<NdefRecord> NdefMessage::MakeExternalRecord(const std::string& domainName,
139bc2ed2b3Sopenharmony_ci                                                            const std::string& serviceName,
140bc2ed2b3Sopenharmony_ci                                                            const std::string& externalData)
141bc2ed2b3Sopenharmony_ci{
142bc2ed2b3Sopenharmony_ci    if (domainName.empty() || serviceName.empty() || externalData.empty()) {
143bc2ed2b3Sopenharmony_ci        ErrorLog("MakeExternalRecord, domainName or serviceName invalid.");
144bc2ed2b3Sopenharmony_ci        return std::shared_ptr<NdefRecord>();
145bc2ed2b3Sopenharmony_ci    }
146bc2ed2b3Sopenharmony_ci
147bc2ed2b3Sopenharmony_ci    std::string domain = domainName;
148bc2ed2b3Sopenharmony_ci    std::string service = serviceName;
149bc2ed2b3Sopenharmony_ci    domain.erase(0, domain.find_first_not_of("\r\t\n "));
150bc2ed2b3Sopenharmony_ci    domain.erase(domain.find_last_not_of("\r\t\n ") + 1);
151bc2ed2b3Sopenharmony_ci    transform(domain.begin(), domain.end(), domain.begin(), ::tolower);
152bc2ed2b3Sopenharmony_ci    service.erase(0, service.find_first_not_of("\r\t\n "));
153bc2ed2b3Sopenharmony_ci    service.erase(service.find_last_not_of("\r\t\n ") + 1);
154bc2ed2b3Sopenharmony_ci    transform(service.begin(), service.end(), service.begin(), ::tolower);
155bc2ed2b3Sopenharmony_ci
156bc2ed2b3Sopenharmony_ci    if (domain.empty() || service.empty()) {
157bc2ed2b3Sopenharmony_ci        return std::shared_ptr<NdefRecord>();
158bc2ed2b3Sopenharmony_ci    }
159bc2ed2b3Sopenharmony_ci
160bc2ed2b3Sopenharmony_ci    std::string tagRtdType = NfcSdkCommon::StringToHexString(domain + ":" + service);
161bc2ed2b3Sopenharmony_ci    std::string id = "";
162bc2ed2b3Sopenharmony_ci
163bc2ed2b3Sopenharmony_ci    return CreateNdefRecord(TNF_EXTERNAL_TYPE, id, externalData, tagRtdType);
164bc2ed2b3Sopenharmony_ci}
165bc2ed2b3Sopenharmony_ci
166bc2ed2b3Sopenharmony_cistd::string NdefMessage::MessageToString(std::weak_ptr<NdefMessage> ndefMessage)
167bc2ed2b3Sopenharmony_ci{
168bc2ed2b3Sopenharmony_ci    std::string buffer;
169bc2ed2b3Sopenharmony_ci    if (ndefMessage.expired()) {
170bc2ed2b3Sopenharmony_ci        ErrorLog("MessageToString, ndefMessage invalid.");
171bc2ed2b3Sopenharmony_ci        return buffer;
172bc2ed2b3Sopenharmony_ci    }
173bc2ed2b3Sopenharmony_ci    for (size_t i = 0; i < ndefMessage.lock()->ndefRecordList_.size(); i++) {
174bc2ed2b3Sopenharmony_ci        bool bIsMB = (i == 0);                                                // first record
175bc2ed2b3Sopenharmony_ci        bool bIsME = (i == ndefMessage.lock()->ndefRecordList_.size() - 1);  // last record
176bc2ed2b3Sopenharmony_ci        NdefRecordToString(ndefMessage.lock()->ndefRecordList_.at(i), buffer, bIsMB, bIsME);
177bc2ed2b3Sopenharmony_ci    }
178bc2ed2b3Sopenharmony_ci    return buffer;
179bc2ed2b3Sopenharmony_ci}
180bc2ed2b3Sopenharmony_ci
181bc2ed2b3Sopenharmony_civoid NdefMessage::NdefRecordToString(std::weak_ptr<NdefRecord> record, std::string& buffer, bool bIsMB, bool bIsME)
182bc2ed2b3Sopenharmony_ci{
183bc2ed2b3Sopenharmony_ci    if (record.expired()) {
184bc2ed2b3Sopenharmony_ci        ErrorLog("NdefRecordToString, record invalid.");
185bc2ed2b3Sopenharmony_ci        return;
186bc2ed2b3Sopenharmony_ci    }
187bc2ed2b3Sopenharmony_ci    std::string payload = record.lock()->payload_;
188bc2ed2b3Sopenharmony_ci    uint32_t tnf = record.lock()->tnf_;
189bc2ed2b3Sopenharmony_ci    std::string id = record.lock()->id_;
190bc2ed2b3Sopenharmony_ci    std::string rtdType = record.lock()->tagRtdType_;
191bc2ed2b3Sopenharmony_ci    bool sr = NfcSdkCommon::GetHexStrBytesLen(payload) < SHORT_RECORD_SIZE;
192bc2ed2b3Sopenharmony_ci    bool il = (tnf == TNF_EMPTY) ? true : (NfcSdkCommon::GetHexStrBytesLen(id) > 0);
193bc2ed2b3Sopenharmony_ci    unsigned char flag = (unsigned char)((bIsMB ? FLAG_MB : 0) | (bIsME ? FLAG_ME : 0)
194bc2ed2b3Sopenharmony_ci        | (sr ? FLAG_SR : 0) | (il ? FLAG_IL : 0)) | (char)tnf;
195bc2ed2b3Sopenharmony_ci    buffer.append(NfcSdkCommon::UnsignedCharToHexString(flag));
196bc2ed2b3Sopenharmony_ci    buffer.append(NfcSdkCommon::IntToHexString(NfcSdkCommon::GetHexStrBytesLen(rtdType)));
197bc2ed2b3Sopenharmony_ci    if (sr) {
198bc2ed2b3Sopenharmony_ci        buffer.append(NfcSdkCommon::IntToHexString(NfcSdkCommon::GetHexStrBytesLen(payload)));
199bc2ed2b3Sopenharmony_ci    } else {
200bc2ed2b3Sopenharmony_ci        buffer.append(NfcSdkCommon::IntToHexString(NfcSdkCommon::GetHexStrBytesLen(payload)));
201bc2ed2b3Sopenharmony_ci    }
202bc2ed2b3Sopenharmony_ci    if (il) {
203bc2ed2b3Sopenharmony_ci        buffer.append(NfcSdkCommon::IntToHexString(NfcSdkCommon::GetHexStrBytesLen(id)));
204bc2ed2b3Sopenharmony_ci    }
205bc2ed2b3Sopenharmony_ci
206bc2ed2b3Sopenharmony_ci    buffer.append(rtdType);
207bc2ed2b3Sopenharmony_ci    buffer.append(id);
208bc2ed2b3Sopenharmony_ci    buffer.append(payload);
209bc2ed2b3Sopenharmony_ci}
210bc2ed2b3Sopenharmony_ci
211bc2ed2b3Sopenharmony_civoid NdefMessage::ParseRecordLayoutHead(RecordLayout& layout, unsigned char head)
212bc2ed2b3Sopenharmony_ci{
213bc2ed2b3Sopenharmony_ci    layout.mb = (head & FLAG_MB) != 0;
214bc2ed2b3Sopenharmony_ci    layout.me = (head & FLAG_ME) != 0;
215bc2ed2b3Sopenharmony_ci    layout.cf = (head & FLAG_CF) != 0;
216bc2ed2b3Sopenharmony_ci    layout.sr = (head & FLAG_SR) != 0;
217bc2ed2b3Sopenharmony_ci    layout.il = (head & FLAG_IL) != 0;
218bc2ed2b3Sopenharmony_ci    layout.tnf = static_cast<short>(head & FLAG_TNF);
219bc2ed2b3Sopenharmony_ci}
220bc2ed2b3Sopenharmony_ci
221bc2ed2b3Sopenharmony_cibool NdefMessage::IsInvalidRecordLayoutHead(RecordLayout& layout, bool isChunkFound,
222bc2ed2b3Sopenharmony_ci    uint32_t parsedRecordSize, bool isMbMeIgnored)
223bc2ed2b3Sopenharmony_ci{
224bc2ed2b3Sopenharmony_ci    if (!layout.mb && parsedRecordSize == 0 && !isChunkFound && !isMbMeIgnored) {
225bc2ed2b3Sopenharmony_ci        ErrorLog("IsInvalidRecordLayoutHead, 1st error for mb and size.");
226bc2ed2b3Sopenharmony_ci        return true;
227bc2ed2b3Sopenharmony_ci    } else if (layout.mb && (parsedRecordSize != 0 || isChunkFound) && !isMbMeIgnored) {
228bc2ed2b3Sopenharmony_ci        ErrorLog("IsInvalidRecordLayoutHead, 2nd error for mb and size");
229bc2ed2b3Sopenharmony_ci        return true;
230bc2ed2b3Sopenharmony_ci    } else if (isChunkFound && layout.il) {
231bc2ed2b3Sopenharmony_ci        ErrorLog("IsInvalidRecordLayoutHead, 3rd error for il");
232bc2ed2b3Sopenharmony_ci        return true;
233bc2ed2b3Sopenharmony_ci    } else if (layout.cf && layout.me) {
234bc2ed2b3Sopenharmony_ci        ErrorLog("IsInvalidRecordLayoutHead, 4th error for cf and me");
235bc2ed2b3Sopenharmony_ci        return true;
236bc2ed2b3Sopenharmony_ci    } else if (isChunkFound && layout.tnf != TNF_UNCHANGED) {
237bc2ed2b3Sopenharmony_ci        ErrorLog("IsInvalidRecordLayoutHead, 5th error for tnf");
238bc2ed2b3Sopenharmony_ci        return true;
239bc2ed2b3Sopenharmony_ci    } else if (!isChunkFound && layout.tnf == TNF_UNCHANGED) {
240bc2ed2b3Sopenharmony_ci        ErrorLog("IsInvalidRecordLayoutHead, 6th error for tnf");
241bc2ed2b3Sopenharmony_ci        return true;
242bc2ed2b3Sopenharmony_ci    }
243bc2ed2b3Sopenharmony_ci    return false;
244bc2ed2b3Sopenharmony_ci}
245bc2ed2b3Sopenharmony_ci
246bc2ed2b3Sopenharmony_civoid NdefMessage::ParseRecordLayoutLength(RecordLayout& layout, bool isChunkFound,
247bc2ed2b3Sopenharmony_ci    const std::string& data, uint32_t& parsedDataIndex)
248bc2ed2b3Sopenharmony_ci{
249bc2ed2b3Sopenharmony_ci    layout.typeLength = NfcSdkCommon::GetByteFromHexStr(data, parsedDataIndex++) & 0xFF;
250bc2ed2b3Sopenharmony_ci    if (layout.sr) {
251bc2ed2b3Sopenharmony_ci        layout.payloadLength = NfcSdkCommon::GetByteFromHexStr(data, parsedDataIndex++) & 0xFF;
252bc2ed2b3Sopenharmony_ci    } else {
253bc2ed2b3Sopenharmony_ci        if (NfcSdkCommon::GetHexStrBytesLen(data) < parsedDataIndex + int(sizeof(int))) {
254bc2ed2b3Sopenharmony_ci            layout.payloadLength = 0;
255bc2ed2b3Sopenharmony_ci        } else {
256bc2ed2b3Sopenharmony_ci            std::string lenString = data.substr(parsedDataIndex * HEX_BYTE_LEN, sizeof(int) * HEX_BYTE_LEN);
257bc2ed2b3Sopenharmony_ci            layout.payloadLength = 0;
258bc2ed2b3Sopenharmony_ci            for (unsigned int i = 0; i < sizeof(int); i++) {
259bc2ed2b3Sopenharmony_ci                layout.payloadLength +=
260bc2ed2b3Sopenharmony_ci                    (NfcSdkCommon::GetByteFromHexStr(lenString, i) << ((sizeof(int) - i - 1) * ONE_BYTE_SHIFT));
261bc2ed2b3Sopenharmony_ci            }
262bc2ed2b3Sopenharmony_ci            parsedDataIndex += sizeof(int);
263bc2ed2b3Sopenharmony_ci        }
264bc2ed2b3Sopenharmony_ci    }
265bc2ed2b3Sopenharmony_ci    layout.idLength = layout.il ? (NfcSdkCommon::GetByteFromHexStr(data, parsedDataIndex++) & 0xFF) : 0;
266bc2ed2b3Sopenharmony_ci}
267bc2ed2b3Sopenharmony_ci
268bc2ed2b3Sopenharmony_cibool NdefMessage::IsRecordLayoutLengthInvalid(RecordLayout& layout, bool isChunkFound)
269bc2ed2b3Sopenharmony_ci{
270bc2ed2b3Sopenharmony_ci    // for the middle chunks record, need the type length is zero.
271bc2ed2b3Sopenharmony_ci    if (isChunkFound && layout.typeLength != 0) {
272bc2ed2b3Sopenharmony_ci        ErrorLog("IsInvalidRecordLayoutHead, 1st error for typeLength");
273bc2ed2b3Sopenharmony_ci        return true;
274bc2ed2b3Sopenharmony_ci    }
275bc2ed2b3Sopenharmony_ci
276bc2ed2b3Sopenharmony_ci    // for the first chunk, expected has type.
277bc2ed2b3Sopenharmony_ci    if (layout.cf && !isChunkFound) {
278bc2ed2b3Sopenharmony_ci        if (layout.typeLength == 0 && layout.tnf != TNF_UNKNOWN) {
279bc2ed2b3Sopenharmony_ci            ErrorLog("IsInvalidRecordLayoutHead, 2nd error for typeLength and tnf");
280bc2ed2b3Sopenharmony_ci            return true;
281bc2ed2b3Sopenharmony_ci        }
282bc2ed2b3Sopenharmony_ci    }
283bc2ed2b3Sopenharmony_ci
284bc2ed2b3Sopenharmony_ci    if (layout.payloadLength > MAX_PAYLOAD_SIZE) {
285bc2ed2b3Sopenharmony_ci        ErrorLog("IsInvalidRecordLayoutHead, 3rd error for payloadLength");
286bc2ed2b3Sopenharmony_ci        return true;
287bc2ed2b3Sopenharmony_ci    }
288bc2ed2b3Sopenharmony_ci    return false;
289bc2ed2b3Sopenharmony_ci}
290bc2ed2b3Sopenharmony_ci
291bc2ed2b3Sopenharmony_cistd::string NdefMessage::ParseRecordType(RecordLayout& layout, const std::string& data, uint32_t& parsedDataIndex)
292bc2ed2b3Sopenharmony_ci{
293bc2ed2b3Sopenharmony_ci    if (layout.typeLength <= 0) {
294bc2ed2b3Sopenharmony_ci        ErrorLog("IsInvalidRecordLayoutHead, typeLength less than 0.");
295bc2ed2b3Sopenharmony_ci        return "";
296bc2ed2b3Sopenharmony_ci    }
297bc2ed2b3Sopenharmony_ci    if (NfcSdkCommon::GetHexStrBytesLen(data) < parsedDataIndex + layout.typeLength) {
298bc2ed2b3Sopenharmony_ci        ErrorLog("data len.%{public}d index.%{public}d rtdtype len.%{public}d error",
299bc2ed2b3Sopenharmony_ci            NfcSdkCommon::GetHexStrBytesLen(data), parsedDataIndex, layout.typeLength);
300bc2ed2b3Sopenharmony_ci        return "";
301bc2ed2b3Sopenharmony_ci    }
302bc2ed2b3Sopenharmony_ci    std::string type = data.substr(parsedDataIndex * HEX_BYTE_LEN, layout.typeLength * HEX_BYTE_LEN);
303bc2ed2b3Sopenharmony_ci    parsedDataIndex += layout.typeLength;
304bc2ed2b3Sopenharmony_ci    return type;
305bc2ed2b3Sopenharmony_ci}
306bc2ed2b3Sopenharmony_ci
307bc2ed2b3Sopenharmony_cistd::string NdefMessage::ParseRecordId(RecordLayout& layout, const std::string& data, uint32_t& parsedDataIndex)
308bc2ed2b3Sopenharmony_ci{
309bc2ed2b3Sopenharmony_ci    if (layout.idLength <= 0) {
310bc2ed2b3Sopenharmony_ci        ErrorLog("ParseRecordId, idLength <= 0");
311bc2ed2b3Sopenharmony_ci        return "";
312bc2ed2b3Sopenharmony_ci    }
313bc2ed2b3Sopenharmony_ci    if (NfcSdkCommon::GetHexStrBytesLen(data) < parsedDataIndex + layout.idLength) {
314bc2ed2b3Sopenharmony_ci        ErrorLog("data len.%{public}d index.%{public}d id len.%{public}d error",
315bc2ed2b3Sopenharmony_ci            NfcSdkCommon::GetHexStrBytesLen(data), parsedDataIndex, layout.idLength);
316bc2ed2b3Sopenharmony_ci        return "";
317bc2ed2b3Sopenharmony_ci    }
318bc2ed2b3Sopenharmony_ci    std::string id = data.substr(parsedDataIndex * HEX_BYTE_LEN, layout.idLength * HEX_BYTE_LEN);
319bc2ed2b3Sopenharmony_ci    parsedDataIndex += layout.idLength;
320bc2ed2b3Sopenharmony_ci    return id;
321bc2ed2b3Sopenharmony_ci}
322bc2ed2b3Sopenharmony_ci
323bc2ed2b3Sopenharmony_cistd::string NdefMessage::ParseRecordPayload(RecordLayout& layout, const std::string& data, uint32_t& parsedDataIndex)
324bc2ed2b3Sopenharmony_ci{
325bc2ed2b3Sopenharmony_ci    if (layout.payloadLength <= 0) {
326bc2ed2b3Sopenharmony_ci        ErrorLog("ParseRecordPayload, payloadLength <= 0");
327bc2ed2b3Sopenharmony_ci        return "";
328bc2ed2b3Sopenharmony_ci    }
329bc2ed2b3Sopenharmony_ci    if (NfcSdkCommon::GetHexStrBytesLen(data) < (parsedDataIndex + layout.payloadLength)) {
330bc2ed2b3Sopenharmony_ci        ErrorLog("data len.%{public}d index.%{public}d payload len.%{public}d error",
331bc2ed2b3Sopenharmony_ci            NfcSdkCommon::GetHexStrBytesLen(data), parsedDataIndex, layout.payloadLength);
332bc2ed2b3Sopenharmony_ci        return "";
333bc2ed2b3Sopenharmony_ci    }
334bc2ed2b3Sopenharmony_ci    std::string payload = data.substr(parsedDataIndex * HEX_BYTE_LEN, layout.payloadLength * HEX_BYTE_LEN);
335bc2ed2b3Sopenharmony_ci    parsedDataIndex += layout.payloadLength;
336bc2ed2b3Sopenharmony_ci    return payload;
337bc2ed2b3Sopenharmony_ci}
338bc2ed2b3Sopenharmony_ci
339bc2ed2b3Sopenharmony_civoid NdefMessage::SaveRecordChunks(RecordLayout& layout, bool isChunkFound,
340bc2ed2b3Sopenharmony_ci    std::vector<std::string>& chunks, char& chunkTnf, const std::string& payload)
341bc2ed2b3Sopenharmony_ci{
342bc2ed2b3Sopenharmony_ci    // handle for the first chunk.
343bc2ed2b3Sopenharmony_ci    if (layout.cf && !isChunkFound) {
344bc2ed2b3Sopenharmony_ci        chunks.clear();
345bc2ed2b3Sopenharmony_ci        chunkTnf = layout.tnf;
346bc2ed2b3Sopenharmony_ci    }
347bc2ed2b3Sopenharmony_ci
348bc2ed2b3Sopenharmony_ci    // save the payload for all(first/middle/last) chunk.
349bc2ed2b3Sopenharmony_ci    if (layout.cf || isChunkFound) {
350bc2ed2b3Sopenharmony_ci        chunks.push_back(payload);
351bc2ed2b3Sopenharmony_ci    }
352bc2ed2b3Sopenharmony_ci}
353bc2ed2b3Sopenharmony_ci
354bc2ed2b3Sopenharmony_cistd::string NdefMessage::MergePayloadByChunks(RecordLayout& layout, bool isChunkFound,
355bc2ed2b3Sopenharmony_ci    std::vector<std::string>& chunks, char chunkTnf, const std::string& payload)
356bc2ed2b3Sopenharmony_ci{
357bc2ed2b3Sopenharmony_ci    // it's the last chunk, merge the payload for NdefRecord.
358bc2ed2b3Sopenharmony_ci    if (!layout.cf && isChunkFound) {
359bc2ed2b3Sopenharmony_ci        std::string mergedPayload;
360bc2ed2b3Sopenharmony_ci        for (std::string n : chunks) {
361bc2ed2b3Sopenharmony_ci            mergedPayload += n;
362bc2ed2b3Sopenharmony_ci        }
363bc2ed2b3Sopenharmony_ci        layout.tnf = chunkTnf;
364bc2ed2b3Sopenharmony_ci        return mergedPayload;
365bc2ed2b3Sopenharmony_ci    }
366bc2ed2b3Sopenharmony_ci    return payload;
367bc2ed2b3Sopenharmony_ci}
368bc2ed2b3Sopenharmony_ci
369bc2ed2b3Sopenharmony_cistd::shared_ptr<NdefRecord> NdefMessage::CreateNdefRecord(short tnf, const std::string& id,
370bc2ed2b3Sopenharmony_ci    const std::string& payload, const std::string& tagRtdType)
371bc2ed2b3Sopenharmony_ci{
372bc2ed2b3Sopenharmony_ci    bool isValidTnf = CheckTnf(tnf, tagRtdType, id, payload);
373bc2ed2b3Sopenharmony_ci    if (!isValidTnf) {
374bc2ed2b3Sopenharmony_ci        ErrorLog("CreateNdefRecord, isValidTnf failed.");
375bc2ed2b3Sopenharmony_ci        return std::shared_ptr<NdefRecord>();
376bc2ed2b3Sopenharmony_ci    }
377bc2ed2b3Sopenharmony_ci    std::shared_ptr<NdefRecord> ndefRecord = std::make_shared<NdefRecord>();
378bc2ed2b3Sopenharmony_ci    ndefRecord->tnf_ = tnf;
379bc2ed2b3Sopenharmony_ci    ndefRecord->id_ = id;
380bc2ed2b3Sopenharmony_ci    ndefRecord->payload_ = payload;
381bc2ed2b3Sopenharmony_ci    ndefRecord->tagRtdType_ = tagRtdType;
382bc2ed2b3Sopenharmony_ci    return ndefRecord;
383bc2ed2b3Sopenharmony_ci}
384bc2ed2b3Sopenharmony_ci
385bc2ed2b3Sopenharmony_cibool NdefMessage::CheckTnf(short tnf, const std::string& tagRtdType, const std::string& id, const std::string& payload)
386bc2ed2b3Sopenharmony_ci{
387bc2ed2b3Sopenharmony_ci    switch (tnf) {
388bc2ed2b3Sopenharmony_ci        case TNF_EMPTY:
389bc2ed2b3Sopenharmony_ci            if (!tagRtdType.empty() || !id.empty() || !payload.empty()) {
390bc2ed2b3Sopenharmony_ci                ErrorLog("CheckTnf, TNF_EMPTY error.");
391bc2ed2b3Sopenharmony_ci                return false;
392bc2ed2b3Sopenharmony_ci            }
393bc2ed2b3Sopenharmony_ci            break;
394bc2ed2b3Sopenharmony_ci        case TNF_WELL_KNOWN:
395bc2ed2b3Sopenharmony_ci        case TNF_MIME_MEDIA:
396bc2ed2b3Sopenharmony_ci        case TNF_ABSOLUTE_URI:
397bc2ed2b3Sopenharmony_ci        case TNF_EXTERNAL_TYPE:
398bc2ed2b3Sopenharmony_ci            return true;
399bc2ed2b3Sopenharmony_ci        case TNF_UNKNOWN:
400bc2ed2b3Sopenharmony_ci        case TNF_RESERVED:
401bc2ed2b3Sopenharmony_ci            if (tagRtdType.empty()) {
402bc2ed2b3Sopenharmony_ci                return false;
403bc2ed2b3Sopenharmony_ci            }
404bc2ed2b3Sopenharmony_ci            return true;
405bc2ed2b3Sopenharmony_ci        case TNF_UNCHANGED:
406bc2ed2b3Sopenharmony_ci            return false;
407bc2ed2b3Sopenharmony_ci        default:
408bc2ed2b3Sopenharmony_ci            break;
409bc2ed2b3Sopenharmony_ci    }
410bc2ed2b3Sopenharmony_ci    return false;
411bc2ed2b3Sopenharmony_ci}
412bc2ed2b3Sopenharmony_ci
413bc2ed2b3Sopenharmony_cistd::vector<std::shared_ptr<NdefRecord>> NdefMessage::ParseRecord(const std::string& data, bool isMbMeIgnored)
414bc2ed2b3Sopenharmony_ci{
415bc2ed2b3Sopenharmony_ci    std::vector<std::shared_ptr<NdefRecord>> recordList;
416bc2ed2b3Sopenharmony_ci    if (data.empty()) {
417bc2ed2b3Sopenharmony_ci        ErrorLog("ParseRecord, raw data empty.");
418bc2ed2b3Sopenharmony_ci        return recordList;
419bc2ed2b3Sopenharmony_ci    }
420bc2ed2b3Sopenharmony_ci
421bc2ed2b3Sopenharmony_ci    std::string tagRtdType;
422bc2ed2b3Sopenharmony_ci    std::string id;
423bc2ed2b3Sopenharmony_ci    std::vector<std::string> chunks;
424bc2ed2b3Sopenharmony_ci    bool isChunkFound = false;
425bc2ed2b3Sopenharmony_ci    char chunkTnf = 0;
426bc2ed2b3Sopenharmony_ci    bool isMessageEnd = false;
427bc2ed2b3Sopenharmony_ci    uint32_t parsedDataIndex = 0;
428bc2ed2b3Sopenharmony_ci    while (!isMessageEnd) {
429bc2ed2b3Sopenharmony_ci        RecordLayout layout;
430bc2ed2b3Sopenharmony_ci        ParseRecordLayoutHead(layout, NfcSdkCommon::GetByteFromHexStr(data, parsedDataIndex++));
431bc2ed2b3Sopenharmony_ci        isMessageEnd = layout.me;
432bc2ed2b3Sopenharmony_ci
433bc2ed2b3Sopenharmony_ci        if (data.size() / HEX_BYTE_LEN < parsedDataIndex) {
434bc2ed2b3Sopenharmony_ci            return recordList;
435bc2ed2b3Sopenharmony_ci        }
436bc2ed2b3Sopenharmony_ci        if ((data.size() / HEX_BYTE_LEN - parsedDataIndex) < MIN_RECORD_LEN && !isMessageEnd) {
437bc2ed2b3Sopenharmony_ci            return recordList;
438bc2ed2b3Sopenharmony_ci        }
439bc2ed2b3Sopenharmony_ci        if (IsInvalidRecordLayoutHead(layout, isChunkFound, recordList.size(), isMbMeIgnored)) {
440bc2ed2b3Sopenharmony_ci            return recordList;
441bc2ed2b3Sopenharmony_ci        }
442bc2ed2b3Sopenharmony_ci
443bc2ed2b3Sopenharmony_ci        ParseRecordLayoutLength(layout, isChunkFound, data, parsedDataIndex);
444bc2ed2b3Sopenharmony_ci
445bc2ed2b3Sopenharmony_ci        if (IsRecordLayoutLengthInvalid(layout, isChunkFound)) {
446bc2ed2b3Sopenharmony_ci            return recordList;
447bc2ed2b3Sopenharmony_ci        }
448bc2ed2b3Sopenharmony_ci
449bc2ed2b3Sopenharmony_ci        if (!isChunkFound) {
450bc2ed2b3Sopenharmony_ci            // don't parse the type and id for the middle chunks record, allowed them tobe empty.
451bc2ed2b3Sopenharmony_ci            tagRtdType = ParseRecordType(layout, data, parsedDataIndex);
452bc2ed2b3Sopenharmony_ci            id = ParseRecordId(layout, data, parsedDataIndex);
453bc2ed2b3Sopenharmony_ci        }
454bc2ed2b3Sopenharmony_ci
455bc2ed2b3Sopenharmony_ci        // parse the payload.
456bc2ed2b3Sopenharmony_ci        std::string payload = ParseRecordPayload(layout, data, parsedDataIndex);
457bc2ed2b3Sopenharmony_ci        SaveRecordChunks(layout, isChunkFound, chunks, chunkTnf, payload);
458bc2ed2b3Sopenharmony_ci        payload = MergePayloadByChunks(layout, isChunkFound, chunks, chunkTnf, payload);
459bc2ed2b3Sopenharmony_ci        if (NfcSdkCommon::GetHexStrBytesLen(payload) > MAX_PAYLOAD_SIZE) {
460bc2ed2b3Sopenharmony_ci            ErrorLog("ParseRecord, payload > MAX_PAYLOAD_SIZE");
461bc2ed2b3Sopenharmony_ci            return recordList;
462bc2ed2b3Sopenharmony_ci        }
463bc2ed2b3Sopenharmony_ci
464bc2ed2b3Sopenharmony_ci        // if not the last chunk, continue to parse again.
465bc2ed2b3Sopenharmony_ci        isChunkFound = layout.cf;
466bc2ed2b3Sopenharmony_ci        if (isChunkFound) {
467bc2ed2b3Sopenharmony_ci            continue;
468bc2ed2b3Sopenharmony_ci        }
469bc2ed2b3Sopenharmony_ci
470bc2ed2b3Sopenharmony_ci        // all chunks parsed end, add a new NdefRecord.
471bc2ed2b3Sopenharmony_ci        std::shared_ptr<NdefRecord> record = CreateNdefRecord(layout.tnf, id, payload, tagRtdType);
472bc2ed2b3Sopenharmony_ci        recordList.push_back(record);
473bc2ed2b3Sopenharmony_ci
474bc2ed2b3Sopenharmony_ci        // isMbMeIgnored is true, means that single record need tobe parsed.
475bc2ed2b3Sopenharmony_ci        if (isMbMeIgnored) {
476bc2ed2b3Sopenharmony_ci            break;
477bc2ed2b3Sopenharmony_ci        }
478bc2ed2b3Sopenharmony_ci    }
479bc2ed2b3Sopenharmony_ci    return recordList;
480bc2ed2b3Sopenharmony_ci}
481bc2ed2b3Sopenharmony_ci}  // namespace KITS
482bc2ed2b3Sopenharmony_ci}  // namespace NFC
483bc2ed2b3Sopenharmony_ci}  // namespace OHOS
484