1 /**
2  * Standalone encoding/decoding functions
3  */
4 module bformat.marshall;
5 
6 /** 
7  * Decodes the provided bformat message into the
8  * message itself
9  *
10  * Params:
11  *   bformatBytes = the bformat payload the decode
12  * Returns: the decoded message
13  */
14 public byte[] decodeMessage(byte[] bformatBytes)
15 {
16 	/* Construct a buffer to receive into */
17 	byte[] receiveBuffer;
18 
19 	/* Get the length of the message */
20 	byte[4] messageLengthBytes = bformatBytes[0..4];
21 
22 	/* Response message length */
23 	uint messageLength;
24 
25 	/* Little endian version you simply read if off the bone (it's already in the correct order) */
26 	version(LittleEndian)
27 	{
28 		messageLength = *cast(int*)messageLengthBytes.ptr;
29 	}
30 
31 	/* Big endian requires we byte-sapped the little-endian encoded number */
32 	version(BigEndian)
33 	{
34 		byte[] swappedLength;
35 		swappedLength.length = 4;
36 
37 		swappedLength[0] = messageLengthBytes[3];
38 		swappedLength[1] = messageLengthBytes[2];
39 		swappedLength[2] = messageLengthBytes[1];
40 		swappedLength[3] = messageLengthBytes[0];
41 
42 		messageLength = *cast(int*)swappedLength.ptr;
43 	}
44 
45 
46 	/* Read the full message */
47 	receiveBuffer = bformatBytes[4..4+messageLength];
48 
49 	return receiveBuffer;
50 }
51 
52 /** 
53  * Encodes the provided message into the bformat format
54  *
55  * Params:
56  *   message = the buffer containing bytes to encode
57  * Returns: the encoded payload
58  */
59 public byte[] encodeBformat(byte[] message)
60 {
61 	/* The message buffer */
62 	byte[] messageBuffer;
63 
64 	/* Encode the 4 byte message length header (little endian) */
65 	int payloadLength = cast(int)message.length;
66 	byte* lengthBytes = cast(byte*)&payloadLength;
67 
68 	/* On little endian simply get the bytes as is (it would be encoded as little endian) */
69 	version(LittleEndian)
70 	{
71 		messageBuffer ~= *(lengthBytes+0);
72 		messageBuffer ~= *(lengthBytes+1);
73 		messageBuffer ~= *(lengthBytes+2);
74 		messageBuffer ~= *(lengthBytes+3);
75 	}
76 
77 	/* On Big Endian you must swap the big-endian-encoded number to be in little endian ordering */
78 	version(BigEndian)
79 	{
80 		messageBuffer ~= *(lengthBytes+3);
81 		messageBuffer ~= *(lengthBytes+2);
82 		messageBuffer ~= *(lengthBytes+1);
83 		messageBuffer ~= *(lengthBytes+0);
84 	}
85 	
86 
87 	/* Add the message to the buffer */
88 	messageBuffer ~= cast(byte[])message;
89 
90 	return messageBuffer;
91 }
92 
93 version(unittest)
94 {
95     import std.string : cmp;
96 }
97 
98 unittest
99 {
100     string message = "This is my message";
101     byte[] bformatEncoded = encodeBformat(cast(byte[])message);
102 
103     byte[] decodedMessageBytes = decodeMessage(bformatEncoded);
104     string decodedMessage = cast(string)decodedMessageBytes;
105 
106     assert(cmp(message, decodedMessage) == 0);
107 }