1 /*
2     SuperCollider real time audio synthesis system
3     Copyright (c) 2002 James McCartney. All rights reserved.
4     Copyright (c) 2013 Tim Blechmann
5 
6     This program is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10 
11     This program is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15 
16     You should have received a copy of the GNU General Public License
17     along with this program; if not, write to the Free Software
18     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
19 */
20 
21 #pragma once
22 
23 #include "SC_ReplyImpl.hpp"
24 #include <cinttypes>
25 
dumpOSCmsg(int inSize,char * inData,bool skipStatus=false)26 static bool dumpOSCmsg(int inSize, char* inData, bool skipStatus = false) {
27     int size;
28     const char* data;
29 
30     if (inData[0]) {
31         const char* addr = inData;
32         if (skipStatus) {
33             if (strcmp(addr, "/status") == 0 || strcmp(addr, "status") == 0) // skip /status messages
34                 return false; // nothing has been printed
35         }
36 
37         data = OSCstrskip(inData);
38         size = inSize - (data - inData);
39         scprintf("[ \"%s\",", addr);
40     } else {
41         scprintf("[ %d,", OSCint(inData));
42         data = inData + 4;
43         size = inSize - 4;
44     }
45 
46     sc_msg_iter msg(size, data);
47 
48     while (msg.remain()) {
49         char c = msg.nextTag('i');
50         switch (c) {
51         case 'i':
52             scprintf(" %d", msg.geti());
53             break;
54         case 'f':
55             scprintf(" %g", msg.getf());
56             break;
57         case 'd':
58             scprintf(" %g", msg.getd());
59             break;
60         case 's':
61             scprintf(" \"%s\"", msg.gets());
62             break;
63         case '[':
64             scprintf(" [");
65             msg.count++;
66             break;
67         case ']':
68             scprintf(" ]");
69             msg.count++;
70             break;
71         case 'b':
72             scprintf(" DATA[%zu]", msg.getbsize());
73             msg.skipb();
74             break;
75         case 'm': {
76             char midi[4];
77             msg.getb(midi, 4);
78             scprintf(" MIDI[0x%02x 0x%02x 0x%02x 0x%02x]", midi[0], midi[1], midi[2], midi[3]);
79             break;
80         }
81         case 'c':
82             scprintf(" %c", (char)msg.geti());
83             break;
84         case 't':
85             scprintf(" %" PRId64 "", msg.gett());
86             break;
87         case 'T':
88             scprintf(" true");
89             msg.count++;
90             break;
91         case 'F':
92             scprintf(" false");
93             msg.count++;
94             break;
95         case 'I':
96             scprintf(" infinitum");
97             msg.count++;
98             break;
99         case 'N':
100             scprintf(" nil");
101             msg.count++;
102             break;
103         default:
104             scprintf(" !unknown tag '%c' 0x%02x !", isprint(c) ? c : '?', (unsigned char)c & 255);
105             goto leave;
106         }
107         if (msg.remain() && (c != '['))
108             scprintf(",");
109     }
110 leave:
111     scprintf(" ]");
112     return true; // something has been printed
113 }
114 
hexdump(int size,char * data)115 static void hexdump(int size, char* data) {
116     char ascii[20];
117     int padsize = (size + 15) & -16;
118     scprintf("size %d\n", size);
119     for (int i = 0; i < padsize; ++i) {
120         if ((i & 15) == 0) {
121             scprintf("%4d   ", i);
122         }
123         if (i >= size) {
124             scprintf("   ");
125             ascii[i & 15] = 0;
126         } else {
127             scprintf("%02x ", (unsigned char)data[i] & 255);
128 
129             if (isprint(data[i]))
130                 ascii[i & 15] = data[i];
131             else
132                 ascii[i & 15] = '.';
133         }
134         if ((i & 15) == 15) {
135             ascii[16] = 0;
136             scprintf("  |%s|\n", ascii);
137         } else if ((i & 3) == 3) {
138             scprintf(" ");
139         }
140     }
141     scprintf("\n");
142 }
143 
dumpOSCbndl(int indent,int size,char * inData)144 static bool dumpOSCbndl(int indent, int size, char* inData) {
145     char* data = inData + 8;
146     char* dataEnd = inData + size;
147 
148     scprintf("[ \"#bundle\", %" PRIu64 ", ", OSCtime(data));
149     data += 8;
150     while (data < dataEnd) {
151         int contentPrinted;
152 
153         int32 msgSize = OSCint(data);
154         data += sizeof(int32);
155 
156         scprintf("\n");
157         for (int i = 0; i < indent + 1; i++)
158             scprintf("  ");
159 
160         if (!strcmp(data, "#bundle"))
161             contentPrinted = dumpOSCbndl(indent + 1, msgSize, data);
162         else
163             contentPrinted = dumpOSCmsg(msgSize, data, true);
164         data += msgSize;
165         if ((data < dataEnd) && contentPrinted)
166             scprintf(",");
167     }
168     scprintf("\n");
169     for (int i = 0; i < indent; i++)
170         scprintf("  ");
171     scprintf("]");
172 
173     return true;
174 }
175 
dumpOSC(int mode,int size,char * inData)176 static void dumpOSC(int mode, int size, char* inData) {
177     if (mode & 1) {
178         int indent = 0;
179         bool contentPrinted;
180 
181         if (strcmp(inData, "#bundle") == 0)
182             contentPrinted = dumpOSCbndl(indent, size, inData);
183         else
184             contentPrinted = dumpOSCmsg(size, inData, true);
185 
186         if (contentPrinted)
187             scprintf("\n");
188     }
189 
190     if (mode & 2)
191         hexdump(size, inData);
192 }
193 
194 #if 0 // debugging code
195 static void DumpReplyAddress(ReplyAddress *inReplyAddress)
196 {
197 	scprintf("mAddress %s\n", inReplyAddress->mAddress.to_string().c_str());
198 	if (inReplyAddress->mProtocol == kUDP)
199 		scprintf("mProtocol UDP\n");
200 	else
201 		scprintf("mProtocol TCP\n");
202 
203 	scprintf("mPort %d\n",   inReplyAddress->mPort);
204 	scprintf("mSocket %d\n", inReplyAddress->mSocket);
205 
206 	scprintf("mReplyFunc %p\n", (void*)inReplyAddress->mReplyFunc);
207 }
208 #endif
209