#include "OSC_Message.h" OSC_Message *OSC_Message_init() { OSC_Message *msg = calloc( 1, sizeof(OSC_Message) ); msg->path = malloc( InitialPathSize ); msg->types = malloc( InitialTypesSize ); msg->data = malloc( InitialDataSize ); msg->pathSize = InitialPathSize; msg->typeSize = InitialTypesSize; msg->dataSize = InitialDataSize; msg->pathComponents = PathComponents_init(); OSC_Message_reset(msg); return msg; } void OSC_Message_reset(OSC_Message* message) { message->path[0] = '\0'; message->types[0] = ','; message->types[1] = 0; message->numTypes = 1; message->numArguments = 0; message->dataOffset = 0; if(message->arguments) { free( message->arguments ); message->arguments = NULL; } PathComponents_reset(message->pathComponents); } void OSC_Message_resetArguments(OSC_Message* message) { message->types[0] = ','; message->types[1] = 0; message->numTypes = 1; message->numArguments = 0; message->dataOffset = 0; } void OSC_Message_destroy(OSC_Message* message) { free( message->path ); free( message->types ); free( message->arguments ); PathComponents_destroy(message->pathComponents); free( message ); } OSC_Argument **OSC_Message_allocNumArguments(OSC_Message *message, int numArguments) { message->arguments = calloc(numArguments + 1, sizeof(OSC_Argument*)); message->numArguments = numArguments; return message->arguments; } int OSC_Message_parseMessageFromBuffer(OSC_Message *message, char *buffer, int bufferSize) { OSC_Argument **argv; int j, size, numArguments; char *path, *types, *arguments, *argPtr; path = buffer; types = buffer + OSC_Message_stringSize(path); numArguments = strlen(types) - 1; arguments = types + OSC_Message_stringSize(types); argPtr = arguments; message->virtualArgumentPtr = argPtr; // make sure we have a valid message... if( *types != ',' ) { printf("Invalid OSC message\n"); return -1; } //printf("Path: %s Num Args: %d Types: %s\n", path, numArguments, types); OSC_Message_setPath(message, path); OSC_Message_setTypes(message, types); argv = OSC_Message_allocNumArguments(message, numArguments); //printf("types=%s numArgs=%d\n", types, numArguments); for(j = 1; j < numArguments+1; j++) { size = OSC_Message_argumentSize( types[j], argPtr ); argv[j-1] = (OSC_Argument*)argPtr; OSC_Message_convertArgumentEndian(types[j], argPtr); argPtr += size; } return 0; } void OSC_Message_copyArguments(OSC_Message *message) { int j; int size; int32_t *nptr; OSC_cast32 unionCast; char *dataPtr; dataPtr = message->virtualArgumentPtr; for(j = 0; j < message->numArguments; j++) { size = OSC_Message_argumentSize( message->types[j+1], dataPtr ); switch(message->types[j+1]) { case OSC_INT32: nptr = OSC_Message_addData(message, sizeof(int32_t)); unionCast.i = *((int*)dataPtr); *nptr = htonl(unionCast.nl); // 32-bit byte-swap if need be break; case OSC_FLOAT: nptr = OSC_Message_addData(message, sizeof(float)); unionCast.f = *((float*)dataPtr); *nptr = htonl(unionCast.nl); // 32-bit byte-swap if need be break; case OSC_STRING: nptr = OSC_Message_addData(message, size); strncpy((char*)nptr, dataPtr, size); break; case OSC_BLOB: // TODO //OSC_Message_addBlobArgument(message, dataPtr); break; } dataPtr += size; } } int OSC_Message_setPath(OSC_Message* message, char *path) { int pathLen = strlen(path); if(pathLen > message->pathSize) { char *result; if(pathLen > PathSizeLimit) { printf("Attempted to go beyond path size limit (pathLen=%d)\n", pathLen); return -1; } result = realloc(message->path, pathLen+1); if(result) { message->path = result; // only on success, reassign message->pathSize = pathLen+1; } } strcpy(message->path, path); return 0; } char *OSC_Message_path(OSC_Message* message) { return message->path; } //strncmp int OSC_Message_parsePath(OSC_Message *message) { return PathComponents_parse(message->pathComponents, message->path); } PathComponents *OSC_Message_pathComponents(OSC_Message *message) { return message->pathComponents; } int OSC_Message_setTypes(OSC_Message* message, char *types) { int typesLen = strlen(types); if( OSC_Message_resizeTypes(message, typesLen+1) < 0 ) { return -1; } strcpy(message->types, types); return 0; } int OSC_Message_resizeTypes(OSC_Message *message, int typesLen) { if(typesLen > message->typeSize) { char *result; if(typesLen > TypeSizeLimit) { printf("Attempted to go beyond types size limit (typesLen=%d)\n", typesLen); return -1; } result = realloc(message->types, typesLen+1); if(result) { message->types = result; // only on success, reassign message->typeSize = typesLen+1; } } return 0; } int OSC_Message_resizeData(OSC_Message *message, int newLen) { if(newLen > message->dataSize) { char *result; if(newLen > DataSizeLimit) { printf("Attempted to go beyond data size limit (newLen=%d)\n", newLen); return -1; } result = realloc(message->data, newLen); if(result) { message->data = result; message->dataSize = newLen; } } return 0; } char *OSC_Message_types(OSC_Message* message) { return message->types; } OSC_Argument **OSC_Message_arguments(OSC_Message* message) { return message->arguments; } int OSC_Message_numArguments(OSC_Message* message) { return message->numArguments; } int OSC_Message_addTypeChar(OSC_Message *message, char type) { // check the size if(message->numTypes >= message->typeSize) { int newSize = message->typeSize; while( newSize <= message->numTypes && newSize < TypeSizeLimit ) { newSize *= 2; } // we need to resize OSC_Message_resizeTypes(message, newSize); } // add the type message->types[ message->numTypes ] = type; message->numTypes++; message->types[ message->numTypes ] = '\0'; // terminate char return 0; // success } void *OSC_Message_addData(OSC_Message *message, size_t size) { void *result; int newSize = message->dataOffset + size; OSC_Message_resizeData(message, newSize); result = (void*) ((char*)message->data + message->dataOffset); message->dataOffset += size; return result; } void OSC_Message_addIntArgument(OSC_Message *message, int32_t argument) { OSC_cast32 unionCast; int32_t *nptr = OSC_Message_addData(message, sizeof(argument)); unionCast.i = argument; // add type if( !OSC_Message_addTypeChar(message, OSC_INT32) ) { // copy to data buffer *nptr = htonl(unionCast.nl); // 32-bit byte-swap if need be } } void OSC_Message_addFloatArgument(OSC_Message *message, float argument) { OSC_cast32 unionCast; int32_t *nptr = OSC_Message_addData(message, sizeof(argument)); unionCast.f = argument; // add type if( !OSC_Message_addTypeChar(message, OSC_FLOAT) ) { // copy to data buffer *nptr = htonl(unionCast.nl); // 32-bit byte-swap if need be } } void OSC_Message_addStringArgument(OSC_Message *message, char *argument) { const int size = OSC_Message_stringSize(argument); char *nptr = OSC_Message_addData(message, size); if( !OSC_Message_addTypeChar(message, OSC_STRING) ) { strncpy(nptr, argument, size); } } // note: this function has not been fully tested... void OSC_Message_addBlobArgument(OSC_Message *message, OSC_Blob *argument) { int size = OSC_Blob_size(argument); int32_t dataSize = htonl(OSC_Blob_dataSize(argument)); // 32-bit byte-swap if need be char *nptr = OSC_Message_addData(message, size); if( !OSC_Message_addTypeChar(message, OSC_BLOB) ) { // clear the last few bytes memset(nptr + size - 4, 0, 4); memcpy(nptr, &dataSize, sizeof(dataSize)); memcpy(nptr + sizeof(int32_t), OSC_Blob_dataPtr(argument), OSC_Blob_dataSize(argument)); } } // utility function for debugging a message's arguments void OSC_Message_displayArguments(OSC_Message *message) { int j; for(j = 1; j < message->numArguments + 1; j++) { switch( message->types[j] ) { case OSC_INT32: printf("%d=%d ", j-1, message->arguments[j-1]->i); // OSC_Message_ArgumentInt32( message->arguments[j] )); break; case OSC_FLOAT: printf("%d=%f ", j-1, message->arguments[j-1]->f); //OSC_Message_ArgumentFloat32( message->arguments[j] )); break; case OSC_STRING: printf("%d=%s ", j-1, message->arguments[j-1]); break; } } } int OSC_Message_stringSize(const char *s) { return 4 * (strlen(s) / 4 + 1); } size_t OSC_Message_argumentSize(OSC_Type type, void *data) { switch(type) { case OSC_INT32: case OSC_FLOAT: return 4; case OSC_STRING: return OSC_Message_stringSize((char *)data); case OSC_BLOB: return OSC_Blob_size((OSC_Blob*)data); default: fprintf(stderr, "warning: unhandled OSC type '%c' at %s:%d\n", type, __FILE__, __LINE__); return 0; } return 0; } void OSC_Message_convertArgumentEndian(OSC_Type type, void *data) { switch (type) { case OSC_FLOAT: case OSC_BLOB: case OSC_INT32: *(int32_t *)data = htonl(*(int32_t *)data); // 32-bit byte-swap if need be break; case OSC_STRING: break; default: fprintf(stderr, "warning: unhandled OSC type '%c' at %s:%d\n", type, __FILE__, __LINE__); break; } } size_t OSC_Message_size(OSC_Message *message) { return OSC_Message_stringSize(message->path) + OSC_Message_stringSize(message->types) + message->dataOffset; } int OSC_Message_serializeToNetworkString(OSC_Message *message, char **string) { size_t size = OSC_Message_size(message) + sizeof(int); if( size > 0 ) { int pathSize, typesSize; OSC_cast32 unionCast; uint32_t header; unionCast.i = size - sizeof(int); header = htonl(unionCast.nl); // 32-bit byte-swap if need be *string = calloc(1, size); pathSize = OSC_Message_stringSize(message->path); typesSize = OSC_Message_stringSize(message->types); memcpy(*string, (void*)&header, sizeof(int)); strcpy(*string + sizeof(int), message->path); strcpy(*string + pathSize + sizeof(int), message->types); memcpy(*string + pathSize + typesSize + sizeof(int), message->data, message->dataOffset); } return size; }