<commit_before>/*  =========================================================================
    zosc - work with Open Sound Control messages

    Copyright (c) the Contributors as noted in the AUTHORS file.
    This file is part of CZMQ, the high-level C binding for 0MQ:
    http://czmq.zeromq.org.

    This Source Code Form is subject to the terms of the Mozilla Public
    License, v. 2.0. If a copy of the MPL was not distributed with this
    file, You can obtain one at http://mozilla.org/MPL/2.0/.
    =========================================================================
*/

/*
@header
    zosc - work with Open Sound Control messages
@discuss
@end
*/

#ifdef WIN32
#include <winsock2.h>           //  needed for ntohll/htonll
#endif
#include "czmq_classes.h"
#if __unix__ && !__APPLE__
#include <endian.h>
#define htonll(x) htobe64(x)
#define ntohll(x) be64toh(x)
#endif
//  Structure of our class

struct _zosc_t {
    char        *address;       //  the osc address string
    char        *format;        //  the string containing type hints
    zchunk_t    *chunk;         //  zchunk containing the complete OSC data
    size_t      data_begin;     //  start position of actual OSC data
    int         cursor_index;   //  cursor position of the iterator
    size_t      *data_indexes;  //  data offset positions of the elements in the message
};

// appends data to the chunk returning the new size, returns -1 on failure
static size_t
s_append_data(zchunk_t *chunk, const char *format, va_list argptr)
{
    size_t size = (size_t)-1;
    while (*format)
    {
        char typetag = *format;
        switch (typetag)
        {
            case 'b':
            {
                // todo handle bundles
                zsys_error("bundles or blobs not yet implemented");
                break;
            }
            case 'i' :
            {
                uint32_t int_v = va_arg( argptr, uint32_t );
                int_v = htonl(int_v);
                size = zchunk_extend( chunk, &int_v, sizeof(uint32_t) );
                break;
            }
            case 'h':
            {
                uint64_t int_v = va_arg( argptr, uint64_t );
                int_v = htonll(int_v);
                size = zchunk_extend( chunk, &int_v, sizeof(uint64_t) );
                break;
            }
            case 'f':
            {
                float flt_v = (float)va_arg( argptr, double );
                uint32_t flt_int = htonl(*((uint32_t *) &flt_v));
                size = zchunk_extend( chunk, &flt_int, sizeof(float) );
                break;
            }
            case 'd':
            {
                double dbl_v = (double)va_arg( argptr, double );
                uint64_t dbl_int = htonll(*((uint64_t *) &dbl_v));
                size = zchunk_extend( chunk, &dbl_int, sizeof(double) );
                break;
            }
            case 's':
            {
                //  not sure if the double pointer is the way to go
                char *str = va_arg( argptr, char * );
                assert(str);
                if (str)
                {
                    size = zchunk_extend( chunk, str, strlen(str)+1);
                    //  osc dictates we need to supply data in multitudes of 4 bytes so append \0's if needed
                    size_t newsize = (size + 3) & (size_t)~0x03;
                    if (newsize-size)
                        size = zchunk_extend(chunk, "\x00\x00\x00\x00", newsize-size);
                }
                break;
            }
            case 'S': // never used???
                break;
            case 'c': // is this ever used?
            {
                char char_v = (char)va_arg( argptr, int); // the standard dictates to use int for smaller vars
                //  osc dictates we need to supply data in multitudes of 4 bytes so create a 0 array to hold our char
                //  Not sure if this correct on big endian machines!!!
                char v[5] = "\x00\x00\x00\x00"; // a char array on windows always wants a terminating null so we need size 5 :|
                v[3] = char_v;
                size = zchunk_extend( chunk, v, 4 );
                break;
            }
            case 'm': // midi data
            {
                uint32_t midi_v = va_arg( argptr, uint32_t);
                size = zchunk_extend( chunk, &midi_v, sizeof(uint32_t) );
                break;
            }
            case 'T':
            case 'F':
            case 'N': // never used???
            case 'I': // never used???
            {
                // booleans and infinite are not added as data but only as type tag
                // just return the current size
                size = zchunk_size(chunk);
                break;
            }
            default:
                zsys_error("format identifier '%c' not matched", typetag);
        }
        format++;
    }
    if ( size > 8192 )
        zsys_debug("The packet size exceeds 8192 bytes. It's fine for ZMTP but for DGRAM(UDP) it only works on rare networks");
    else
    if ( size > 508 )
        zsys_debug("The packet size exceeds 508 bytes. It's fine for ZMTP but for DGRAM(UDP) it might not work");

    return size;
}

//  --------------------------------------------------------------------------
//  Create a new zosc

zosc_t *
zosc_new (const char *address)
{
    zosc_t *self = (zosc_t *) zmalloc (sizeof (zosc_t));
    assert (self);
    //  Initialize class properties here
    self->address = strdup(address);
    self->format = strdup("");
    assert(self->address);
    assert(self->format);
    self->chunk = zchunk_new(NULL, 0);
    self->data_begin = 0;
    self->data_indexes = NULL;
    return self;
}


//  --------------------------------------------------------------------------
//  Destroy the zosc

