/* Copyright (C) 2019-2021 Daniel Dakhno 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 . */ package nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.buttonconfig; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.util.ArrayList; import java.util.Arrays; import java.util.zip.CRC32; public class ConfigFileBuilder { private ConfigPayload[] configs; public ConfigFileBuilder(ConfigPayload[] configs) { this.configs = configs; } public byte[] build(boolean appendChecksum) { int payloadSize = 0; for (ConfigPayload payload : this.configs) { payloadSize += payload.getData().length; } int headerSize = 0; for (ConfigPayload payload : this.configs) { headerSize += payload.getHeader().length + 3; // button + version + null; } ByteBuffer buffer = ByteBuffer.allocate( 3 // version bytes + 1 // header count byte + headerSize + 1 // payload count byte + payloadSize + 1 // customization count byte + (appendChecksum ? 4 : 0) // checksum ); buffer.order(ByteOrder.LITTLE_ENDIAN); buffer.put(new byte[]{(byte) 0x01, (byte) 0x00, (byte) 0x00}); // version buffer.put((byte) this.configs.length); int buttonIndex = 0x00; for (ConfigPayload payload : configs) { buffer.put((byte) (buttonIndex += 0x10)); buffer.put((byte) 0x01); buffer.put(payload.getHeader()); buffer.put((byte) 0x00); } ArrayList distinctPayloads = new ArrayList<>(3); // distinctPayloads.add(configs[0].getData()); compareLoop: for (int payloadIndex = 0; payloadIndex < configs.length; payloadIndex++) { for (int compareTo = 0; compareTo < distinctPayloads.size(); compareTo++) { if (configs[payloadIndex].equals(distinctPayloads.get(compareTo))) { continue compareLoop; } } distinctPayloads.add(configs[payloadIndex]); } buffer.put((byte) distinctPayloads.size()); for (ConfigPayload payload : distinctPayloads) { buffer.put(payload.getData()); } buffer.put((byte) 0x00); ByteBuffer buffer2 = ByteBuffer.allocate(buffer.position() + (appendChecksum ? 4 : 0)); buffer2.order(ByteOrder.LITTLE_ENDIAN); buffer2.put(buffer.array(), 0, buffer.position()); if (!appendChecksum) return buffer2.array(); CRC32 crc = new CRC32(); crc.update(buffer.array(), 0, buffer.position()); buffer2.putInt((int) crc.getValue()); return buffer2.array(); } }