Compare commits
3 Commits
9f101abc10
...
16813d67ab
Author | SHA1 | Date | |
---|---|---|---|
16813d67ab
|
|||
f3e07290e3
|
|||
87d2781a0e
|
280
blog/Serializing-data-in-C/index.html
Normal file
280
blog/Serializing-data-in-C/index.html
Normal file
@ -0,0 +1,280 @@
|
|||||||
|
<!DOCTYPE HTML>
|
||||||
|
<html lang="en">
|
||||||
|
<title>'Serializing data in C'</title>
|
||||||
|
<meta name="date" content="2025/07/14">
|
||||||
|
<meta name="colorscheme" content="mellow"></meta>
|
||||||
|
<link rel="stylesheet" href="/style.css">
|
||||||
|
<style>
|
||||||
|
.-spell {}
|
||||||
|
.Number {color: #e29eca}
|
||||||
|
.Function {color: #c1c0d4}
|
||||||
|
.String {color: #90b99f}
|
||||||
|
.Character {color: #90b99f}
|
||||||
|
.PreCondit {color: #ea83a5}
|
||||||
|
.-property {color: #c1c0d4}
|
||||||
|
.Comment {color: #757581; font-style: italic}
|
||||||
|
.Macro {color: #ea83a5}
|
||||||
|
.-type-builtin {color: #e29eca}
|
||||||
|
.Type {color: #b9aeda}
|
||||||
|
.Keyword {color: #aca1cf}
|
||||||
|
.Constant {color: #ea83a5}
|
||||||
|
.-variable-parameter {color: #e29eca}
|
||||||
|
.-punctuation-delimiter {color: #9998a8}
|
||||||
|
.-punctuation-bracket {color: #9998a8}
|
||||||
|
.Include {color: #aca1cf}
|
||||||
|
.Structure {color: #e6b99d}
|
||||||
|
.-variable {color: #c9c7cd}
|
||||||
|
.Operator {color: #e6b99d}
|
||||||
|
</style>
|
||||||
|
<body id="blog">
|
||||||
|
<h1>Serializing data in C</h1>
|
||||||
|
<p>
|
||||||
|
I've started work on a new project! The project in question is one that
|
||||||
|
I have wanted to tackle for a long time but did not have the courage to
|
||||||
|
do so. However at long last it is time...
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
time to get funky...
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
I'm writing a music player, and not one that simply plays music like
|
||||||
|
spotify. This music player falls more inline with MPD in which it's a
|
||||||
|
daemon running in the background playing the music and clients may
|
||||||
|
communicate with it to tell it what to play when and the likes.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Currently I'm at that very important part in which the daemon needs to
|
||||||
|
communicate to clients via a protocol *fancy*, and to do so I have decided
|
||||||
|
to go with a socket that way <i>in theory</i> I can control my daemon from
|
||||||
|
other devices on the network. With the communication method decided I now
|
||||||
|
have to define what data goes between devices. At the current moment I've
|
||||||
|
settled on an enum for different signals.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
As seen here:
|
||||||
|
</p>
|
||||||
|
<pre>
|
||||||
|
<span class="Structure"><span class="Keyword">enum</span></span> <span class="Type">libmoo_signal</span> <span class="-punctuation-bracket">{</span>
|
||||||
|
<span class="Comment"><span class="Comment"><span class="-spell">/* core signals are in the < 100 range */</span></span></span>
|
||||||
|
<span class="-variable"><span class="Constant"><span class="Constant">LIBMOO_SIGNAL_ESTCON</span></span></span> <span class="Operator">=</span> <span class="Number"><span class="Number">1</span></span><span class="-punctuation-delimiter">,</span>
|
||||||
|
<span class="-variable"><span class="Constant"><span class="Constant">LIBMOO_SIGNAL_ESTDCON</span></span></span> <span class="Operator">=</span> <span class="Number"><span class="Number">2</span></span><span class="-punctuation-delimiter">,</span>
|
||||||
|
<span class="-variable"><span class="Constant"><span class="Constant">LIBMOO_SIGNAL_INCOMPATABLE_VERSION</span></span></span> <span class="Operator">=</span> <span class="Number"><span class="Number">3</span></span><span class="-punctuation-delimiter">,</span>
|
||||||
|
|
||||||
|
<span class="-variable"><span class="Constant"><span class="Constant">LIBMOO_SIGNAL_OK</span></span></span> <span class="Operator">=</span> <span class="Number"><span class="Number">50</span></span><span class="-punctuation-delimiter">,</span> <span class="Comment"><span class="Comment"><span class="-spell">/* previous message received was ok */</span></span></span>
|
||||||
|
<span class="-variable"><span class="Constant"><span class="Constant">LIBMOO_SIGNAL_NOK</span></span></span> <span class="Operator">=</span> <span class="Number"><span class="Number">51</span></span><span class="-punctuation-delimiter">,</span> <span class="Comment"><span class="Comment"><span class="-spell">/* previous message received was not ok */</span></span></span>
|
||||||
|
|
||||||
|
<span class="Comment"><span class="Comment"><span class="-spell">/* setting/adding data happens in the 100 range */</span></span></span>
|
||||||
|
<span class="-variable"><span class="Constant"><span class="Constant">LIBMOO_SIGNAL_ADD_SONG</span></span></span> <span class="Operator">=</span> <span class="Number"><span class="Number">101</span></span><span class="-punctuation-delimiter">,</span>
|
||||||
|
<span class="-variable"><span class="Constant"><span class="Constant">LIBMOO_SIGNAL_SET_PLAY</span></span></span> <span class="Operator">=</span> <span class="Number"><span class="Number">103</span></span><span class="-punctuation-delimiter">,</span>
|
||||||
|
<span class="-variable"><span class="Constant"><span class="Constant">LIBMOO_SIGNAL_SET_PAUSE</span></span></span> <span class="Operator">=</span> <span class="Number"><span class="Number">104</span></span><span class="-punctuation-delimiter">,</span>
|
||||||
|
<span class="-variable"><span class="Constant"><span class="Constant">LIBMOO_SIGNAL_SET_TOGGLE_PAUSE</span></span></span> <span class="Operator">=</span> <span class="Number"><span class="Number">105</span></span><span class="-punctuation-delimiter">,</span>
|
||||||
|
<span class="-variable"><span class="Constant"><span class="Constant">LIBMOO_SIGNAL_SET_SKIP_NEXT</span></span></span> <span class="Operator">=</span> <span class="Number"><span class="Number">110</span></span><span class="-punctuation-delimiter">,</span>
|
||||||
|
<span class="-variable"><span class="Constant"><span class="Constant">LIBMOO_SIGNAL_SET_SKIP_PREV</span></span></span> <span class="Operator">=</span> <span class="Number"><span class="Number">111</span></span><span class="-punctuation-delimiter">,</span>
|
||||||
|
|
||||||
|
<span class="Comment"><span class="Comment"><span class="-spell">/* removing data happens in the 200 range */</span></span></span>
|
||||||
|
<span class="-variable"><span class="Constant"><span class="Constant">LIBMOO_SIGNAL_REM_SONG</span></span></span> <span class="Operator">=</span> <span class="Number"><span class="Number">201</span></span><span class="-punctuation-delimiter">,</span>
|
||||||
|
|
||||||
|
<span class="Comment"><span class="Comment"><span class="-spell">/* getting data happens in the 300 range */</span></span></span>
|
||||||
|
<span class="-variable"><span class="Constant"><span class="Constant">LIBMOO_SIGNAL_GET_CUR_SONG</span></span></span> <span class="Operator">=</span> <span class="Number"><span class="Number">301</span></span><span class="-punctuation-delimiter">,</span>
|
||||||
|
<span class="-variable"><span class="Constant"><span class="Constant">LIBMOO_SIGNAL_GET_PAUSE</span></span></span> <span class="Operator">=</span> <span class="Number"><span class="Number">303</span></span><span class="-punctuation-delimiter">,</span>
|
||||||
|
<span class="-variable"><span class="Constant"><span class="Constant">LIBMOO_SIGNAL_GET_PROGRESS</span></span></span> <span class="Operator">=</span> <span class="Number"><span class="Number">310</span></span><span class="-punctuation-delimiter">,</span>
|
||||||
|
<span class="-punctuation-bracket">}</span><span class="-punctuation-delimiter">;</span>
|
||||||
|
</pre>
|
||||||
|
<p>
|
||||||
|
As for how I actually transmit the signals, I've settled on a format which
|
||||||
|
defaults to 42 bytes of data being sent with the option to send more by
|
||||||
|
setting the 41st-42nd bytes to a uint16 containing the additional number
|
||||||
|
of bytes being sent.
|
||||||
|
</p>
|
||||||
|
<pre>
|
||||||
|
<span class="Comment"><span class="Comment"><span class="-spell">/* byte - data</span></span><span class="-spell">
|
||||||
|
<span class="Comment"> *</span>
|
||||||
|
<span class="Comment"> * 0-7 - libmoo protocol version</span>
|
||||||
|
<span class="Comment"> *</span>
|
||||||
|
<span class="Comment"> * 8-31 - reserved for the future</span>
|
||||||
|
<span class="Comment"> *</span>
|
||||||
|
<span class="Comment"> * 32-40 - libmoo_signal</span>
|
||||||
|
<span class="Comment"> *</span>
|
||||||
|
<span class="Comment"> * 41-42 - uint16 more_data</span>
|
||||||
|
<span class="Comment"> *</span>
|
||||||
|
<span class="Comment"> * 43-8191 - char *data</span>
|
||||||
|
<span class="Comment"> */</span></span><span class="Comment"></span></span>
|
||||||
|
<span class="Structure"><span class="Keyword">typedef</span></span> <span class="Type"><span class="-type-builtin">char</span></span> <span class="Operator">*</span> <span class="Type">libmoo_payload</span><span class="-punctuation-delimiter">;</span>
|
||||||
|
</pre>
|
||||||
|
<p>
|
||||||
|
I'm not sure how this compares to other protocols used to transmit data,
|
||||||
|
but I'm quite proud of how I've laid this out.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Moving on to actual the point of this article: serialization. For the sake
|
||||||
|
of useablilty I've defined a datatype which models our payload which you
|
||||||
|
can see here:
|
||||||
|
</p>
|
||||||
|
<pre>
|
||||||
|
<span class="Structure"><span class="Keyword">typedef</span></span> <span class="Structure"><span class="Keyword">struct</span></span> <span class="-punctuation-bracket">{</span>
|
||||||
|
<span class="Structure"><span class="Keyword">enum</span></span> <span class="Type">libmoo_signal</span> <span class="-property">signal</span><span class="-punctuation-delimiter">;</span> <span class="Comment"><span class="Comment"><span class="-spell">/* the signal */</span></span></span>
|
||||||
|
<span class="Type"><span class="-type-builtin">uint16_t</span></span> <span class="-property">more_data</span><span class="-punctuation-delimiter">;</span> <span class="Comment"><span class="Comment"><span class="-spell">/* the number bytes of the additional data */</span></span></span>
|
||||||
|
<span class="Type"><span class="-type-builtin">char</span></span> <span class="Operator">*</span><span class="-property">data</span><span class="-punctuation-delimiter">;</span> <span class="Comment"><span class="Comment"><span class="-spell">/* additional data */</span></span></span>
|
||||||
|
<span class="-punctuation-bracket">}</span> <span class="Type"><span class="Type">libmoo_data</span></span><span class="-punctuation-delimiter">;</span>
|
||||||
|
</pre>
|
||||||
|
<p>
|
||||||
|
And a function which allows you to easily create libmoo_data:
|
||||||
|
</p>
|
||||||
|
<pre>
|
||||||
|
<span class="Comment"><span class="Comment"><span class="-spell"><span class="Comment">/**</span>
|
||||||
|
<span class="Comment"> * @brief create a new libmoo_data</span>
|
||||||
|
<span class="Comment"> *</span>
|
||||||
|
<span class="Comment"> * @param signal the signal to set</span>
|
||||||
|
<span class="Comment"> * @param data the data to set</span>
|
||||||
|
<span class="Comment"> * @return the data object</span>
|
||||||
|
<span class="Comment"> */</span></span></span></span>
|
||||||
|
<span class="Type">libmoo_data</span> <span class="Operator">*</span><span class="-variable"><span class="Function">libmoo_create_data</span></span><span class="-punctuation-bracket">(</span><span class="Structure"><span class="Keyword">enum</span></span> <span class="Type">libmoo_signal</span> <span class="-variable"><span class="-variable-parameter">signal</span></span><span class="-punctuation-delimiter">,</span> <span class="Type"><span class="-type-builtin">char</span></span> <span class="-variable-parameter"><span class="Operator">*</span><span class="-variable">data</span></span><span class="-punctuation-bracket">)</span><span class="-punctuation-delimiter">;</span>
|
||||||
|
</pre>
|
||||||
|
<p>
|
||||||
|
I've provided this so that you don't have to deal with manually setting
|
||||||
|
the size of the data that you pass into the object, although (if you so
|
||||||
|
choose) you may easily override it.
|
||||||
|
</p>
|
||||||
|
<h2>Serializing</h2>
|
||||||
|
<p>
|
||||||
|
Now that we've gone over the interface for interacting with the payload
|
||||||
|
let's get to the intersting stage in which we get the data ready for
|
||||||
|
launch.
|
||||||
|
</p>
|
||||||
|
<pre>
|
||||||
|
<span class="Comment"><span class="Comment"><span class="-spell"><span class="Comment">/**</span>
|
||||||
|
<span class="Comment"> * @brief convert data into a payload.</span>
|
||||||
|
<span class="Comment"> * The payload must be allocated prior to calling this function it should be</span>
|
||||||
|
<span class="Comment"> * LIBMOO_PAYLOAD_SIZE chars long unless you think you know better.</span>
|
||||||
|
<span class="Comment"> *</span>
|
||||||
|
<span class="Comment"> * @param payload pointer to the payload</span>
|
||||||
|
<span class="Comment"> * @param data data which will be serialized</span>
|
||||||
|
<span class="Comment"> * @return the size of the resulting payload</span>
|
||||||
|
<span class="Comment"> */</span></span></span></span>
|
||||||
|
<span class="Type"><span class="-type-builtin">size_t</span></span>
|
||||||
|
<span class="-variable"><span class="Function">libmoo_serialize_data</span></span><span class="-punctuation-bracket">(</span><span class="Type">libmoo_payload</span> <span class="-variable"><span class="-variable-parameter">payload</span></span><span class="-punctuation-delimiter">,</span> <span class="Type">libmoo_data</span> <span class="-variable-parameter"><span class="Operator">*</span><span class="-variable">data</span></span><span class="-punctuation-bracket">)</span>
|
||||||
|
<span class="-punctuation-bracket">{</span>
|
||||||
|
<span class="Type"><span class="-type-builtin">void</span></span> <span class="Operator">*</span><span class="-variable">ptr</span><span class="-punctuation-delimiter">;</span>
|
||||||
|
|
||||||
|
<span class="-variable">ptr</span> <span class="Operator">=</span> <span class="-variable">payload</span><span class="-punctuation-delimiter">;</span>
|
||||||
|
|
||||||
|
<span class="Comment"><span class="Comment"><span class="-spell">/* add LIBMOO_VERSION */</span></span></span>
|
||||||
|
<span class="-variable"><span class="Function">mempcpy</span></span><span class="-punctuation-bracket">(</span><span class="-variable">ptr</span><span class="-punctuation-delimiter">,</span> <span class="-variable"><span class="Constant">LIBMOO_VERSION</span></span><span class="-punctuation-delimiter">,</span> <span class="-variable"><span class="Function">strlen</span></span><span class="-punctuation-bracket">(</span><span class="-variable"><span class="Constant">LIBMOO_VERSION</span></span><span class="-punctuation-bracket">)</span><span class="-punctuation-bracket">)</span><span class="-punctuation-delimiter">;</span>
|
||||||
|
|
||||||
|
<span class="Comment"><span class="Comment"><span class="-spell">/* skip the reserved space */</span></span></span>
|
||||||
|
<span class="-variable">ptr</span> <span class="Operator">+=</span> <span class="Number"><span class="Number">24</span></span><span class="-punctuation-delimiter">;</span>
|
||||||
|
|
||||||
|
<span class="Comment"><span class="Comment"><span class="-spell">/* add the signal type */</span></span></span>
|
||||||
|
<span class="-variable"><span class="Function">mempcpy</span></span><span class="-punctuation-bracket">(</span><span class="-variable">ptr</span><span class="-punctuation-delimiter">,</span> <span class="Operator">&</span><span class="-_parent"><span class="-variable">data</span><span class="Operator">-></span><span class="-property">signal</span></span><span class="-punctuation-delimiter">,</span> <span class="Operator"><span class="Keyword">sizeof</span></span><span class="-punctuation-bracket">(</span><span class="-_parent"><span class="-variable">data</span><span class="Operator">-></span><span class="-property">signal</span></span><span class="-punctuation-bracket">)</span><span class="-punctuation-bracket">)</span><span class="-punctuation-delimiter">;</span>
|
||||||
|
|
||||||
|
<span class="Comment"><span class="Comment"><span class="-spell">/* add the size of the more data */</span></span></span>
|
||||||
|
<span class="-variable"><span class="Function">mempcpy</span></span><span class="-punctuation-bracket">(</span><span class="-variable">ptr</span><span class="-punctuation-delimiter">,</span> <span class="Operator">&</span><span class="-_parent"><span class="-variable">data</span><span class="Operator">-></span><span class="-property">more_data</span></span><span class="-punctuation-delimiter">,</span> <span class="Operator"><span class="Keyword">sizeof</span></span><span class="-punctuation-bracket">(</span><span class="-_parent"><span class="-variable">data</span><span class="Operator">-></span><span class="-property">more_data</span></span><span class="-punctuation-bracket">)</span><span class="-punctuation-bracket">)</span><span class="-punctuation-delimiter">;</span>
|
||||||
|
|
||||||
|
<span class="Comment"><span class="Comment"><span class="-spell">/* the more data */</span></span></span>
|
||||||
|
<span class="Conditional"><span class="Keyword">if</span></span> <span class="-punctuation-bracket">(</span><span class="-_parent"><span class="-variable">data</span><span class="Operator">-></span><span class="-property">more_data</span></span><span class="-punctuation-bracket">)</span> <span class="-punctuation-bracket">{</span>
|
||||||
|
<span class="-variable"><span class="Function">mempcpy</span></span><span class="-punctuation-bracket">(</span><span class="-variable">ptr</span><span class="-punctuation-delimiter">,</span> <span class="-_parent"><span class="-variable">data</span><span class="Operator">-></span><span class="-property">data</span></span><span class="-punctuation-delimiter">,</span> <span class="-variable"><span class="Function">strlen</span></span><span class="-punctuation-bracket">(</span><span class="-_parent"><span class="-variable">data</span><span class="Operator">-></span><span class="-property">data</span></span><span class="-punctuation-bracket">)</span><span class="-punctuation-bracket">)</span><span class="-punctuation-delimiter">;</span>
|
||||||
|
<span class="-punctuation-bracket">}</span>
|
||||||
|
|
||||||
|
<span class="Statement"><span class="Keyword">return</span></span> <span class="-variable"><span class="Constant">LIBMOO_HEADER_SIZE</span></span> <span class="Operator">+</span> <span class="Operator"><span class="Keyword">sizeof</span></span><span class="-punctuation-bracket">(</span><span class="-_parent"><span class="-variable">data</span><span class="Operator">-></span><span class="-property">more_data</span></span><span class="-punctuation-bracket">)</span> <span class="Operator">+</span> <span class="-_parent"><span class="-variable">data</span><span class="Operator">-></span><span class="-property">more_data</span></span><span class="-punctuation-delimiter">;</span>
|
||||||
|
<span class="-punctuation-bracket">}</span>
|
||||||
|
</pre>
|
||||||
|
<p>
|
||||||
|
As you may have noticed in the code snippet above libmoo_serialize_data is
|
||||||
|
a function that takes in a pre-allocated payload, and the data to
|
||||||
|
serialize. I've opted to allow the user to allocate space for the payload
|
||||||
|
if they determine that they know what they're doing incase my dumb
|
||||||
|
function is too generous. Moving onto the body of the function you'll see
|
||||||
|
an unfamiliar function called mempcpy which is a macro for copying data
|
||||||
|
into the payload. This macro takes in the same arguments as memcpy (dest,
|
||||||
|
src, size), but in addition it increments dest by size so I can append
|
||||||
|
data to the payload without making this code horrible to read.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
In earlier stages of development I didn't actually return the size of the
|
||||||
|
resulting payload, thinking that I could just strlen it. This was a rookie
|
||||||
|
mistake. Because I've included extra space (bytes 8-31) when you run
|
||||||
|
strlen on any payload it results in 5 (the length of the version string).
|
||||||
|
After finding this out I decided that I do actually want to send more
|
||||||
|
than the version information, and so now libmoo_serialize_data returns a
|
||||||
|
size_t continaing the number of bytes that have been serialized.
|
||||||
|
</p>
|
||||||
|
<h2>Deserializing</h2>
|
||||||
|
<p>
|
||||||
|
Now that we've serialized and <i>presumably</i> sent the data to a client
|
||||||
|
we need to do the magic part which completes this transaction:
|
||||||
|
deserialization.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Below is my method of deserializing the data. It's pretty much the
|
||||||
|
opposite of the serialization function with the key exception that we
|
||||||
|
need to do some validation. <i>Which I haven't implemented yet.</i>
|
||||||
|
</p>
|
||||||
|
<pre>
|
||||||
|
<span class="Type">libmoo_data</span>
|
||||||
|
<span class="Operator">*</span><span class="-variable"><span class="Function">libmoo_deserialize_data</span></span><span class="-punctuation-bracket">(</span><span class="Type">libmoo_payload</span> <span class="-variable"><span class="-variable-parameter">payload</span></span><span class="-punctuation-delimiter">,</span> <span class="Type"><span class="-type-builtin">unsigned</span></span> <span class="Type"><span class="-type-builtin"><span class="-type-builtin">int</span></span></span> <span class="-variable"><span class="-variable-parameter">payload_size</span></span><span class="-punctuation-bracket">)</span>
|
||||||
|
<span class="-punctuation-bracket">{</span>
|
||||||
|
<span class="Type">libmoo_data</span> <span class="Operator">*</span><span class="-variable">data</span><span class="-punctuation-delimiter">;</span>
|
||||||
|
<span class="Type"><span class="-type-builtin">char</span></span> <span class="-variable">libmoo_version</span><span class="-punctuation-bracket">[</span><span class="-variable"><span class="Constant">LIBMOO_VERSION_LEN</span></span> <span class="Operator">+</span> <span class="Number"><span class="Number">1</span></span><span class="-punctuation-bracket">]</span><span class="-punctuation-delimiter">;</span>
|
||||||
|
|
||||||
|
<span class="Comment"><span class="Comment"><span class="-spell">/* ensure that there's enough data to comply to spec */</span></span></span>
|
||||||
|
<span class="Conditional"><span class="Keyword">if</span></span> <span class="-punctuation-bracket">(</span><span class="-variable">payload_size</span> <span class="Operator"><</span> <span class="-variable"><span class="Constant">LIBMOO_HEADER_SIZE</span></span><span class="-punctuation-bracket">)</span> <span class="-punctuation-bracket">{</span>
|
||||||
|
<span class="-variable">errno</span> <span class="Operator">=</span> <span class="-variable"><span class="Constant">EBADE</span></span><span class="-punctuation-delimiter">;</span>
|
||||||
|
<span class="Statement"><span class="Keyword">return</span></span> <span class="Constant"><span class="-constant-builtin">NULL</span></span><span class="-punctuation-delimiter">;</span>
|
||||||
|
<span class="-punctuation-bracket">}</span>
|
||||||
|
|
||||||
|
<span class="Comment"><span class="Comment"><span class="-spell">/* attempt to allocate space and if we fail return NULL errno contains the</span></span><span class="-spell">
|
||||||
|
<span class="Comment"> * error</span>
|
||||||
|
<span class="Comment"> */</span></span><span class="Comment"></span></span>
|
||||||
|
<span class="-variable">data</span> <span class="Operator">=</span> <span class="-variable"><span class="Function">calloc</span></span><span class="-punctuation-bracket">(</span><span class="Number"><span class="Number">1</span></span><span class="-punctuation-delimiter">,</span> <span class="Operator"><span class="Keyword">sizeof</span></span><span class="-punctuation-bracket">(</span><span class="-variable">libmoo_data</span><span class="-punctuation-bracket">)</span><span class="-punctuation-bracket">)</span><span class="-punctuation-delimiter">;</span>
|
||||||
|
<span class="Conditional"><span class="Keyword">if</span></span> <span class="-punctuation-bracket">(</span><span class="-variable">data</span> <span class="Operator">==</span> <span class="Constant"><span class="-constant-builtin">NULL</span></span><span class="-punctuation-bracket">)</span> <span class="-punctuation-bracket">{</span>
|
||||||
|
<span class="-variable">errno</span> <span class="Operator">=</span> <span class="Constant"><span class="-variable"><span class="Constant">ENOMEM</span></span></span><span class="-punctuation-delimiter">;</span>
|
||||||
|
<span class="Statement"><span class="Keyword">return</span></span> <span class="Constant"><span class="-constant-builtin">NULL</span></span><span class="-punctuation-delimiter">;</span>
|
||||||
|
<span class="-punctuation-bracket">}</span>
|
||||||
|
|
||||||
|
<span class="Comment"><span class="Comment"><span class="-spell">/* get the libmoo_version */</span></span></span>
|
||||||
|
<span class="-variable"><span class="Function">memscpy</span></span><span class="-punctuation-bracket">(</span><span class="-variable">libmoo_version</span><span class="-punctuation-delimiter">,</span> <span class="-variable">payload</span><span class="-punctuation-delimiter">,</span> <span class="-variable"><span class="Constant">LIBMOO_VERSION_LEN</span></span><span class="-punctuation-bracket">)</span><span class="-punctuation-delimiter">;</span>
|
||||||
|
<span class="-variable">libmoo_version</span><span class="-punctuation-bracket">[</span><span class="-variable"><span class="Constant">LIBMOO_VERSION_LEN</span></span><span class="-punctuation-bracket">]</span> <span class="Operator">=</span> <span class="SpecialChar"><span class="Character">'<span class="-string-escape">\0</span>'</span></span><span class="-punctuation-delimiter">;</span>
|
||||||
|
|
||||||
|
<span class="Comment"><span class="Comment"><span class="-spell">/*<span class="TodoBgNOTE"> </span></span></span><span class="-spell"><span class="TodoBgNOTE"><span class="Todo">TODO</span><span class="Comment"><span class="TodoFgNOTE">:</span></span></span><span class="Comment"><span class="TodoFgNOTE"> check that the version of the library we're talking to and our</span></span>
|
||||||
|
<span class="Comment"> * <span class="TodoFgNOTE">version are compatable</span></span>
|
||||||
|
<span class="Comment"> */</span></span><span class="Comment"></span></span>
|
||||||
|
|
||||||
|
<span class="Comment"><span class="Comment"><span class="-spell">/* gotta tell the client that we're incompatible */</span></span></span>
|
||||||
|
<span class="Conditional"><span class="Keyword">if</span></span> <span class="-punctuation-bracket">(</span><span class="-variable"><span class="Function">strcmp</span></span><span class="-punctuation-bracket">(</span><span class="-variable">libmoo_version</span><span class="-punctuation-delimiter">,</span> <span class="-variable"><span class="Constant">LIBMOO_VERSION</span></span><span class="-punctuation-bracket">)</span> <span class="Operator">!=</span> <span class="Number"><span class="Number">0</span></span><span class="-punctuation-bracket">)</span> <span class="-punctuation-bracket">{</span>
|
||||||
|
<span class="-variable">errno</span> <span class="Operator">=</span> <span class="Constant"><span class="-variable"><span class="Constant">EINVAL</span></span></span><span class="-punctuation-delimiter">;</span>
|
||||||
|
<span class="-variable"><span class="Function">free</span></span><span class="-punctuation-bracket">(</span><span class="-variable">data</span><span class="-punctuation-bracket">)</span><span class="-punctuation-delimiter">;</span>
|
||||||
|
<span class="Statement"><span class="Keyword">return</span></span> <span class="Constant"><span class="-constant-builtin">NULL</span></span><span class="-punctuation-delimiter">;</span>
|
||||||
|
<span class="-punctuation-bracket">}</span>
|
||||||
|
|
||||||
|
<span class="Comment"><span class="Comment"><span class="-spell">/* skip the reserved space */</span></span></span>
|
||||||
|
<span class="-variable">payload</span> <span class="Operator">+=</span> <span class="Number"><span class="Number">24</span></span><span class="-punctuation-delimiter">;</span>
|
||||||
|
|
||||||
|
<span class="Comment"><span class="Comment"><span class="-spell">/* get the signal */</span></span></span>
|
||||||
|
<span class="-variable"><span class="Function">memscpy</span></span><span class="-punctuation-bracket">(</span><span class="Operator">&</span><span class="-_parent"><span class="-variable">data</span><span class="Operator">-></span><span class="-property">signal</span></span><span class="-punctuation-delimiter">,</span> <span class="-variable">payload</span><span class="-punctuation-delimiter">,</span> <span class="Operator"><span class="Keyword">sizeof</span></span><span class="-punctuation-bracket">(</span><span class="-_parent"><span class="-variable">data</span><span class="Operator">-></span><span class="-property">signal</span></span><span class="-punctuation-bracket">)</span><span class="-punctuation-bracket">)</span><span class="-punctuation-delimiter">;</span>
|
||||||
|
|
||||||
|
<span class="Comment"><span class="Comment"><span class="-spell">/* get the more data marker */</span></span></span>
|
||||||
|
<span class="-variable"><span class="Function">memscpy</span></span><span class="-punctuation-bracket">(</span><span class="Operator">&</span><span class="-_parent"><span class="-variable">data</span><span class="Operator">-></span><span class="-property">more_data</span></span><span class="-punctuation-delimiter">,</span> <span class="-variable">payload</span><span class="-punctuation-delimiter">,</span> <span class="Operator"><span class="Keyword">sizeof</span></span><span class="-punctuation-bracket">(</span><span class="-_parent"><span class="-variable">data</span><span class="Operator">-></span><span class="-property">more_data</span></span><span class="-punctuation-bracket">)</span><span class="-punctuation-bracket">)</span><span class="-punctuation-delimiter">;</span>
|
||||||
|
|
||||||
|
<span class="Comment"><span class="Comment"><span class="-spell">/* get the data */</span></span></span>
|
||||||
|
<span class="Conditional"><span class="Keyword">if</span></span> <span class="-punctuation-bracket">(</span><span class="-_parent"><span class="-variable">data</span><span class="Operator">-></span><span class="-property">more_data</span></span><span class="-punctuation-bracket">)</span> <span class="-punctuation-bracket">{</span>
|
||||||
|
<span class="-_parent"><span class="-variable">data</span><span class="Operator">-></span><span class="-property">data</span></span> <span class="Operator">=</span> <span class="-variable"><span class="Function">malloc</span></span><span class="-punctuation-bracket">(</span><span class="-punctuation-bracket">(</span><span class="-_parent"><span class="-variable">data</span><span class="Operator">-></span><span class="-property">more_data</span></span> <span class="Operator">+</span> <span class="Number"><span class="Number">1</span></span><span class="-punctuation-bracket">)</span> <span class="Operator">*</span> <span class="Operator"><span class="Keyword">sizeof</span></span><span class="-punctuation-bracket">(</span><span class="Type"><span class="Type"><span class="-type-builtin">char</span></span></span><span class="-punctuation-bracket">)</span><span class="-punctuation-bracket">)</span><span class="-punctuation-delimiter">;</span>
|
||||||
|
<span class="-variable"><span class="Function">memscpy</span></span><span class="-punctuation-bracket">(</span><span class="-_parent"><span class="-variable">data</span><span class="Operator">-></span><span class="-property">data</span></span><span class="-punctuation-delimiter">,</span> <span class="-variable">payload</span><span class="-punctuation-delimiter">,</span> <span class="-_parent"><span class="-variable">data</span><span class="Operator">-></span><span class="-property">more_data</span></span> <span class="Operator">*</span> <span class="Operator"><span class="Keyword">sizeof</span></span><span class="-punctuation-bracket">(</span><span class="Type"><span class="Type"><span class="-type-builtin">char</span></span></span><span class="-punctuation-bracket">)</span><span class="-punctuation-bracket">)</span><span class="-punctuation-delimiter">;</span>
|
||||||
|
<span class="-_parent"><span class="-variable">data</span><span class="Operator">-></span><span class="-property">data</span></span><span class="-punctuation-bracket">[</span><span class="-_parent"><span class="-variable">data</span><span class="Operator">-></span><span class="-property">more_data</span></span><span class="-punctuation-bracket">]</span> <span class="Operator">=</span> <span class="SpecialChar"><span class="Character">'<span class="-string-escape">\0</span>'</span></span><span class="-punctuation-delimiter">;</span> <span class="Comment"><span class="Comment"><span class="-spell">/* null terminate this string, yo */</span></span></span>
|
||||||
|
<span class="-punctuation-bracket">}</span>
|
||||||
|
|
||||||
|
<span class="Statement"><span class="Keyword">return</span></span> <span class="-variable">data</span><span class="-punctuation-delimiter">;</span>
|
||||||
|
<span class="-punctuation-bracket">}</span>
|
||||||
|
</pre>
|
||||||
|
<p>
|
||||||
|
And that's kinda it just like with the mempcpy macro I've made a memscpy
|
||||||
|
macro which increments the src by the size of the data to make reading
|
||||||
|
the data easy.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
See you next year o/
|
||||||
|
<sub>I might have my project done by then, who knows</sub>
|
||||||
|
</p>
|
||||||
|
<br>
|
||||||
|
<br>
|
||||||
|
</body>
|
||||||
|
</html>
|
@ -1,35 +0,0 @@
|
|||||||
<!DOCTYPE HTML>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<title>Squibid's Blog</title>
|
|
||||||
<link rel="stylesheet" href="/style.css">
|
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
||||||
</head>
|
|
||||||
<style type="text/css">
|
|
||||||
#bloglist {
|
|
||||||
text-align: left;
|
|
||||||
font-size: 2ch;
|
|
||||||
}
|
|
||||||
p#bloglist span {
|
|
||||||
float: right;
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
<body style="background-color: #161617;">
|
|
||||||
<div id="master">
|
|
||||||
<header>
|
|
||||||
<h1 id="font", style="margin-bottom: 0">
|
|
||||||
<a href="/">Squibid's</a> Blog
|
|
||||||
</h1>
|
|
||||||
</header>
|
|
||||||
<hr style="color: #f7f7f7;">
|
|
||||||
<p id="bloglist">
|
|
||||||
<?php include(__DIR__.'/../misc/tools.php'); blog_entries("../blog"); ?>
|
|
||||||
</p>
|
|
||||||
<h2 id="font" style="text-align: center; margin-top: 0;">
|
|
||||||
<a href="/blog/rss.xml", title="rss">subscribe</a>
|
|
||||||
</h2>
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
267
blog/rss.xml
267
blog/rss.xml
@ -11,6 +11,273 @@
|
|||||||
|
|
||||||
<!-- LB -->
|
<!-- LB -->
|
||||||
|
|
||||||
|
<item>
|
||||||
|
<title> 'Serializing data in C'</title>
|
||||||
|
<guid>https://squi.bid/blog/Serializing-data-in-C/index.html</guid>
|
||||||
|
<link>https://squi.bid/blog/Serializing-data-in-C/index.html</link>
|
||||||
|
<pubDate>Sat, 09 Aug 2025 08:50:12 -0400</pubDate>
|
||||||
|
<description><![CDATA[<!DOCTYPE HTML>
|
||||||
|
<html lang="en">
|
||||||
|
<title>'Serializing data in C'</title>
|
||||||
|
<meta name="date" content="2025/07/14">
|
||||||
|
<meta name="colorscheme" content="mellow"></meta>
|
||||||
|
<link rel="stylesheet" href="/style.css">
|
||||||
|
<style>
|
||||||
|
.-spell {}
|
||||||
|
.Number {color: #e29eca}
|
||||||
|
.Function {color: #c1c0d4}
|
||||||
|
.String {color: #90b99f}
|
||||||
|
.Character {color: #90b99f}
|
||||||
|
.PreCondit {color: #ea83a5}
|
||||||
|
.-property {color: #c1c0d4}
|
||||||
|
.Comment {color: #757581; font-style: italic}
|
||||||
|
.Macro {color: #ea83a5}
|
||||||
|
.-type-builtin {color: #e29eca}
|
||||||
|
.Type {color: #b9aeda}
|
||||||
|
.Keyword {color: #aca1cf}
|
||||||
|
.Constant {color: #ea83a5}
|
||||||
|
.-variable-parameter {color: #e29eca}
|
||||||
|
.-punctuation-delimiter {color: #9998a8}
|
||||||
|
.-punctuation-bracket {color: #9998a8}
|
||||||
|
.Include {color: #aca1cf}
|
||||||
|
.Structure {color: #e6b99d}
|
||||||
|
.-variable {color: #c9c7cd}
|
||||||
|
.Operator {color: #e6b99d}
|
||||||
|
</style>
|
||||||
|
<body id="blog">
|
||||||
|
<h1>Serializing data in C</h1>
|
||||||
|
<p>
|
||||||
|
I've started work on a new project! The project in question is one that
|
||||||
|
I have wanted to tackle for a long time but did not have the courage to
|
||||||
|
do so. However at long last it is time...
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
time to get funky...
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
I'm writing a music player, and not one that simply plays music like
|
||||||
|
spotify. This music player falls more inline with MPD in which it's a
|
||||||
|
daemon running in the background playing the music and clients may
|
||||||
|
communicate with it to tell it what to play when and the likes.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Currently I'm at that very important part in which the daemon needs to
|
||||||
|
communicate to clients via a protocol *fancy*, and to do so I have decided
|
||||||
|
to go with a socket that way <i>in theory</i> I can control my daemon from
|
||||||
|
other devices on the network. With the communication method decided I now
|
||||||
|
have to define what data goes between devices. At the current moment I've
|
||||||
|
settled on an enum for different signals.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
As seen here:
|
||||||
|
</p>
|
||||||
|
<pre>
|
||||||
|
<span class="Structure"><span class="Keyword">enum</span></span> <span class="Type">libmoo_signal</span> <span class="-punctuation-bracket">{</span>
|
||||||
|
<span class="Comment"><span class="Comment"><span class="-spell">/* core signals are in the < 100 range */</span></span></span>
|
||||||
|
<span class="-variable"><span class="Constant"><span class="Constant">LIBMOO_SIGNAL_ESTCON</span></span></span> <span class="Operator">=</span> <span class="Number"><span class="Number">1</span></span><span class="-punctuation-delimiter">,</span>
|
||||||
|
<span class="-variable"><span class="Constant"><span class="Constant">LIBMOO_SIGNAL_ESTDCON</span></span></span> <span class="Operator">=</span> <span class="Number"><span class="Number">2</span></span><span class="-punctuation-delimiter">,</span>
|
||||||
|
<span class="-variable"><span class="Constant"><span class="Constant">LIBMOO_SIGNAL_INCOMPATABLE_VERSION</span></span></span> <span class="Operator">=</span> <span class="Number"><span class="Number">3</span></span><span class="-punctuation-delimiter">,</span>
|
||||||
|
<span class="-variable"><span class="Constant"><span class="Constant">LIBMOO_SIGNAL_OK</span></span></span> <span class="Operator">=</span> <span class="Number"><span class="Number">50</span></span><span class="-punctuation-delimiter">,</span> <span class="Comment"><span class="Comment"><span class="-spell">/* previous message received was ok */</span></span></span>
|
||||||
|
<span class="-variable"><span class="Constant"><span class="Constant">LIBMOO_SIGNAL_NOK</span></span></span> <span class="Operator">=</span> <span class="Number"><span class="Number">51</span></span><span class="-punctuation-delimiter">,</span> <span class="Comment"><span class="Comment"><span class="-spell">/* previous message received was not ok */</span></span></span>
|
||||||
|
<span class="Comment"><span class="Comment"><span class="-spell">/* setting/adding data happens in the 100 range */</span></span></span>
|
||||||
|
<span class="-variable"><span class="Constant"><span class="Constant">LIBMOO_SIGNAL_ADD_SONG</span></span></span> <span class="Operator">=</span> <span class="Number"><span class="Number">101</span></span><span class="-punctuation-delimiter">,</span>
|
||||||
|
<span class="-variable"><span class="Constant"><span class="Constant">LIBMOO_SIGNAL_SET_PLAY</span></span></span> <span class="Operator">=</span> <span class="Number"><span class="Number">103</span></span><span class="-punctuation-delimiter">,</span>
|
||||||
|
<span class="-variable"><span class="Constant"><span class="Constant">LIBMOO_SIGNAL_SET_PAUSE</span></span></span> <span class="Operator">=</span> <span class="Number"><span class="Number">104</span></span><span class="-punctuation-delimiter">,</span>
|
||||||
|
<span class="-variable"><span class="Constant"><span class="Constant">LIBMOO_SIGNAL_SET_TOGGLE_PAUSE</span></span></span> <span class="Operator">=</span> <span class="Number"><span class="Number">105</span></span><span class="-punctuation-delimiter">,</span>
|
||||||
|
<span class="-variable"><span class="Constant"><span class="Constant">LIBMOO_SIGNAL_SET_SKIP_NEXT</span></span></span> <span class="Operator">=</span> <span class="Number"><span class="Number">110</span></span><span class="-punctuation-delimiter">,</span>
|
||||||
|
<span class="-variable"><span class="Constant"><span class="Constant">LIBMOO_SIGNAL_SET_SKIP_PREV</span></span></span> <span class="Operator">=</span> <span class="Number"><span class="Number">111</span></span><span class="-punctuation-delimiter">,</span>
|
||||||
|
<span class="Comment"><span class="Comment"><span class="-spell">/* removing data happens in the 200 range */</span></span></span>
|
||||||
|
<span class="-variable"><span class="Constant"><span class="Constant">LIBMOO_SIGNAL_REM_SONG</span></span></span> <span class="Operator">=</span> <span class="Number"><span class="Number">201</span></span><span class="-punctuation-delimiter">,</span>
|
||||||
|
<span class="Comment"><span class="Comment"><span class="-spell">/* getting data happens in the 300 range */</span></span></span>
|
||||||
|
<span class="-variable"><span class="Constant"><span class="Constant">LIBMOO_SIGNAL_GET_CUR_SONG</span></span></span> <span class="Operator">=</span> <span class="Number"><span class="Number">301</span></span><span class="-punctuation-delimiter">,</span>
|
||||||
|
<span class="-variable"><span class="Constant"><span class="Constant">LIBMOO_SIGNAL_GET_PAUSE</span></span></span> <span class="Operator">=</span> <span class="Number"><span class="Number">303</span></span><span class="-punctuation-delimiter">,</span>
|
||||||
|
<span class="-variable"><span class="Constant"><span class="Constant">LIBMOO_SIGNAL_GET_PROGRESS</span></span></span> <span class="Operator">=</span> <span class="Number"><span class="Number">310</span></span><span class="-punctuation-delimiter">,</span>
|
||||||
|
<span class="-punctuation-bracket">}</span><span class="-punctuation-delimiter">;</span>
|
||||||
|
</pre>
|
||||||
|
<p>
|
||||||
|
As for how I actually transmit the signals, I've settled on a format which
|
||||||
|
defaults to 42 bytes of data being sent with the option to send more by
|
||||||
|
setting the 41st-42nd bytes to a uint16 containing the additional number
|
||||||
|
of bytes being sent.
|
||||||
|
</p>
|
||||||
|
<pre>
|
||||||
|
<span class="Comment"><span class="Comment"><span class="-spell">/* byte - data</span></span><span class="-spell">
|
||||||
|
<span class="Comment"> *</span>
|
||||||
|
<span class="Comment"> * 0-7 - libmoo protocol version</span>
|
||||||
|
<span class="Comment"> *</span>
|
||||||
|
<span class="Comment"> * 8-31 - reserved for the future</span>
|
||||||
|
<span class="Comment"> *</span>
|
||||||
|
<span class="Comment"> * 32-40 - libmoo_signal</span>
|
||||||
|
<span class="Comment"> *</span>
|
||||||
|
<span class="Comment"> * 41-42 - uint16 more_data</span>
|
||||||
|
<span class="Comment"> *</span>
|
||||||
|
<span class="Comment"> * 43-8191 - char *data</span>
|
||||||
|
<span class="Comment"> */</span></span><span class="Comment"></span></span>
|
||||||
|
<span class="Structure"><span class="Keyword">typedef</span></span> <span class="Type"><span class="-type-builtin">char</span></span> <span class="Operator">*</span> <span class="Type">libmoo_payload</span><span class="-punctuation-delimiter">;</span>
|
||||||
|
</pre>
|
||||||
|
<p>
|
||||||
|
I'm not sure how this compares to other protocols used to transmit data,
|
||||||
|
but I'm quite proud of how I've laid this out.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Moving on to actual the point of this article: serialization. For the sake
|
||||||
|
of useablilty I've defined a datatype which models our payload which you
|
||||||
|
can see here:
|
||||||
|
</p>
|
||||||
|
<pre>
|
||||||
|
<span class="Structure"><span class="Keyword">typedef</span></span> <span class="Structure"><span class="Keyword">struct</span></span> <span class="-punctuation-bracket">{</span>
|
||||||
|
<span class="Structure"><span class="Keyword">enum</span></span> <span class="Type">libmoo_signal</span> <span class="-property">signal</span><span class="-punctuation-delimiter">;</span> <span class="Comment"><span class="Comment"><span class="-spell">/* the signal */</span></span></span>
|
||||||
|
<span class="Type"><span class="-type-builtin">uint16_t</span></span> <span class="-property">more_data</span><span class="-punctuation-delimiter">;</span> <span class="Comment"><span class="Comment"><span class="-spell">/* the number bytes of the additional data */</span></span></span>
|
||||||
|
<span class="Type"><span class="-type-builtin">char</span></span> <span class="Operator">*</span><span class="-property">data</span><span class="-punctuation-delimiter">;</span> <span class="Comment"><span class="Comment"><span class="-spell">/* additional data */</span></span></span>
|
||||||
|
<span class="-punctuation-bracket">}</span> <span class="Type"><span class="Type">libmoo_data</span></span><span class="-punctuation-delimiter">;</span>
|
||||||
|
</pre>
|
||||||
|
<p>
|
||||||
|
And a function which allows you to easily create libmoo_data:
|
||||||
|
</p>
|
||||||
|
<pre>
|
||||||
|
<span class="Comment"><span class="Comment"><span class="-spell"><span class="Comment">/**</span>
|
||||||
|
<span class="Comment"> * @brief create a new libmoo_data</span>
|
||||||
|
<span class="Comment"> *</span>
|
||||||
|
<span class="Comment"> * @param signal the signal to set</span>
|
||||||
|
<span class="Comment"> * @param data the data to set</span>
|
||||||
|
<span class="Comment"> * @return the data object</span>
|
||||||
|
<span class="Comment"> */</span></span></span></span>
|
||||||
|
<span class="Type">libmoo_data</span> <span class="Operator">*</span><span class="-variable"><span class="Function">libmoo_create_data</span></span><span class="-punctuation-bracket">(</span><span class="Structure"><span class="Keyword">enum</span></span> <span class="Type">libmoo_signal</span> <span class="-variable"><span class="-variable-parameter">signal</span></span><span class="-punctuation-delimiter">,</span> <span class="Type"><span class="-type-builtin">char</span></span> <span class="-variable-parameter"><span class="Operator">*</span><span class="-variable">data</span></span><span class="-punctuation-bracket">)</span><span class="-punctuation-delimiter">;</span>
|
||||||
|
</pre>
|
||||||
|
<p>
|
||||||
|
I've provided this so that you don't have to deal with manually setting
|
||||||
|
the size of the data that you pass into the object, although (if you so
|
||||||
|
choose) you may easily override it.
|
||||||
|
</p>
|
||||||
|
<h2>Serializing</h2>
|
||||||
|
<p>
|
||||||
|
Now that we've gone over the interface for interacting with the payload
|
||||||
|
let's get to the intersting stage in which we get the data ready for
|
||||||
|
launch.
|
||||||
|
</p>
|
||||||
|
<pre>
|
||||||
|
<span class="Comment"><span class="Comment"><span class="-spell"><span class="Comment">/**</span>
|
||||||
|
<span class="Comment"> * @brief convert data into a payload.</span>
|
||||||
|
<span class="Comment"> * The payload must be allocated prior to calling this function it should be</span>
|
||||||
|
<span class="Comment"> * LIBMOO_PAYLOAD_SIZE chars long unless you think you know better.</span>
|
||||||
|
<span class="Comment"> *</span>
|
||||||
|
<span class="Comment"> * @param payload pointer to the payload</span>
|
||||||
|
<span class="Comment"> * @param data data which will be serialized</span>
|
||||||
|
<span class="Comment"> * @return the size of the resulting payload</span>
|
||||||
|
<span class="Comment"> */</span></span></span></span>
|
||||||
|
<span class="Type"><span class="-type-builtin">size_t</span></span>
|
||||||
|
<span class="-variable"><span class="Function">libmoo_serialize_data</span></span><span class="-punctuation-bracket">(</span><span class="Type">libmoo_payload</span> <span class="-variable"><span class="-variable-parameter">payload</span></span><span class="-punctuation-delimiter">,</span> <span class="Type">libmoo_data</span> <span class="-variable-parameter"><span class="Operator">*</span><span class="-variable">data</span></span><span class="-punctuation-bracket">)</span>
|
||||||
|
<span class="-punctuation-bracket">{</span>
|
||||||
|
<span class="Type"><span class="-type-builtin">void</span></span> <span class="Operator">*</span><span class="-variable">ptr</span><span class="-punctuation-delimiter">;</span>
|
||||||
|
<span class="-variable">ptr</span> <span class="Operator">=</span> <span class="-variable">payload</span><span class="-punctuation-delimiter">;</span>
|
||||||
|
<span class="Comment"><span class="Comment"><span class="-spell">/* add LIBMOO_VERSION */</span></span></span>
|
||||||
|
<span class="-variable"><span class="Function">mempcpy</span></span><span class="-punctuation-bracket">(</span><span class="-variable">ptr</span><span class="-punctuation-delimiter">,</span> <span class="-variable"><span class="Constant">LIBMOO_VERSION</span></span><span class="-punctuation-delimiter">,</span> <span class="-variable"><span class="Function">strlen</span></span><span class="-punctuation-bracket">(</span><span class="-variable"><span class="Constant">LIBMOO_VERSION</span></span><span class="-punctuation-bracket">)</span><span class="-punctuation-bracket">)</span><span class="-punctuation-delimiter">;</span>
|
||||||
|
<span class="Comment"><span class="Comment"><span class="-spell">/* skip the reserved space */</span></span></span>
|
||||||
|
<span class="-variable">ptr</span> <span class="Operator">+=</span> <span class="Number"><span class="Number">24</span></span><span class="-punctuation-delimiter">;</span>
|
||||||
|
<span class="Comment"><span class="Comment"><span class="-spell">/* add the signal type */</span></span></span>
|
||||||
|
<span class="-variable"><span class="Function">mempcpy</span></span><span class="-punctuation-bracket">(</span><span class="-variable">ptr</span><span class="-punctuation-delimiter">,</span> <span class="Operator">&</span><span class="-_parent"><span class="-variable">data</span><span class="Operator">-></span><span class="-property">signal</span></span><span class="-punctuation-delimiter">,</span> <span class="Operator"><span class="Keyword">sizeof</span></span><span class="-punctuation-bracket">(</span><span class="-_parent"><span class="-variable">data</span><span class="Operator">-></span><span class="-property">signal</span></span><span class="-punctuation-bracket">)</span><span class="-punctuation-bracket">)</span><span class="-punctuation-delimiter">;</span>
|
||||||
|
<span class="Comment"><span class="Comment"><span class="-spell">/* add the size of the more data */</span></span></span>
|
||||||
|
<span class="-variable"><span class="Function">mempcpy</span></span><span class="-punctuation-bracket">(</span><span class="-variable">ptr</span><span class="-punctuation-delimiter">,</span> <span class="Operator">&</span><span class="-_parent"><span class="-variable">data</span><span class="Operator">-></span><span class="-property">more_data</span></span><span class="-punctuation-delimiter">,</span> <span class="Operator"><span class="Keyword">sizeof</span></span><span class="-punctuation-bracket">(</span><span class="-_parent"><span class="-variable">data</span><span class="Operator">-></span><span class="-property">more_data</span></span><span class="-punctuation-bracket">)</span><span class="-punctuation-bracket">)</span><span class="-punctuation-delimiter">;</span>
|
||||||
|
<span class="Comment"><span class="Comment"><span class="-spell">/* the more data */</span></span></span>
|
||||||
|
<span class="Conditional"><span class="Keyword">if</span></span> <span class="-punctuation-bracket">(</span><span class="-_parent"><span class="-variable">data</span><span class="Operator">-></span><span class="-property">more_data</span></span><span class="-punctuation-bracket">)</span> <span class="-punctuation-bracket">{</span>
|
||||||
|
<span class="-variable"><span class="Function">mempcpy</span></span><span class="-punctuation-bracket">(</span><span class="-variable">ptr</span><span class="-punctuation-delimiter">,</span> <span class="-_parent"><span class="-variable">data</span><span class="Operator">-></span><span class="-property">data</span></span><span class="-punctuation-delimiter">,</span> <span class="-variable"><span class="Function">strlen</span></span><span class="-punctuation-bracket">(</span><span class="-_parent"><span class="-variable">data</span><span class="Operator">-></span><span class="-property">data</span></span><span class="-punctuation-bracket">)</span><span class="-punctuation-bracket">)</span><span class="-punctuation-delimiter">;</span>
|
||||||
|
<span class="-punctuation-bracket">}</span>
|
||||||
|
<span class="Statement"><span class="Keyword">return</span></span> <span class="-variable"><span class="Constant">LIBMOO_HEADER_SIZE</span></span> <span class="Operator">+</span> <span class="Operator"><span class="Keyword">sizeof</span></span><span class="-punctuation-bracket">(</span><span class="-_parent"><span class="-variable">data</span><span class="Operator">-></span><span class="-property">more_data</span></span><span class="-punctuation-bracket">)</span> <span class="Operator">+</span> <span class="-_parent"><span class="-variable">data</span><span class="Operator">-></span><span class="-property">more_data</span></span><span class="-punctuation-delimiter">;</span>
|
||||||
|
<span class="-punctuation-bracket">}</span>
|
||||||
|
</pre>
|
||||||
|
<p>
|
||||||
|
As you may have noticed in the code snippet above libmoo_serialize_data is
|
||||||
|
a function that takes in a pre-allocated payload, and the data to
|
||||||
|
serialize. I've opted to allow the user to allocate space for the payload
|
||||||
|
if they determine that they know what they're doing incase my dumb
|
||||||
|
function is too generous. Moving onto the body of the function you'll see
|
||||||
|
an unfamiliar function called mempcpy which is a macro for copying data
|
||||||
|
into the payload. This macro takes in the same arguments as memcpy (dest,
|
||||||
|
src, size), but in addition it increments dest by size so I can append
|
||||||
|
data to the payload without making this code horrible to read.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
In earlier stages of development I didn't actually return the size of the
|
||||||
|
resulting payload, thinking that I could just strlen it. This was a rookie
|
||||||
|
mistake. Because I've included extra space (bytes 8-31) when you run
|
||||||
|
strlen on any payload it results in 5 (the length of the version string).
|
||||||
|
After finding this out I decided that I do actually want to send more
|
||||||
|
than the version information, and so now libmoo_serialize_data returns a
|
||||||
|
size_t continaing the number of bytes that have been serialized.
|
||||||
|
</p>
|
||||||
|
<h2>Deserializing</h2>
|
||||||
|
<p>
|
||||||
|
Now that we've serialized and <i>presumably</i> sent the data to a client
|
||||||
|
we need to do the magic part which completes this transaction:
|
||||||
|
deserialization.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Below is my method of deserializing the data. It's pretty much the
|
||||||
|
opposite of the serialization function with the key exception that we
|
||||||
|
need to do some validation. <i>Which I haven't implemented yet.</i>
|
||||||
|
</p>
|
||||||
|
<pre>
|
||||||
|
<span class="Type">libmoo_data</span>
|
||||||
|
<span class="Operator">*</span><span class="-variable"><span class="Function">libmoo_deserialize_data</span></span><span class="-punctuation-bracket">(</span><span class="Type">libmoo_payload</span> <span class="-variable"><span class="-variable-parameter">payload</span></span><span class="-punctuation-delimiter">,</span> <span class="Type"><span class="-type-builtin">unsigned</span></span> <span class="Type"><span class="-type-builtin"><span class="-type-builtin">int</span></span></span> <span class="-variable"><span class="-variable-parameter">payload_size</span></span><span class="-punctuation-bracket">)</span>
|
||||||
|
<span class="-punctuation-bracket">{</span>
|
||||||
|
<span class="Type">libmoo_data</span> <span class="Operator">*</span><span class="-variable">data</span><span class="-punctuation-delimiter">;</span>
|
||||||
|
<span class="Type"><span class="-type-builtin">char</span></span> <span class="-variable">libmoo_version</span><span class="-punctuation-bracket">[</span><span class="-variable"><span class="Constant">LIBMOO_VERSION_LEN</span></span> <span class="Operator">+</span> <span class="Number"><span class="Number">1</span></span><span class="-punctuation-bracket">]</span><span class="-punctuation-delimiter">;</span>
|
||||||
|
<span class="Comment"><span class="Comment"><span class="-spell">/* ensure that there's enough data to comply to spec */</span></span></span>
|
||||||
|
<span class="Conditional"><span class="Keyword">if</span></span> <span class="-punctuation-bracket">(</span><span class="-variable">payload_size</span> <span class="Operator"><</span> <span class="-variable"><span class="Constant">LIBMOO_HEADER_SIZE</span></span><span class="-punctuation-bracket">)</span> <span class="-punctuation-bracket">{</span>
|
||||||
|
<span class="-variable">errno</span> <span class="Operator">=</span> <span class="-variable"><span class="Constant">EBADE</span></span><span class="-punctuation-delimiter">;</span>
|
||||||
|
<span class="Statement"><span class="Keyword">return</span></span> <span class="Constant"><span class="-constant-builtin">NULL</span></span><span class="-punctuation-delimiter">;</span>
|
||||||
|
<span class="-punctuation-bracket">}</span>
|
||||||
|
<span class="Comment"><span class="Comment"><span class="-spell">/* attempt to allocate space and if we fail return NULL errno contains the</span></span><span class="-spell">
|
||||||
|
<span class="Comment"> * error</span>
|
||||||
|
<span class="Comment"> */</span></span><span class="Comment"></span></span>
|
||||||
|
<span class="-variable">data</span> <span class="Operator">=</span> <span class="-variable"><span class="Function">calloc</span></span><span class="-punctuation-bracket">(</span><span class="Number"><span class="Number">1</span></span><span class="-punctuation-delimiter">,</span> <span class="Operator"><span class="Keyword">sizeof</span></span><span class="-punctuation-bracket">(</span><span class="-variable">libmoo_data</span><span class="-punctuation-bracket">)</span><span class="-punctuation-bracket">)</span><span class="-punctuation-delimiter">;</span>
|
||||||
|
<span class="Conditional"><span class="Keyword">if</span></span> <span class="-punctuation-bracket">(</span><span class="-variable">data</span> <span class="Operator">==</span> <span class="Constant"><span class="-constant-builtin">NULL</span></span><span class="-punctuation-bracket">)</span> <span class="-punctuation-bracket">{</span>
|
||||||
|
<span class="-variable">errno</span> <span class="Operator">=</span> <span class="Constant"><span class="-variable"><span class="Constant">ENOMEM</span></span></span><span class="-punctuation-delimiter">;</span>
|
||||||
|
<span class="Statement"><span class="Keyword">return</span></span> <span class="Constant"><span class="-constant-builtin">NULL</span></span><span class="-punctuation-delimiter">;</span>
|
||||||
|
<span class="-punctuation-bracket">}</span>
|
||||||
|
<span class="Comment"><span class="Comment"><span class="-spell">/* get the libmoo_version */</span></span></span>
|
||||||
|
<span class="-variable"><span class="Function">memscpy</span></span><span class="-punctuation-bracket">(</span><span class="-variable">libmoo_version</span><span class="-punctuation-delimiter">,</span> <span class="-variable">payload</span><span class="-punctuation-delimiter">,</span> <span class="-variable"><span class="Constant">LIBMOO_VERSION_LEN</span></span><span class="-punctuation-bracket">)</span><span class="-punctuation-delimiter">;</span>
|
||||||
|
<span class="-variable">libmoo_version</span><span class="-punctuation-bracket">[</span><span class="-variable"><span class="Constant">LIBMOO_VERSION_LEN</span></span><span class="-punctuation-bracket">]</span> <span class="Operator">=</span> <span class="SpecialChar"><span class="Character">'<span class="-string-escape"> |