diff --git a/blog/Serializing-data-in-C/index.html b/blog/Serializing-data-in-C/index.html new file mode 100644 index 0000000..cdba0c4 --- /dev/null +++ b/blog/Serializing-data-in-C/index.html @@ -0,0 +1,280 @@ + + + 'Serializing data in C' + + + + + +

Serializing data in C

+

+ 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... +

+

+ time to get funky... +

+

+ 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. +

+

+ 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 in theory 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. +

+

+ As seen here: +

+
+enum libmoo_signal {
+  /* core signals are in the < 100 range */
+  LIBMOO_SIGNAL_ESTCON = 1,
+  LIBMOO_SIGNAL_ESTDCON = 2,
+  LIBMOO_SIGNAL_INCOMPATABLE_VERSION = 3,
+
+  LIBMOO_SIGNAL_OK = 50, /* previous message received was ok */
+  LIBMOO_SIGNAL_NOK = 51, /* previous message received was not ok */
+
+  /* setting/adding data happens in the 100 range */
+  LIBMOO_SIGNAL_ADD_SONG = 101,
+  LIBMOO_SIGNAL_SET_PLAY = 103,
+  LIBMOO_SIGNAL_SET_PAUSE = 104,
+  LIBMOO_SIGNAL_SET_TOGGLE_PAUSE = 105,
+  LIBMOO_SIGNAL_SET_SKIP_NEXT = 110,
+  LIBMOO_SIGNAL_SET_SKIP_PREV = 111,
+
+  /* removing data happens in the 200 range */
+  LIBMOO_SIGNAL_REM_SONG = 201,
+
+  /* getting data happens in the 300 range */
+  LIBMOO_SIGNAL_GET_CUR_SONG = 301,
+  LIBMOO_SIGNAL_GET_PAUSE = 303,
+  LIBMOO_SIGNAL_GET_PROGRESS = 310,
+};
+    
+

+ 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. +

+
+/* byte - data
+ *
+ * 0-7  - libmoo protocol version
+ *
+ * 8-31  - reserved for the future
+ *
+ * 32-40 - libmoo_signal
+ *
+ * 41-42 - uint16 more_data
+ *
+ * 43-8191 - char *data
+ */
+typedef char * libmoo_payload;
+    
+

+ 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. +

+

+ 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: +

+
+typedef struct {
+  enum libmoo_signal signal; /* the signal */
+  uint16_t           more_data; /* the number bytes of the additional data */
+  char              *data; /* additional data */
+} libmoo_data;
+    
+

+ And a function which allows you to easily create libmoo_data: +

+
+/**
+ * @brief create a new libmoo_data
+ *
+ * @param signal the signal to set
+ * @param data the data to set
+ * @return the data object
+ */
+libmoo_data *libmoo_create_data(enum libmoo_signal signal, char *data);
+    
+

+ 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. +

+

Serializing

+

+ 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. +

+
+/**
+ * @brief convert data into a payload.
+ * The payload must be allocated prior to calling this function it should be
+ * LIBMOO_PAYLOAD_SIZE chars long unless you think you know better.
+ *
+ * @param payload pointer to the payload
+ * @param data data which will be serialized
+ * @return the size of the resulting payload
+ */
+size_t
+libmoo_serialize_data(libmoo_payload payload, libmoo_data *data)
+{
+  void *ptr;
+
+  ptr = payload;
+
+  /* add LIBMOO_VERSION */
+  mempcpy(ptr, LIBMOO_VERSION, strlen(LIBMOO_VERSION));
+
+  /* skip the reserved space */
+  ptr += 24;
+
+  /* add the signal type */
+  mempcpy(ptr, &data->signal, sizeof(data->signal));
+
+  /* add the size of the more data */
+  mempcpy(ptr, &data->more_data, sizeof(data->more_data));
+
+  /* the more data */
+  if (data->more_data) {
+    mempcpy(ptr, data->data, strlen(data->data));
+  }
+
+  return LIBMOO_HEADER_SIZE + sizeof(data->more_data) + data->more_data;
+}
+    
+

+ 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. +

+

+ 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. +

+

Deserializing

+

