1
0
mirror of https://codeberg.org/Freeyourgadget/Gadgetbridge synced 2024-06-01 19:06:06 +02:00
Gadgetbridge/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/requests/DebugRequest.java
2024-01-07 23:18:08 +01:00

222 lines
8.3 KiB
Java

/* Copyright (C) 2023 Gaignon Damien, MartinJM
This file is part of Gadgetbridge.
Gadgetbridge is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Gadgetbridge is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
package nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests;
import java.util.List;
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.HuaweiConstants;
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.HuaweiPacket;
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.HuaweiTLV;
import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.HuaweiSupportProvider;
import nodomain.freeyourgadget.gadgetbridge.util.GB;
public class DebugRequest extends Request {
public DebugRequest(HuaweiSupportProvider support) {
super(support);
this.serviceId = 0;
this.commandId = 0;
this.addToResponse = false;
}
@Override
protected List<byte[]> createRequest() throws RequestCreationException {
String debugString = GBApplication
.getDeviceSpecificSharedPrefs(supportProvider.getDevice().getAddress())
.getString(HuaweiConstants.PREF_HUAWEI_DEBUG, "1,1,false,(1,/),(2,/),(3,/),(4,/)");
HuaweiPacket packet = parseDebugString(debugString);
try {
return packet.serialize();
} catch (HuaweiPacket.CryptoException e) {
throw new RequestCreationException(e);
}
}
/*
DebugString := [service_id] "," [command id] "," [encryptflag] ("," [tlv])*
service_id := int
| "0x" hex
command_id := int
| "0x" hex
encryptflag := "true"
| "t"
| "false"
| "f"
tlv := "(" [tag] "," [typevalue] ")"
tag := int
| "0x" hex
typevalue := [type] [value]
| [tlv]
type := "/" # Empty tag
| "B" # Byte (1 byte)
| "S" # Short (2 bytes)
| "I" # Integer (4 bytes)
| "b" # Boolean
| "a" # Array of bytes (in hex)
| "-" # String
value := [any]
*/
public HuaweiPacket parseDebugString(String debugString) throws RequestCreationException {
HuaweiPacket packet = new HuaweiPacket(paramsProvider);
int current = 0;
int nextComma = debugString.indexOf(',');
if (nextComma < 1 || debugString.length() - current < 2)
throw new RequestCreationException("Invalid debug command");
if (debugString.charAt(current+1) == 'x')
packet.serviceId = Short.valueOf(debugString.substring(current+2, nextComma), 16).byteValue();
else
packet.serviceId = Short.valueOf(debugString.substring(current, nextComma)).byteValue();
current = nextComma + 1;
nextComma = debugString.indexOf(',', current);
if (nextComma < 1 || debugString.length() - current < 2)
throw new RequestCreationException("Invalid debug command");
if (debugString.charAt(current+1) == 'x')
packet.commandId = Short.valueOf(debugString.substring(current+2, nextComma), 16).byteValue();
else
packet.commandId = Short.valueOf(debugString.substring(current, nextComma)).byteValue();
current = nextComma + 1;
nextComma = debugString.indexOf(',', current);
if (debugString.length() - current < 2)
throw new RequestCreationException("Invalid debug command");
if (nextComma < 0)
nextComma = debugString.length(); // For no TLVs
switch (debugString.substring(current, nextComma)) {
case "true":
case "t":
packet.setEncryption(true);
break;
case "false":
case "f":
packet.setEncryption(false);
break;
default:
throw new RequestCreationException("Boolean is not a boolean");
}
current = nextComma + 1;
if (current < debugString.length()) {
HuaweiTlvParseReturn retv = parseTlv(debugString.substring(current));
if (current + retv.parsedCount != debugString.length())
throw new RequestCreationException("Invalid debug command");
packet.setTlv(retv.tlv);
}
packet.complete = true;
return packet;
}
private HuaweiTlvParseReturn parseTlv(String tlvString) throws RequestCreationException {
HuaweiTLV tlv = new HuaweiTLV();
int current = 0;
int nextDelim;
while (current < tlvString.length()) {
if (tlvString.charAt(current) != '(')
throw new RequestCreationException("Invalid debug command");
current += 1;
nextDelim = tlvString.indexOf(',', current);
if (nextDelim < 1 || tlvString.length() - current < 2)
throw new RequestCreationException("Invalid debug command");
byte tag;
// Short in between is because Java doesn't like unsigned numbers
if (tlvString.charAt(current+1) == 'x')
tag = Short.valueOf(tlvString.substring(current+2, nextDelim), 16).byteValue();
else
tag = Short.valueOf(tlvString.substring(current, nextDelim)).byteValue();
current = nextDelim + 1;
nextDelim = tlvString.indexOf(')', current);
if (nextDelim < 1)
throw new RequestCreationException("Invalid debug command");
if (tlvString.charAt(current) != '(') {
char type = tlvString.charAt(current);
String value = tlvString.substring(current + 1, nextDelim);
switch (type) {
case '/':
tlv.put(tag);
break;
case 'B':
tlv.put(tag, Byte.parseByte(value));
break;
case 'S':
tlv.put(tag, Short.parseShort(value));
break;
case 'I':
tlv.put(tag, Integer.parseInt(value));
break;
case 'b':
tlv.put(tag, value.equals("1"));
break;
case 'a':
tlv.put(tag, GB.hexStringToByteArray(value));
break;
case '-':
tlv.put(tag, value);
break;
default:
throw new RequestCreationException("Invalid tag type");
}
current = nextDelim + 1;
} else {
HuaweiTlvParseReturn retv = parseTlv(tlvString.substring(current));
tlv.put(tag, retv.tlv);
current += retv.parsedCount + 1;
}
if (current == tlvString.length())
break;
if (tlvString.charAt(current) == ')')
break;
if (tlvString.charAt(current) != ',')
throw new RequestCreationException("Invalid debug command");
current += 1;
}
return new HuaweiTlvParseReturn(tlv, current);
}
private static class HuaweiTlvParseReturn {
public HuaweiTLV tlv;
public Integer parsedCount;
HuaweiTlvParseReturn(HuaweiTLV tlv, Integer parsedCount) {
this.tlv = tlv;
this.parsedCount = parsedCount;
}
}
}