void
zosc_destroy (zosc_t **self_p)
{
    assert (self_p);
    if (*self_p) {
        zosc_t *self = *self_p;
        //  Free class properties here
        self->address = NULL;
        self->format = NULL;
        zchunk_destroy(&self->chunk);
        if (self->data_indexes)
            free(self->data_indexes);

        //  Free object itself
        free (self);
        *self_p = NULL;
    }
}
<commit_msg>fix zosc leak by moving address to the chunk (#2179)<commit_after>/*  =========================================================================
    zosc - work with Open Sound Control messages

    Copyright (c) the Contributors as noted in the AUTHORS file.
    This file is part of CZMQ, the high-level C binding for 0MQ:
    http://czmq.zeromq.org.

    This Source Code Form is subject to the terms of the Mozilla Public
    License, v. 2.0. If a copy of the MPL was not distributed with this
    file, You can obtain one at http://mozilla.org/MPL/2.0/.
    =========================================================================
*/

/*
@header
    zosc - work with Open Sound Control messages
@discuss
@end
*/

#ifdef WIN32
#include <winsock2.h>           //  needed for ntohll/htonll
#endif
#include "czmq_classes.h"
#if __unix__ && !__APPLE__
#include <endian.h>
#define htonll(x) htobe64(x)
#define ntohll(x) be64toh(x)
#endif
//  Structure of our class

struct _zosc_t {
    char        *address;       //  the osc address string
    char        *format;        //  the string containing type hints
    zchunk_t    *chunk;         //  zchunk containing the complete OSC data
    size_t      data_begin;     //  start position of actual OSC data
    int         cursor_index;   //  cursor position of the iterator
    size_t      *data_indexes;  //  data offset positions of the elements in the message
};

// appends data to the chunk returning the new size, returns -1 on failure
static size_t
s_append_data(zchunk_t *chunk, const char *format, va_list argptr)
{
    size_t size = (size_t)-1;
    while (*format)
    {
        char typetag = *format;
        switch (typetag)
        {
            case 'b':
            {
                // todo handle bundles
                zsys_error("bundles or blobs not yet implemented");
                break;
            }
            case 'i' :
            {
                uint32_t int_v = va_arg( argptr, uint32_t );
                int_v = htonl(int_v);
                size = zchunk_extend( chunk, &int_v, sizeof(uint32_t) );
                break;
            }
            case 'h':
            {
                uint64_t int_v = va_arg( argptr, uint64_t );
                int_v = htonll(int_v);
                size = zchunk_extend( chunk, &int_v, sizeof(uint64_t) );
                break;
            }
            case 'f':
            {
                float flt_v = (float)va_arg( argptr, double );
                uint32_t flt_int = htonl(*((uint32_t *) &flt_v));
                size = zchunk_extend( chunk, &flt_int, sizeof(float) );
                break;
            }
            case 'd':
            {
                double dbl_v = (double)va_arg( argptr, double );
                uint64_t dbl_int = htonll(*((uint64_t *) &dbl_v));
                size = zchunk_extend( chunk, &dbl_int, sizeof(double) );
                break;
            }
            case 's':
            {
                //  not sure if the double pointer is the way to go
                char *str = va_arg( argptr, char * );
                assert(str);
                if (str)
                {
                    size = zchunk_extend( chunk, str, strlen(str)+1);
                    //  osc dictates we need to supply data in multitudes of 4 bytes so append \0's if needed
                    size_t newsize = (size + 3) & (size_t)~0x03;
                    if (newsize-size)
                        size = zchunk_extend(chunk, "\x00\x00\x00\x00", newsize-size);
                }
                break;
            }
            case 'S': // never used???
                break;
            case 'c': // is this ever used?
            {
                char char_v = (char)va_arg( argptr, int); // the standard dictates to use int for smaller vars
                //  osc dictates we need to supply data in multitudes of 4 bytes so create a 0 array to hold our char
                //  Not sure if this correct on big endian machines!!!
                char v[5] = "\x00\x00\x00\x00"; // a char array on windows always wants a terminating null so we need size 5 :|
                v[3] = char_v;
                size = zchunk_extend( chunk, v, 4 );
                break;
            }
            case 'm': // midi data
            {
                uint32_t midi_v = va_arg( argptr, uint32_t);
                size = zchunk_extend( chunk, &midi_v, sizeof(uint32_t) );
                break;
            }
            case 'T':
            case 'F':
            case 'N': // never used???
            case 'I': // never used???
            {
                // booleans and infinite are not added as data but only as type tag
                // just return the current size
                size = zchunk_size(chunk);
                break;
            }
            default:
                zsys_error("format identifier '%c' not matched", typetag);
        }
        format++;
    }
    if ( size > 8192 )
        zsys_debug("The packet size exceeds 8192 bytes. It's fine for ZMTP but for DGRAM(UDP) it only works on rare networks");
    else
    if ( size > 508 )
        zsys_debug("The packet size exceeds 508 bytes. It's fine for ZMTP but for DGRAM(UDP) it might not work");

    return size;
}

//  --------------------------------------------------------------------------
//  Create a new zosc

zosc_t *
zosc_new (const char *address)
{
    zosc_t *self = (zosc_t *) zmalloc (sizeof (zosc_t));
    assert (self);
    //  Initialize class properties here
    self->format = "";
    self->chunk = zchunk_new(address, strlen(address) + 1);
    self->address = (char *)zchunk_data(self->chunk);
    assert(self->address);
    assert(self->format);
    self->data_begin = 0;
    self->data_indexes = NULL;
    return self;
}


//  --------------------------------------------------------------------------
//  Destroy the zosc

void
zosc_destroy (zosc_t **self_p)
{
    assert (self_p);
    if (*self_p) {
        zosc_t *self = *self_p;
        //  Free class properties here
        self->address = NULL;
        self->format = NULL;
        zchunk_destroy(&self->chunk);
        if (self->data_indexes)
            free(self->data_indexes);

        //  Free object itself
        free (self);
        *self_p = NULL;
    }
}

{'fraction_non_alphanumeric': 0.1416473595909563, 'fraction_numerical': 0.013901094511464408, 'mean_word_length': 1.480776852952834, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 36, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '42386', 'n_tokens_mistral': 3823, 'n_tokens_neox': 3553, 'n_words': 1138}