+ Now that we've serialized and presumably sent the data to a client + we need to do the magic part which completes this transaction: + deserialization. +

+

+ 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. Which I haven't implemented yet. +

+
+libmoo_data
+*libmoo_deserialize_data(libmoo_payload payload, unsigned int payload_size)
+{
+  libmoo_data *data;
+  char libmoo_version[LIBMOO_VERSION_LEN + 1];
+
+  /* ensure that there's enough data to comply to spec */
+  if (payload_size < LIBMOO_HEADER_SIZE) {
+    errno = EBADE;
+    return NULL;
+  }
+
+  /* attempt to allocate space and if we fail return NULL errno contains the
+   * error
+   */
+  data = calloc(1, sizeof(libmoo_data));
+  if (data == NULL) {
+    errno = ENOMEM;
+    return NULL;
+  }
+
+  /* get the libmoo_version */
+  memscpy(libmoo_version, payload, LIBMOO_VERSION_LEN);
+  libmoo_version[LIBMOO_VERSION_LEN] = '\0';
+
+  /* TODO: check that the version of the library we're talking to and our
+   * version are compatable
+   */
+
+  /* gotta tell the client that we're incompatible */
+  if (strcmp(libmoo_version, LIBMOO_VERSION) != 0) {
+    errno = EINVAL;
+    free(data);
+    return NULL;
+  }
+
+  /* skip the reserved space */
+  payload += 24;
+
+  /* get the signal */
+  memscpy(&data->signal, payload, sizeof(data->signal));
+
+  /* get the more data marker */
+  memscpy(&data->more_data, payload, sizeof(data->more_data));
+
+  /* get the data */
+  if (data->more_data) {
+    data->data = malloc((data->more_data + 1) * sizeof(char));
+    memscpy(data->data, payload, data->more_data * sizeof(char));
+    data->data[data->more_data] = '\0'; /* null terminate this string, yo */
+  }
+
+  return data;
+}
+    
+

+ 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. +

+

+ See you next year o/ + I might have my project done by then, who knows +

+
+
+ + diff --git a/blog/index.php b/blog/index.php deleted file mode 100644 index 945c1f3..0000000 --- a/blog/index.php +++ /dev/null @@ -1,35 +0,0 @@ - - - - Squibid's Blog - - - - - - -
-
-

- Squibid's Blog -

-
-
-

- -

-

- subscribe -

-
- - diff --git a/blog/rss.xml b/blog/rss.xml index 2eef69a..63a1ae5 100644 --- a/blog/rss.xml +++ b/blog/rss.xml @@ -11,6 +11,273 @@ + + 'Serializing data in C' +https://squi.bid/blog/Serializing-data-in-C/index.html +https://squi.bid/blog/Serializing-data-in-C/index.html +Sat, 09 Aug 2025 08:50:12 -0400 + + + 'Serializing data in C' + + + + + +

Serializing data in C

+

+ 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... +

+

+ time to get funky... +

+

+ 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. +

+

+ 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 in theory 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. +

+

+ As seen here: +

+
+enum libmoo_signal {
+  /* core signals are in the < 100 range */
+  LIBMOO_SIGNAL_ESTCON = 1,
+  LIBMOO_SIGNAL_ESTDCON = 2,
+  LIBMOO_SIGNAL_INCOMPATABLE_VERSION = 3,
+  LIBMOO_SIGNAL_OK = 50, /* previous message received was ok */
+  LIBMOO_SIGNAL_NOK = 51, /* previous message received was not ok */
+  /* setting/adding data happens in the 100 range */
+  LIBMOO_SIGNAL_ADD_SONG = 101,
+  LIBMOO_SIGNAL_SET_PLAY = 103,
+  LIBMOO_SIGNAL_SET_PAUSE = 104,
+  LIBMOO_SIGNAL_SET_TOGGLE_PAUSE = 105,
+  LIBMOO_SIGNAL_SET_SKIP_NEXT = 110,
+  LIBMOO_SIGNAL_SET_SKIP_PREV = 111,
+  /* removing data happens in the 200 range */
+  LIBMOO_SIGNAL_REM_SONG = 201,
+  /* getting data happens in the 300 range */
+  LIBMOO_SIGNAL_GET_CUR_SONG = 301,
+  LIBMOO_SIGNAL_GET_PAUSE = 303,
+  LIBMOO_SIGNAL_GET_PROGRESS = 310,
+};
+    
+

