From f2cc4393278cd1d41a8b360b72eea55b5b4e63c4 Mon Sep 17 00:00:00 2001 From: forge-bot Date: Sat, 18 Jul 2026 11:09:17 +0000 Subject: [PATCH] =?UTF-8?q?[=EA=B3=B5=ED=86=B5]=20util=20=E2=86=92=20frame?= =?UTF-8?q?work=20=EC=9C=A0=ED=8B=B8=20(ACM-CM-002)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../framework/util/MessageUtil.java | 145 ++++++++++++++++++ 1 file changed, 145 insertions(+) create mode 100644 boot/common-framework/src/main/java/com/klaro/acquirecore/framework/util/MessageUtil.java diff --git a/boot/common-framework/src/main/java/com/klaro/acquirecore/framework/util/MessageUtil.java b/boot/common-framework/src/main/java/com/klaro/acquirecore/framework/util/MessageUtil.java new file mode 100644 index 0000000..00ab3fd --- /dev/null +++ b/boot/common-framework/src/main/java/com/klaro/acquirecore/framework/util/MessageUtil.java @@ -0,0 +1,145 @@ +package com.klaro.acquirecore.framework.util; + +import java.nio.charset.StandardCharsets; +import java.util.Base64; + +/** + * Static utility class for message/frame processing migrated from legacy C code. + * Provides encoding, decoding, and checksum operations for message frames. + */ +public final class MessageUtil { + + private static final int HEADER_SIZE = 4; + private static final int MAX_MESSAGE_SIZE = 4096; + private static final String DELIMITER = "|"; + + private MessageUtil() { + // Utility class - prevent instantiation + } + + public static String encode(String type, byte[] payload) { + if (type == null || type.isBlank()) { + return null; + } + int length = (payload != null) ? payload.length : 0; + String header = String.format("%s%s%d%s", padRight(type, HEADER_SIZE), DELIMITER, length, DELIMITER); + if (payload == null || payload.length == 0) { + return header; + } + return header + new String(payload, StandardCharsets.UTF_8); + } + + public static String encode(String type, String payload) { + if (payload == null) { + return encode(type, (byte[]) null); + } + return encode(type, payload.getBytes(StandardCharsets.UTF_8)); + } + + public static MessageFrame decode(String message) { + if (message == null || message.isBlank()) { + return null; + } + int firstDelim = message.indexOf(DELIMITER); + if (firstDelim < 0 || firstDelim > HEADER_SIZE) { + return null; + } + String type = message.substring(0, firstDelim).trim(); + int secondDelim = message.indexOf(DELIMITER, firstDelim + 1); + if (secondDelim < 0) { + return null; + } + String lengthStr = message.substring(firstDelim + 1, secondDelim).trim(); + int length; + try { + length = Integer.parseInt(lengthStr); + } catch (NumberFormatException e) { + return null; + } + String payloadStr = message.substring(secondDelim + 1); + byte[] payload = payloadStr.getBytes(StandardCharsets.UTF_8); + return new MessageFrame(type, length, payload); + } + + public static int checksum(byte[] payload) { + if (payload == null || payload.length == 0) { + return 0; + } + int sum = 0; + for (byte b : payload) { + sum += (b & 0xFF); + } + return sum & 0xFFFF; + } + + public static int checksum(String payload) { + if (payload == null || payload.isEmpty()) { + return 0; + } + return checksum(payload.getBytes(StandardCharsets.UTF_8)); + } + + public static String encodeBase64(byte[] data) { + if (data == null) { + return null; + } + return Base64.getEncoder().encodeToString(data); + } + + public static byte[] decodeBase64(String encoded) { + if (encoded == null || encoded.isBlank()) { + return null; + } + try { + return Base64.getDecoder().decode(encoded); + } catch (IllegalArgumentException e) { + return null; + } + } + + public static boolean isValidSize(String message) { + return message != null && message.length() <= MAX_MESSAGE_SIZE; + } + + private static String padRight(String str, int length) { + if (str == null) { + str = ""; + } + if (str.length() >= length) { + return str.substring(0, length); + } + StringBuilder sb = new StringBuilder(str); + while (sb.length() < length) { + sb.append(' '); + } + return sb.toString(); + } + + public static final class MessageFrame { + private final String type; + private final int length; + private final byte[] payload; + + public MessageFrame(String type, int length, byte[] payload) { + this.type = type; + this.length = length; + this.payload = payload; + } + + public String getType() { return type; } + public int getLength() { return length; } + public byte[] getPayload() { return payload; } + + public String getPayloadAsString() { + if (payload == null) { + return ""; + } + return new String(payload, StandardCharsets.UTF_8); + } + + @Override + public String toString() { + return String.format("MessageFrame{type='%s', length=%d, payload=%s}", type, length, getPayloadAsString()); + } + } +}