parse static method
Parses a STOMP frame from bytes
Implementation
static StompFrame parse(Uint8List data) {
if (data.isEmpty) {
throw const StompFrameException('Empty frame data');
}
var position = 0;
// Parse command
final commandEnd = _findLineEnd(data, position);
if (commandEnd == -1) {
throw const StompFrameException('No command line found');
}
final command = _extractLine(data, position, commandEnd);
if (command.isEmpty) {
throw const StompFrameException('Empty command');
}
position = commandEnd + 1;
if (position < data.length && data[position - 1] == StompConstants.carriageReturn) {
position++; // Skip LF after CR
}
// Parse headers
final headers = <String, String>{};
while (position < data.length) {
final lineEnd = _findLineEnd(data, position);
if (lineEnd == -1) {
throw const StompFrameException('Malformed headers section');
}
final line = _extractLine(data, position, lineEnd);
// Empty line indicates end of headers
if (line.isEmpty) {
position = lineEnd + 1;
if (position < data.length && data[position - 1] == StompConstants.carriageReturn) {
position++; // Skip LF after CR
}
break;
}
// Parse header
final colonIndex = line.indexOf(':');
if (colonIndex == -1) {
throw StompFrameException('Invalid header format: $line');
}
final name = line.substring(0, colonIndex);
final value = line.substring(colonIndex + 1);
// Handle repeated headers (use first occurrence)
if (!headers.containsKey(name)) {
headers[name] = _shouldEscapeHeaders(command) ? StompEscaping.unescape(value) : value;
}
position = lineEnd + 1;
if (position < data.length && data[position - 1] == StompConstants.carriageReturn) {
position++; // Skip LF after CR
}
}
// Parse body
Uint8List? body;
if (position < data.length) {
// Find NULL terminator
var bodyEnd = data.length;
for (int i = position; i < data.length; i++) {
if (data[i] == StompConstants.nullByte) {
bodyEnd = i;
break;
}
}
if (bodyEnd == data.length) {
throw const StompFrameException('Frame not terminated with NULL byte');
}
// Check content-length if specified
final contentLengthStr = headers[StompHeaders.contentLength];
if (contentLengthStr != null) {
final contentLength = int.tryParse(contentLengthStr);
if (contentLength == null || contentLength < 0) {
throw StompFrameException('Invalid content-length: $contentLengthStr');
}
if (position + contentLength > bodyEnd) {
throw const StompFrameException('Content-length exceeds available body data');
}
bodyEnd = position + contentLength;
}
if (bodyEnd > position) {
body = Uint8List.fromList(data.sublist(position, bodyEnd));
}
}
final frame = StompFrame(
command: command,
headers: headers,
body: body,
);
frame.validate();
return frame;
}