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 #ifndef NDEF_MESSAGE_H
16 #define NDEF_MESSAGE_H
17 
18 #include <array>
19 #include <string>
20 #include <vector>
21 
22 namespace OHOS {
23 namespace NFC {
24 namespace KITS {
25 // record data, see NFC Data Exchange Format (NDEF) Technical Specification.
26 struct NdefRecord {
27     short tnf_;
28     std::string id_;            // hex string, 0x00~0xFF
29     std::string payload_;       // hex string, 0x00~0xFF
30     std::string tagRtdType_;    // hex string, 0x00~0xFF
31 };
32 
33 // layout, see NFC Data Exchange Format (NDEF) Technical Specification.
34 struct RecordLayout {
35     bool mb; // message begin
36     bool me; // message end
37     bool cf; // chunk flag
38     bool sr; // short record
39     bool il; // id length
40     short tnf; // type name format
41     uint16_t typeLength;
42     uint32_t payloadLength;
43     uint16_t idLength;
44 };
45 
46 // URI charactor code defined by NFC Forum
47 static const size_t MAX_URI_CODE_NUM = 0x24;
48 static std::array<std::string, MAX_URI_CODE_NUM> g_uriPrefix = {
49     "",                            // NFC Forum define value: 0x00
50     "http://www.",                 // NFC Forum define value: 0x01
51     "https://www.",                // NFC Forum define value: 0x02
52     "http://",                     // NFC Forum define value: 0x03
53     "https://",                    // NFC Forum define value: 0x04
54     "tel:",                        // NFC Forum define value: 0x05
55     "mailto:",                     // NFC Forum define value: 0x06
56     "ftp://anonymous:anonymous@",  // NFC Forum define value: 0x07
57     "ftp://ftp.",                  // NFC Forum define value: 0x08
58     "ftps://",                     // NFC Forum define value: 0x09
59     "sftp://",                     // NFC Forum define value: 0x0A
60     "smb://",                      // NFC Forum define value: 0x0B
61     "nfs://",                      // NFC Forum define value: 0x0C
62     "ftp://",                      // NFC Forum define value: 0x0D
63     "dav://",                      // NFC Forum define value: 0x0E
64     "news:",                       // NFC Forum define value: 0x0F
65     "telnet://",                   // NFC Forum define value: 0x10
66     "imap:",                       // NFC Forum define value: 0x11
67     "rtsp://",                     // NFC Forum define value: 0x12
68     "urn:",                        // NFC Forum define value: 0x13
69     "pop:",                        // NFC Forum define value: 0x14
70     "sip:",                        // NFC Forum define value: 0x15
71     "sips:",                       // NFC Forum define value: 0x16
72     "tftp:",                       // NFC Forum define value: 0x17
73     "btspp://",                    // NFC Forum define value: 0x18
74     "btl2cap://",                  // NFC Forum define value: 0x19
75     "btgoep://",                   // NFC Forum define value: 0x1A
76     "tcpobex://",                  // NFC Forum define value: 0x1B
77     "irdaobex://",                 // NFC Forum define value: 0x1C
78     "file://",                     // NFC Forum define value: 0x1D
79     "urn:epc:id:",                 // NFC Forum define value: 0x1E
80     "urn:epc:tag:",                // NFC Forum define value: 0x1F
81     "urn:epc:pat:",                // NFC Forum define value: 0x20
82     "urn:epc:raw:",                // NFC Forum define value: 0x21
83     "urn:epc:",                    // NFC Forum define value: 0x22
84     "urn:nfc:",                    // NFC Forum define value: 0x23
85 };
86 
87 class NdefMessage final {
88 public:
89     const int MAX_RTD_TYPE_LEN = 2;
90     static const int MIN_RECORD_LEN = 3;
91     static const long int MAX_PAYLOAD_SIZE = 10 * (1 << 20);  // 10MB
92     static const int SHORT_RECORD_SIZE = 256;
93     static const unsigned int ONE_BYTE_SHIFT = 8;
94 
95     // TNF Type define
96     enum EmTnfType {
97         TNF_EMPTY = 0x00,
98         TNF_WELL_KNOWN = 0x01,
99         TNF_MIME_MEDIA = 0x02,
100         TNF_ABSOLUTE_URI = 0x03,
101         TNF_EXTERNAL_TYPE = 0x04,
102         TNF_UNKNOWN = 0x05,
103         TNF_UNCHANGED = 0x06,
104         TNF_RESERVED = 0x07
105     };
106 
107     // record Flag
108     enum EmRecordFlag {
109         FLAG_MB = 0x80,
110         FLAG_ME = 0x40,
111         FLAG_CF = 0x20,
112         FLAG_SR = 0x10,
113         FLAG_IL = 0x08,
114         FLAG_TNF = 0x07
115     };
116 
117     enum EmRtdType {
118         RTD_UNKNOWN = 0,
119         RTD_TEXT,
120         RTD_URI,
121         RTD_SMART_POSTER,
122         RTD_ALTERNATIVE_CARRIER,
123         RTD_HANDOVER_CARRIER,
124         RTD_HANDOVER_REQUEST,
125         RTD_HANDOVER_SELECT,
126         RTD_OHOS_APP,
127         RTD_RESERVED,
128     };
129 public:
130     explicit NdefMessage(std::vector<std::shared_ptr<NdefRecord>> ndefRecords);
131     ~NdefMessage();
132 
133     /**
134      * @Description constructe a ndef message with raw bytes.
135      * @param data raw bytes to parse ndef message
136      * @return std::shared_ptr<NdefMessage>
137      */
138     static std::shared_ptr<NdefMessage> GetNdefMessage(const std::string& data);
139     /**
140      * @Description constructe a ndef message with record list.
141      * @param ndefRecords record list to parse ndef message
142      * @return std::shared_ptr<NdefMessage>
143      */
144     static std::shared_ptr<NdefMessage> GetNdefMessage(std::vector<std::shared_ptr<NdefRecord>> ndefRecords);
145     /**
146      * @Description convert the rtd bytes into byte array defined in Nfc forum.
147      * @param rtdtype rtd type of a record
148      * @return rtd byte array
149      */
150     static std::string GetTagRtdType(EmRtdType rtdtype);
151     /**
152      * @Description Create a ndef record with uri data.
153      * @param uriString uri data for new a ndef record
154      * @return std::shared_ptr<NdefRecord>
155      */
156     static std::shared_ptr<NdefRecord> MakeUriRecord(const std::string& uriString);
157     /**
158      * @Description Create a ndef record with text data.
159      * @param text text data for new a ndef record
160      * @param locale language code for the ndef record . if locale is null, use default locale
161      * @return std::shared_ptr<NdefRecord>
162      */
163     static std::shared_ptr<NdefRecord> MakeTextRecord(const std::string& text, const std::string& locale);
164     /**
165      * @Description Create a ndef record with mime data.
166      * @param mimeType type of mime data for new a ndef record
167      * @param mimeData mime data for new a ndef record
168      * @return std::shared_ptr<NdefRecord>
169      */
170     static std::shared_ptr<NdefRecord> MakeMimeRecord(const std::string& mimeType, const std::string& mimeData);
171 
172     /**
173      * @Description Create a ndef record with external data.
174      * @param domainName domain name of issuing organization for the external data
175      * @param serviceName domain specific type of data for the external data
176      * @param externalData data payload of a ndef record
177      * @return std::shared_ptr<NdefRecord>
178      */
179     static std::shared_ptr<NdefRecord> MakeExternalRecord(const std::string& domainName,
180                                                           const std::string& serviceName,
181                                                           const std::string& externalData);
182     /**
183      * @Description parse a ndef message into raw bytes.
184      * @param ndefMessage a ndef message to parse
185      * @return raw bytes of a ndef message
186      */
187     static std::string MessageToString(std::weak_ptr<NdefMessage> ndefMessage);
188     /**
189      * @Description parse a ndef record into raw bytes.
190      * @param record a ndef record to parse
191      * @param buffer raw bytes of a ndef record
192      * @param bIsMB the flag of begin record
193      * @param bIsME the flag of end record
194      * @return void
195      */
196     static void NdefRecordToString(std::weak_ptr<NdefRecord> record, std::string& buffer, bool bIsMB, bool bIsME);
197     /**
198      * @Description Get all records of a ndef message.
199      * @param void
200      * @return record list of a ndef message
201      */
202     std::vector<std::shared_ptr<NdefRecord>> GetNdefRecords() const;
203 
204 private:
205     static std::shared_ptr<NdefRecord> CreateNdefRecord(short tnf, const std::string& id,
206         const std::string& payload, const std::string& tagRtdType);
207     static bool CheckTnf(short tnf, const std::string& tagRtdType,
208         const std::string& id, const std::string& payload);
209     static std::vector<std::shared_ptr<NdefRecord>> ParseRecord(const std::string& data, bool isMbMeIgnored);
210     static void ParseRecordLayoutHead(RecordLayout& layout, unsigned char head);
211     static bool IsInvalidRecordLayoutHead(RecordLayout& layout, bool isChunkFound,
212         uint32_t parsedRecordSize, bool isMbMeIgnored);
213     static void ParseRecordLayoutLength(RecordLayout& layout, bool isChunkFound,
214         const std::string& data, uint32_t& parsedDataIndex);
215     static bool IsRecordLayoutLengthInvalid(RecordLayout& layout, bool isChunkFound);
216     static std::string ParseRecordType(RecordLayout& layout, const std::string& data, uint32_t& parsedDataIndex);
217     static std::string ParseRecordId(RecordLayout& layout, const std::string& data, uint32_t& parsedDataIndex);
218     static std::string ParseRecordPayload(RecordLayout& layout, const std::string& data, uint32_t& parsedDataIndex);
219 
220     static void SaveRecordChunks(RecordLayout& layout, bool isChunkFound, std::vector<std::string>& chunks,
221         char& chunkTnf, const std::string& payload);
222     static std::string MergePayloadByChunks(RecordLayout& layout, bool isChunkFound, std::vector<std::string>& chunks,
223         char chunkTnf, const std::string& payload);
224 
225 private:
226     std::vector<std::shared_ptr<NdefRecord>> ndefRecordList_ {};
227 };
228 
229 // RTD types definitions, see NFC Record Type Definition (RTD) Specification.
230 const static std::array<std::string, NdefMessage::EmRtdType::RTD_RESERVED> HEX_RTD_TYPE = {
231     "",                  // RTD_UNKNOWN
232     "54",                // 0x54, RTD_TEXT
233     "55",                // 0x55, RTD_URI
234 };
235 
236 }  // namespace KITS
237 }  // namespace NFC
238 }  // namespace OHOS
239 #endif  // NDEF_MESSAGE_H
240