1 /*
2  * Copyright (C) 2021 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 <cstring>
17 #include <string>
18 #include "packet.h"
19 #include "hfp_ag_defines.h"
20 #include "hfp_ag_command_parser.h"
21 
22 
23 namespace OHOS {
24 namespace bluetooth {
GetInstance()25 HfpAgCommandParser &HfpAgCommandParser::GetInstance()
26 {
27     static HfpAgCommandParser instance;
28     return instance;
29 }
30 
Read(HfpAgDataConnection & dataConn) const31 void HfpAgCommandParser::Read(HfpAgDataConnection &dataConn) const
32 {
33     Packet *pkt = nullptr;
34     Buffer *buf = nullptr;
35     uint8_t *pData = nullptr;
36 
37     dataConn.ReadData(&pkt);
38     if (pkt != nullptr) {
39         auto len = PacketPayloadSize(pkt);
40         buf = PacketContinuousPayload(pkt);
41         pData = (uint8_t *)BufferPtr(buf);
42 
43         std::vector<uint8_t> data(pData, pData + len);
44         Parse(dataConn, data, len);
45         PacketFree(pkt);
46     }
47 }
48 
Parse(HfpAgDataConnection & dataConn,std::vector<uint8_t> & data,size_t len) const49 void HfpAgCommandParser::Parse(HfpAgDataConnection &dataConn, std::vector<uint8_t> &data, size_t len) const
50 {
51     std::string cmd;
52     std::string arg;
53     size_t cmdLen = 0;
54     int cmdType = HFP_AG_CMD_UNKNOWN;
55 
56     if (data.empty() == true) {
57         HILOGI("data is nullptr");
58         return;
59     }
60 
61     for (size_t pos = 0; pos < len; pos++) {
62         // skip null characters
63         if (data[pos] == '\0') {
64             continue;
65         }
66         std::vector<uint8_t> partData(data.begin() + pos, data.end());
67         cmdType = Extract(partData, cmd, arg, cmdLen, len - pos);
68         pos += cmdLen;
69         HfpAgCommandProcessor::GetInstance().Handle(dataConn, cmd, arg, cmdType);
70     }
71     return;
72 }
73 
Extract(std::vector<uint8_t> & data,std::string & cmd,std::string & arg,size_t & cmdLen,size_t len) const74 int HfpAgCommandParser::Extract(std::vector<uint8_t> &data, std::string &cmd, std::string &arg,
75                                 size_t &cmdLen, size_t len) const
76 {
77     HfpAgCommandParser::CommandPosition position {0, 0, 0, 0, 0, false, false};
78     GetCommandPosition(data, len, position);
79     HILOGI("headValid: %{public}d, tailValid: %{public}d,"
80         " startPos: %{public}hu, setPos: %{public}hu, getPos: %{public}hu, endPos: %{public}hu",
81         position.headValid,
82         position.tailValid,
83         position.startPos,
84         position.setPos,
85         position.getPos,
86         position.endPos);
87 
88     if (!position.headValid || !position.tailValid || position.endPos < HFP_AG_AT_HEAD_SIZE ||
89         (position.setPos >= position.endPos) || (position.getPos >= position.endPos)) {
90         cmdLen = position.pos;
91         HILOGI("HFP_AG_CMD_INVALID");
92         return HFP_AG_CMD_INVALID;
93     }
94 
95     int type;
96     cmdLen = position.endPos - position.startPos + 1;
97     // cmd include cmd itself and cmd arguments
98     cmd = std::string((char *)&data[position.startPos], cmdLen);
99     if (cmd.compare(0, ATA_LENGTH, "ATA", 0, ATA_LENGTH) == 0) {
100         type = HFP_AG_CMD_EXEC;
101         cmd = "ATA";
102     } else if (cmd.compare(0, ATD_LENGTH, "ATD", 0, ATD_LENGTH) == 0) {
103         type = HFP_AG_CMD_EXEC;
104         arg = std::string(cmd, ATD_LENGTH, cmd.length() - (ATD_LENGTH - 1));
105         cmd = "ATD";
106     } else if (!position.setPos && !position.getPos) {
107         type = HFP_AG_CMD_EXEC;
108         cmd = cmd.substr(0, cmd.length() - (AT_EXEC_OPERATOR_LENGTH + 1));
109     } else if (!position.setPos && position.getPos) {
110         type = HFP_AG_CMD_GET;
111         cmd = cmd.substr(0, cmd.length() - (AT_GET_OPERATOR_LENGTH + 1));
112     } else if (position.setPos && !position.getPos) {
113         type = HFP_AG_CMD_SET;
114         ExtractArg(cmd, arg);
115     } else if (position.setPos == position.getPos - 1) {
116         type = HFP_AG_CMD_TEST;
117         cmd = cmd.substr(0, cmd.length() - (AT_TEST_OPERATOR_LENGTH + 1));
118     } else {
119         type = HFP_AG_CMD_UNKNOWN;
120     }
121     HILOGI(
122         "cmd: %{public}s, arg: %{public}s, type: %{public}d, cmdLen: %{public}zu",
123         cmd.c_str(), arg.c_str(), type, cmdLen);
124     return type;
125 }
126 
GetCommandPosition(const std::vector<uint8_t> & data,size_t len,HfpAgCommandParser::CommandPosition & position) const127 void HfpAgCommandParser::GetCommandPosition(const std::vector<uint8_t> &data,
128                                             size_t len,
129                                             HfpAgCommandParser::CommandPosition &position) const
130 {
131     for (position.pos = 0; position.pos < len; position.pos++) {
132         if (data[position.pos] == 'A' || data[position.pos] == 'a') {
133             if ((position.pos + 1 < (int)len) &&
134                 ((data[position.pos + 1] == 'T') || (data[position.pos + 1] == 't'))) {
135                 position.startPos = position.pos;
136                 position.headValid = true;
137             }
138         }
139 
140         if (data[position.pos] == '=') {
141             position.setPos = position.pos;
142         }
143         if (data[position.pos] == '?') {
144             position.getPos = position.pos;
145         }
146 
147         if (((data[position.pos] == '\r') || (data[position.pos] == '\n')) &&
148             (position.pos > position.startPos) &&
149             (position.headValid)) {
150             position.tailValid = true;
151             position.endPos = position.pos;
152             break;
153         }
154     }
155 }
156 
ExtractArg(std::string & cmd,std::string & arg) const157 void HfpAgCommandParser::ExtractArg(std::string &cmd, std::string &arg) const
158 {
159     for (auto it : g_atCmdMap) {
160         if (cmd.find(it.first) != std::string::npos) {
161             // -2 because '\r' and '=' occupied two chars
162             arg = std::string(cmd, it.first.length() + 1,
163                               cmd.length() - it.first.length() - (AT_SET_OPERATOR_LENGTH + 1));
164             cmd = it.first;
165             break;
166         }
167     }
168     HILOGI("cmd: %{public}s arg: %{public}s", cmd.c_str(), arg.c_str());
169 }
170 }  // namespace bluetooth
171 }  // namespace OHOS