+ 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. +

+
+/* byte - data
+ *
+ * 0-7  - libmoo protocol version
+ *
+ * 8-31  - reserved for the future
+ *
+ * 32-40 - libmoo_signal
+ *
+ * 41-42 - uint16 more_data
+ *
+ * 43-8191 - char *data
+ */
+typedef char * libmoo_payload;
+    
+

+ 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. +

+

+ 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: +

+
+typedef struct {
+  enum libmoo_signal signal; /* the signal */
+  uint16_t           more_data; /* the number bytes of the additional data */
+  char              *data; /* additional data */
+} libmoo_data;
+    
+

+ And a function which allows you to easily create libmoo_data: +

+
+/**
+ * @brief create a new libmoo_data
+ *
+ * @param signal the signal to set
+ * @param data the data to set
+ * @return the data object
+ */
+libmoo_data *libmoo_create_data(enum libmoo_signal signal, char *data);
+    
+

+ 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. +

+

Serializing

+

+ 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. +

+
+/**
+ * @brief convert data into a payload.
+ * The payload must be allocated prior to calling this function it should be
+ * LIBMOO_PAYLOAD_SIZE chars long unless you think you know better.
+ *
+ * @param payload pointer to the payload
+ * @param data data which will be serialized
+ * @return the size of the resulting payload
+ */
+size_t
+libmoo_serialize_data(libmoo_payload payload, libmoo_data *data)
+{
+  void *ptr;
+  ptr = payload;
+  /* add LIBMOO_VERSION */
+  mempcpy(ptr, LIBMOO_VERSION, strlen(LIBMOO_VERSION));
+  /* skip the reserved space */
+  ptr += 24;
+  /* add the signal type */
+  mempcpy(ptr, &data->signal, sizeof(data->signal));
+  /* add the size of the more data */
+  mempcpy(ptr, &data->more_data, sizeof(data->more_data));
+  /* the more data */
+  if (data->more_data) {
+    mempcpy(ptr, data->data, strlen(data->data));
+  }
+  return LIBMOO_HEADER_SIZE + sizeof(data->more_data) + data->more_data;
+}
+    
+

+ 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. +

+

+ 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. +

+

Deserializing

+

+ Now that we've serialized and presumably sent the data to a client + we need to do the magic part which completes this transaction: + deserialization. +

+

+ 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. Which I haven't implemented yet. +

+
+libmoo_data
+*libmoo_deserialize_data(libmoo_payload payload, unsigned int payload_size)
+{
+  libmoo_data *data;
+  char libmoo_version[LIBMOO_VERSION_LEN + 1];
+  /* ensure that there's enough data to comply to spec */
+  if (payload_size < LIBMOO_HEADER_SIZE) {
+    errno = EBADE;
+    return NULL;
+  }
+  /* attempt to allocate space and if we fail return NULL errno contains the
+   * error
+   */
+  data = calloc(1, sizeof(libmoo_data));
+  if (data == NULL) {
+    errno = ENOMEM;
+    return NULL;
+  }
+  /* get the libmoo_version */
+  memscpy(libmoo_version, payload, LIBMOO_VERSION_LEN);
+  libmoo_version[LIBMOO_VERSION_LEN] = '';
+  /* TODO: check that the version of the library we're talking to and our
+   * version are compatable
+   */
+  /* gotta tell the client that we're incompatible */
+  if (strcmp(libmoo_version, LIBMOO_VERSION) != 0) {
+    errno = EINVAL;
+    free(data);
+    return NULL;
+  }
+  /* skip the reserved space */
+  payload += 24;
+  /* get the signal */
+  memscpy(&data->signal, payload, sizeof(data->signal));
+  /* get the more data marker */
+  memscpy(&data->more_data, payload, sizeof(data->more_data));
+  /* get the data */
+  if (data->more_data) {
+    data->data = malloc((data->more_data + 1) * sizeof(char));
+    memscpy(data->data, payload, data->more_data * sizeof(char));
+    data->data[data->more_data] = ''; /* null terminate this string, yo */
+  }
+  return data;
+}
+    
+

