summaryrefslogtreecommitdiff
path: root/firmware/common/structec.c
diff options
context:
space:
mode:
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 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2007 by Miika Pekkarinen
11 *
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
14 *
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
17 *
18 ****************************************************************************/
19
20#include <string.h>
21#include "structec.h"
22#include "system.h"
23#include "file.h"
24
25#define MAX_STRUCT_SIZE 128
26
27/**
28 * Convert the struct endianess with the instructions provided.
29 *
30 * For example:
31 * struct test {
32 * long par1;
33 * short par2;
34 * short par3;
35 * };
36 *
37 * structec_convert(instance_of_test, "lss", sizeof(struct test), true);
38 *
39 * Structures to be converted must be properly padded.
40 *
41 * @param structure Pointer to the struct being converted.
42 * @param ecinst Instructions how to do the endianess conversion.
43 * @param count Number of structures to write
44 * @param enable Conversion is not made unless this is true.
45 */
46void structec_convert(void *structure, const char *ecinst,
47 long count, bool enable)
48{
49 const char *ecinst_ring = ecinst;
50 char *buf = (char *)structure;
51
52 if (!enable)
53 return;
54
55 while (count > 0)
56 {
57 switch (*ecinst_ring)
58 {
59 /* Swap nothing. */
60 case 'c':
61 {
62 buf++;
63 break;
64 }
65
66 /* Swap 2 bytes. */
67 case 's':
68 {
69 unsigned short *data = (unsigned short *)buf;
70 *data = SWAP_16(*data);
71 buf += 2;
72 break;
73 }
74
75 /* Swap 4 bytes. */
76 case 'l':
77 {
78 unsigned long *data = (unsigned long *)buf;
79 *data = SWAP_32(*data);
80 buf += 4;
81 break;
82 }
83
84 /* This should be never reached. */
85 default:
86 break;
87 }
88
89 ecinst_ring++;
90 if (*ecinst_ring == '\0')
91 {
92 ecinst_ring = ecinst;
93 count--;
94 }
95 }
96}
97
98/**
99 * Determines the size of a struct in bytes by using endianess correction
100 * string format.
101 *
102 * @param ecinst endianess correction string.
103 * @return length of the struct in bytes.
104 */
105size_t structec_size(const char *ecinst)
106{
107 size_t size = 0;
108
109 do
110 {
111 switch (*ecinst)
112 {
113 case 'c': size += 1; break;
114 case 's': size += 2; break;
115 case 'l': size += 4; break;
116 default: break;
117 }
118 } while (*(++ecinst) != '\0');
119
120 return size;
121}
122
123/**
124 * Reads endianess corrected structure members from the given file.
125 *
126 * @param fd file descriptor of the file being read.
127 * @param buf endianess corrected data is placed here.
128 * @param scount the number of struct members to read.
129 * @param ecinst endianess correction string.
130 * @param ec if true, endianess correction is enabled.
131 */
132ssize_t ecread(int fd, void *buf, size_t scount, const char *ecinst, bool ec)
133{
134 ssize_t ret;
135 size_t member_size = structec_size(ecinst);
136
137 ret = read(fd, buf, scount * member_size);
138 structec_convert(buf, ecinst, scount, ec);
139
140 return ret;
141}
142
143/**
144 * Writes endianess corrected structure members to the given file.
145 *
146 * @param fd file descriptor of the file being written to.
147 * @param buf endianess corrected data is read here.
148 * @param scount the number of struct members to write.
149 * @param ecinst endianess correction string.
150 * @param ec if true, endianess correction is enabled.
151 */
152ssize_t ecwrite(int fd, const void *buf, size_t scount,
153 const char *ecinst, bool ec)
154{
155 char tmp[MAX_STRUCT_SIZE];
156 size_t member_size = structec_size(ecinst);
157
158 if (ec)
159 {
160 const char *p = (const char *)buf;
161 int maxamount = (int)(MAX_STRUCT_SIZE / member_size);
162 int i;
163
164 for (i = 0; i < (long)scount; i += maxamount)
165 {
166 long amount = MIN((int)scount-i, maxamount);
167
168 memcpy(tmp, p, member_size * amount);
169 structec_convert(tmp, ecinst, amount, true);
170 write(fd, tmp, amount * member_size);
171 p += member_size * amount;
172 }
173
174 return scount * member_size;
175 }
176
177 return write(fd, buf, scount * member_size);
178}
179