iPlug2 - C++ Audio Plug-in Framework
Loading...
Searching...
No Matches
IPlugOSC_msg.cpp
1/*
2 ==============================================================================
3
4 This file is part of the iPlug 2 library. Copyright (C) the iPlug 2 developers.
5
6 See LICENSE.txt for more info.
7
8 ==============================================================================
9*/
10
11#ifdef _WIN32
12#include <windows.h>
13#endif
14
15#include <stdlib.h>
16#include <stdio.h>
17#include <string.h>
18#include "IPlugOSC_msg.h"
19
20using namespace iplug;
21
22static int pad4(int len)
23{
24 return (len+4)&~3;
25}
26
27static int _strlen(const char* p, int maxlen)
28{
29 int i=0;
30 while (i < maxlen && *p)
31 {
32 ++p;
33 ++i;
34 }
35 return i;
36}
37
38OscMessageRead::OscMessageRead(char* buf, int len)
39{
40 m_msgok=false;
41
42 if (!buf || len < 1) return;
43 if (len > MAX_OSC_MSG_LEN) len=MAX_OSC_MSG_LEN;
44
45 m_msg_ptr=buf;
46 int n=pad4(_strlen(m_msg_ptr, len));
47
48 if (n == len)
49 {
50 // this is not technically allowed in the OSC spec,
51 // but some implementations omit the type tag with no arguments
52 m_msg_end=buf+n;
53 m_type_ptr=buf+n;
54 m_type_end=buf+n;
55 m_arg_ptr=buf+n;
56 m_arg_end=buf+n;
57 m_msgok=true;
58 }
59 else if (n < len)
60 {
61 m_msg_end=buf+n;
62 m_type_ptr=buf+n;
63 n += pad4(_strlen(m_type_ptr, len-n));
64
65 if (n <= len)
66 {
67 m_type_end=buf+n;
68 m_arg_ptr=buf+n;
69
70 const char* t=m_type_ptr;
71 if (*t == ',')
72 {
73 ++m_type_ptr;
74 while (++t < m_type_end && *t && n < len)
75 {
76 if (*t == 'i')
77 {
78 OSC_MAKEINTMEM4BE(buf+n);
79 n += sizeof(int);
80 }
81 else if (*t == 'f')
82 {
83 OSC_MAKEINTMEM4BE(buf+n);
84 n += sizeof(float);
85 }
86 else if (*t == 's')
87 {
88 n += pad4(_strlen(buf+n, len-n));
89 }
90 else
91 {
92 return; // unknown argument type
93 }
94 }
95
96 if (t <= m_type_end && !*t && n <= len)
97 {
98 m_arg_end=buf+n;
99 m_msgok=true;
100 }
101 }
102 }
103 }
104}
105
106const char* OscMessageRead::GetMessage() const
107{
108 return (m_msgok ? m_msg_ptr : "");
109}
110
111int OscMessageRead::GetNumArgs() const
112{
113 if (!m_msgok) return 0;
114 if (m_type_ptr >= m_type_end) return 0;
115 return (int) strlen(m_type_ptr);
116}
117
118const char* OscMessageRead::PopWord()
119{
120 if (!m_msgok) return 0;
121 if (m_msg_ptr >= m_msg_end) return 0;
122 char* p=m_msg_ptr;
123 if (*p == '/') ++p;
124 char* q=strstr(p, "/");
125 if (q)
126 {
127 *q=0;
128 m_msg_ptr=q+1;
129 }
130 else
131 {
132 m_msg_ptr=m_msg_end;
133 }
134 if (!*p) p=0;
135 return p;
136}
137
138const void *OscMessageRead::GetIndexedArg(int idx, char *typeOut) const
139{
140 if (!m_msgok || idx<0) return 0;
141 const char *ptr = m_type_ptr;
142 const char *valptr = m_arg_ptr;
143 if (ptr >= m_type_end || valptr >= m_arg_end) return 0;
144
145 while (idx>0)
146 {
147 if (*ptr == 'i') valptr += sizeof(int);
148 else if (*ptr == 'f') valptr += sizeof(float);
149 else if (*ptr == 's') valptr += pad4((int) strlen(valptr));
150 else return 0;
151
152 idx--;
153 ptr++;
154 if (ptr >= m_type_end || valptr >= m_arg_end) return 0;
155 }
156
157 *typeOut = *ptr;
158
159 const char *endptr = valptr;
160 if (*ptr == 'i') endptr += sizeof(int);
161 else if (*ptr == 'f') endptr += sizeof(float);
162 else if (*ptr == 's') endptr += pad4((int) strlen(valptr));
163 else return 0;
164
165 if (endptr > m_arg_end) return 0;
166
167 return valptr;
168}
169
170const int* OscMessageRead::PopIntArg(bool peek)
171{
172 if (!m_msgok) return 0;
173 if (m_type_ptr >= m_type_end) return 0;
174 if (*m_type_ptr != 'i') return 0;
175 if (m_arg_ptr+sizeof(int) > m_arg_end) return 0;
176
177 int* p=(int*)m_arg_ptr;
178 if (!peek)
179 {
180 ++m_type_ptr;
181 m_arg_ptr += sizeof(int);
182 }
183
184 return p;
185}
186
187const float* OscMessageRead::PopFloatArg(bool peek)
188{
189 if (!m_msgok) return 0;
190 if (m_type_ptr >= m_type_end) return 0;
191 if (*m_type_ptr != 'f') return 0;
192 if (m_arg_ptr+sizeof(float) > m_arg_end) return 0;
193
194 float* p=(float*)m_arg_ptr;
195
196 if (!peek)
197 {
198 ++m_type_ptr;
199 m_arg_ptr += sizeof(float);
200 }
201
202 return p;
203}
204
205const char* OscMessageRead::PopStringArg(bool peek)
206{
207 if (!m_msgok) return 0;
208 if (m_type_ptr >= m_type_end) return 0;
209 if (*m_type_ptr != 's') return 0;
210 if (m_arg_ptr+strlen(m_arg_ptr) > m_arg_end) return 0;
211
212 const char* p=(const char*)m_arg_ptr;
213 if (!peek)
214 {
215 ++m_type_ptr;
216 int n=pad4((int) strlen(p));
217 m_arg_ptr += n;
218 }
219
220 return p;
221}
222
223void OscMessageRead::DebugDump(const char* label, char* dump, int dumplen)
224{
225 // dump message even if it is invalid
226 if (!label) label="";
227 strcpy(dump, label);
228 strcat(dump, m_msg_ptr);
229
230 int n=pad4((int) strlen(m_msg_ptr));
231
232 const char* t=m_msg_ptr+n;
233 if (*t == ',')
234 {
235 snprintf(dump+strlen(dump), MAX_OSC_MSG_LEN, " [%s]", t+1);
236
237 n += pad4((int) strlen(t));
238
239 const char* a=m_msg_ptr+n;
240 while (*t++)
241 {
242 if (*t == 'i')
243 {
244 snprintf(dump+strlen(dump), MAX_OSC_MSG_LEN, " %d", *(int*)a);
245 a += sizeof(int);
246 }
247 else if (*t == 'f')
248 {
249 snprintf(dump+strlen(dump), MAX_OSC_MSG_LEN, " %f", *(float*)a);
250 a += sizeof(float);
251 }
252 else if (*t == 's')
253 {
254 snprintf(dump + (int) strlen(dump), MAX_OSC_MSG_LEN, " \"%s\"", a);
255 a += pad4((int) strlen(a));
256 }
257 else
258 {
259 snprintf(dump+strlen(dump), MAX_OSC_MSG_LEN, " %c:(unknown argument type)", *t);
260 break;
261 }
262 }
263 }
264}
265
266
267
268OscMessageWrite::OscMessageWrite()
269{
270 m_msg[0]=0;
271 m_types[0]=0;
272 m_args[0]=0;
273
274 m_msg_ptr=m_msg;
275 m_type_ptr=m_types;
276 m_arg_ptr=m_args;
277}
278
279bool OscMessageWrite::PushWord(const char* word)
280{
281 int len=(int) strlen(word);
282 if (m_msg_ptr+len+1 >= m_msg+sizeof(m_msg)) return false;
283
284 strcpy(m_msg_ptr, word);
285 m_msg_ptr += len;
286 return true;
287}
288
289bool OscMessageWrite::PushInt(int val)
290{
291 char buf[64];
292 sprintf(buf, "%d", val);
293 return PushWord(buf);
294}
295
296bool OscMessageWrite::PushIntArg(int val)
297{
298 if (m_type_ptr+1 > m_types+sizeof(m_types)) return false;
299 if (m_arg_ptr+sizeof(int) > m_args+sizeof(m_args)) return false;
300
301 *m_type_ptr++='i';
302 *m_type_ptr=0;
303
304 *(int*)m_arg_ptr=val;
305 OSC_MAKEINTMEM4BE(m_arg_ptr);
306 m_arg_ptr += sizeof(int);
307
308 return true;
309}
310
311bool OscMessageWrite::PushFloatArg(float val)
312{
313 if (m_type_ptr+1 > m_types+sizeof(m_types)) return false;
314 if (m_arg_ptr+sizeof(float) > m_args+sizeof(m_args)) return false;
315
316 *m_type_ptr++='f';
317 *m_type_ptr=0;
318
319 *(float*)m_arg_ptr=val;
320 OSC_MAKEINTMEM4BE(m_arg_ptr);
321 m_arg_ptr += sizeof(float);
322
323 return true;
324}
325
326bool OscMessageWrite::PushStringArg(const char* val)
327{
328 int len=(int) strlen(val);
329 int padlen=pad4(len);
330
331 if (m_type_ptr+1 > m_types+sizeof(m_types)) return false;
332 if (m_arg_ptr+padlen > m_args+sizeof(m_args)) return false;
333
334 *m_type_ptr++='s';
335 *m_type_ptr=0;
336
337 strcpy(m_arg_ptr, val);
338 memset(m_arg_ptr+len, 0, padlen-len);
339 m_arg_ptr += padlen;
340
341 return true;
342}
343
344const char* OscMessageWrite::GetBuffer(int* len)
345{
346 int msglen=(int) (m_msg_ptr-m_msg);
347 int msgpadlen=pad4(msglen);
348
349 int typelen=(int) (m_type_ptr-m_types+1); // add the comma
350 int typepadlen=pad4(typelen);
351
352 int arglen=(int) (m_arg_ptr-m_args); // already padded
353
354 if (msgpadlen+typepadlen+arglen > sizeof(m_msg))
355 {
356 if (len) *len=0;
357 return "";
358 }
359
360 char* p=m_msg;
361 memset(p+msglen, 0, msgpadlen-msglen);
362 p += msgpadlen;
363
364 *p=',';
365 strcpy(p+1, m_types);
366 memset(p+typelen, 0, typepadlen-typelen);
367 p += typepadlen;
368
369 memcpy(p, m_args, arglen);
370 p += arglen;
371
372 if (len) *len=(int) (p-m_msg);
373 return m_msg;
374}
375
376void OscMessageWrite::DebugDump(const char* label, char* dump, int dumplen)
377{
378 int len=0;
379 const char* p=GetBuffer(&len);
380 if (p && len && len <= MAX_OSC_MSG_LEN)
381 {
382 char buf[MAX_OSC_MSG_LEN];
383 memcpy(buf, p, len);
384 OscMessageRead rmsg(buf, len);
385 rmsg.DebugDump(label, dump, dumplen);
386 }
387}