summaryrefslogtreecommitdiffstats
path: root/firmware/common/structec.c
diff options
context:
space:
mode:
authorMiika Pekkarinen <miipekk@ihme.org>2007-02-13 21:51:18 +0000
committerMiika Pekkarinen <miipekk@ihme.org>2007-02-13 21:51:18 +0000
commit9b9539c8d3349975127ff725c313d3b888f89ab6 (patch)
treea9688e8c7210abe09af38dfd60eafb88aba9b40f /firmware/common/structec.c
parent24c8da0b56c5961d948bf85d2a1b25dffd6f9c00 (diff)
downloadrockbox-9b9539c8d3349975127ff725c313d3b888f89ab6.tar.gz
rockbox-9b9539c8d3349975127ff725c313d3b888f89ab6.zip
Make database endianess independent.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@12297 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'firmware/common/structec.c')
-rw-r--r--firmware/common/structec.c179
1 files changed, 179 insertions, 0 deletions
diff --git a/firmware/common/structec.c b/firmware/common/structec.c
new file mode 100644
index 0000000000..ec7e1409fd
--- /dev/null
+++ b/firmware/common/structec.c
@@ -0,0 +1,179 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2007 by Miika Pekkarinen
+ *
+ * All files in this archive are subject to the GNU General Public License.
+ * See the file COPYING in the source tree root for full license agreement.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#include <string.h>
+#include "structec.h"
+#include "system.h"
+#include "file.h"
+
+#define MAX_STRUCT_SIZE 128
+
+/**
+ * Convert the struct endianess with the instructions provided.
+ *
+ * For example:
+ * struct test {
+ * long par1;
+ * short par2;
+ * short par3;
+ * };
+ *
+ * structec_convert(instance_of_test, "lss", sizeof(struct test), true);
+ *
+ * Structures to be converted must be properly padded.
+ *
+ * @param structure Pointer to the struct being converted.
+ * @param ecinst Instructions how to do the endianess conversion.
+ * @param count Number of structures to write
+ * @param enable Conversion is not made unless this is true.
+ */
+void structec_convert(void *structure, const char *ecinst,
+ long count, bool enable)
+{
+ const char *ecinst_ring = ecinst;
+ char *buf = (char *)structure;
+
+ if (!enable)
+ return;
+
+ while (count > 0)
+ {
+ switch (*ecinst_ring)
+ {
+ /* Swap nothing. */
+ case 'c':
+ {
+ buf++;
+ break;
+ }
+
+ /* Swap 2 bytes. */
+ case 's':
+ {
+ unsigned short *data = (unsigned short *)buf;
+ *data = SWAP_16(*data);
+ buf += 2;
+ break;
+ }
+
+ /* Swap 4 bytes. */
+ case 'l':
+ {
+ unsigned long *data = (unsigned long *)buf;
+ *data = SWAP_32(*data);
+ buf += 4;
+ break;
+ }
+
+ /* This should be never reached. */
+ default:
+ break;
+ }
+
+ ecinst_ring++;
+ if (*ecinst_ring == '\0')
+ {
+ ecinst_ring = ecinst;
+ count--;
+ }
+ }
+}
+
+/**
+ * Determines the size of a struct in bytes by using endianess correction
+ * string format.
+ *
+ * @param ecinst endianess correction string.
+ * @return length of the struct in bytes.
+ */
+size_t structec_size(const char *ecinst)
+{
+ size_t size = 0;
+
+ do
+ {
+ switch (*ecinst)
+ {
+ case 'c': size += 1; break;
+ case 's': size += 2; break;
+ case 'l': size += 4; break;
+ default: break;
+ }
+ } while (*(++ecinst) != '\0');
+
+ return size;
+}
+
+/**
+ * Reads endianess corrected structure members from the given file.
+ *
+ * @param fd file descriptor of the file being read.
+ * @param buf endianess corrected data is placed here.
+ * @param scount the number of struct members to read.
+ * @param ecinst endianess correction string.
+ * @param ec if true, endianess correction is enabled.
+ */
+ssize_t ecread(int fd, void *buf, size_t scount, const char *ecinst, bool ec)
+{
+ ssize_t ret;
+ size_t member_size = structec_size(ecinst);
+
+ ret = read(fd, buf, scount * member_size);
+ structec_convert(buf, ecinst, scount, ec);
+
+ return ret;
+}
+
+/**
+ * Writes endianess corrected structure members to the given file.
+ *
+ * @param fd file descriptor of the file being written to.
+ * @param buf endianess corrected data is read here.
+ * @param scount the number of struct members to write.
+ * @param ecinst endianess correction string.
+ * @param ec if true, endianess correction is enabled.
+ */
+ssize_t ecwrite(int fd, const void *buf, size_t scount,
+ const char *ecinst, bool ec)
+{
+ char tmp[MAX_STRUCT_SIZE];
+ size_t member_size = structec_size(ecinst);
+
+ if (ec)
+ {
+ const char *p = (const char *)buf;
+ int maxamount = (int)(MAX_STRUCT_SIZE / member_size);
+ int i;
+
+ for (i = 0; i < (long)scount; i += maxamount)
+ {
+ long amount = MIN((int)scount-i, maxamount);
+
+ memcpy(tmp, p, member_size * amount);
+ structec_convert(tmp, ecinst, amount, true);
+ write(fd, tmp, amount * member_size);
+ p += member_size * amount;
+ }
+
+ return scount * member_size;
+ }
+
+ return write(fd, buf, scount * member_size);
+}
+