+ 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. +

+

+ See you next year o/ + I might have my project done by then, who knows +

+
+
+ +]]>
+
+ + Why "suckless" software is important https://squi.bid/blog/Why-"suckless"-software-is-important/index.html diff --git a/index.php b/index.php index 6865b22..74eb4cf 100644 --- a/index.php +++ b/index.php @@ -3,85 +3,114 @@ Squibid's Site - + - - + + - +
-

Squibid's Website

+

Squibid

-
-
-
-
-

Welcome

-
-

- Hi my name is Squibid, and this is my website! I will be using it - for anything that I find interesting along with some of my personal - projects and a blog. -

- Got a question? Email me. - It's not likely that I will respond fast as I do not check my - messages often. -

-
-
-
-
-

Pinned Git Repos

-

- my best projects -

-
-

My best repos are

+
+

+ Welcome to my website. I do a bunch of coding, I try to lean towards + lower level languages (mostly C) as I find it more fun when there's a + challenge. As for the content of this website: I put blog posts up + when I've got something interesting to talk about and host my own git + server with stuff I make (you can find the things I'm proud of below). +

+

+ Thank you for visiting, if you've got something you wanna say to me, + feel free to contact me somewhere below:

    -
  • wiz - An idle event - manager for Wayland. Written in C!
  • -
  • eat it - - Eat It is a Mpv - package manager written in Lua with the intent of making Mpv - scripts easier to update and use.
  • +
  • email
  • +
  • github.com
  • +
  • codeberg.org
-

more...

-
+

- diff --git a/misc/404.html b/misc/404.html deleted file mode 100644 index 231193d..0000000 --- a/misc/404.html +++ /dev/null @@ -1,23 +0,0 @@ - - - - Squibid's Site - 404 - - - - - - - - -

whoops

- - diff --git a/misc/tools.php b/misc/tools.php deleted file mode 100644 index f683330..0000000 --- a/misc/tools.php +++ /dev/null @@ -1,27 +0,0 @@ - $limit - 1) - break; - $file = $entries[$i][1]; - $age = $entries[$i][2]; - printf('%s%s
', - $path, $file, str_replace("-", " ", $file), - $age ? $age : "¯\_(ツ)_/¯"); - } - } -?> diff --git a/style.css b/style.css index 566d57a..12e0852 100644 --- a/style.css +++ b/style.css @@ -1,7 +1,5 @@ /* root */ :root { - --lr-width: 45%; - /* mellow theme colors */ --bg: #161617; --fg: #c9c7cd; @@ -29,73 +27,33 @@ --gray05: #757581; --gray06: #9998a8; --gray07: #c1c0d4; + + /* site background color */ + --site-bg: var(--bg-dark); } html, body { max-height: 100%; -} - -/* desktop mode */ -@media only screen and (min-width: 100ch) { - #master { - width: 95ch; - } - div#master #left { - float: left; - text-align: left; - width: var(--lr-width); - } - div#master #right { - float: right; - text-align: right; - width: var(--lr-width); - ul { - text-align: left !important; - } - } - p#blogpreview a { - max-width: 30ch; - } -} -/* mobile mode */ -@media only screen and (max-width: 100ch) { - #master { - width: 85%; - } - p#blogpreview a { - max-width: 50vw; - } -} - -html, body { - display: flex; - justify-content: center; -} -body[id=blog] { - background-color: var(--bg); - display: unset !important; + background-color: var(--site-bg); max-width: 80ch; margin: auto; } -div#master header { - text-align: center; - font-size: 30px; -} -div#group hgroup { - text-align: center; -} -#font, p, ul, ol, h1, h2, h3, h4, h5 { +#font, p, ul, ol, h1, h2, h3, h4, h5, table { font-family: sans-serif; color: white; } -p#blogpreview a { - float: left; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; +h1 { + font-size: 3em; } -p#blogpreview span { - float: right; +iframe[src="/blog"] { + width: 100%; + border: none; +} +table#bloglist { + width: 100%; + td.date { + text-align: right; + } } a { font-family: sans-serif;