Beispiel #1
0
bool Streader_match_char(Streader* sr, char ch)
{
    rassert(sr != NULL);

    if (Streader_is_error_set(sr))
        return false;

    Streader_skip_whitespace(sr);

    if (Streader_end_reached(sr))
    {
        Streader_set_error(sr, "Expected '%c' instead of end of data", ch);
        return false;
    }

    if (CUR_CH != ch)
    {
        if (isprint(CUR_CH))
            Streader_set_error(
                    sr, "Expected '%c' instead of '%c'", ch, CUR_CH);
        else
            Streader_set_error(
                    sr,
                    "Expected '%c' instead of %#04hhx",
                    ch, (unsigned)CUR_CH);

        return false;
    }

    ++sr->pos;

    return true;
}
Beispiel #2
0
bool Streader_read_tstamp(Streader* sr, Tstamp* dest)
{
    rassert(sr != NULL);

    if (Streader_is_error_set(sr))
        return false;

    int64_t beats = 0;
    int64_t rem = 0;

    if (!(Streader_match_char(sr, '[')  &&
                Streader_read_int(sr, &beats) &&
                Streader_match_char(sr, ',')  &&
                Streader_read_int(sr, &rem)   &&
                Streader_match_char(sr, ']')))
    {
        Streader_set_error(sr, "Expected a valid timestamp");
        return false;
    }

    if (rem < 0 || rem >= KQT_TSTAMP_BEAT)
    {
        Streader_set_error(
                sr,
                "Timestamp remainder %" PRId64 " out of range [0..%ld)",
                rem,
                KQT_TSTAMP_BEAT);
        return false;
    }

    if (dest != NULL)
        Tstamp_set(dest, beats, (int32_t)rem);

    return true;
}
Beispiel #3
0
bool Streader_match_string(Streader* sr, const char* str)
{
    rassert(sr != NULL);
    rassert(str != NULL);

    if (Streader_is_error_set(sr))
        return false;

    Streader_skip_whitespace(sr);

    if (Streader_end_reached(sr))
    {
        Streader_set_error(
                sr, "Expected beginning of a string instead of end of data");
        return false;
    }

    // Match opening double quote
    if (CUR_CH != '\"')
    {
        if (isprint(CUR_CH))
            Streader_set_error(
                    sr,
                    "Expected beginning of a string instead of '%c'",
                    CUR_CH);
        else
            Streader_set_error(
                    sr,
                    "Expected beginning of a string instead of %#2x",
                    (unsigned)CUR_CH);

        return false;
    }

    ++sr->pos;

    // Match the string
    if (!Streader_match_char_seq(sr, str))
        return false;

    // Match closing double quote
    if (Streader_end_reached(sr) || CUR_CH != '\"')
    {
        Streader_set_error(sr, "Unexpected string (expected `%s`)", str);
        return false;
    }

    ++sr->pos;

    return true;
}
Beispiel #4
0
bool Streader_read_piref(Streader* sr, Pat_inst_ref* dest)
{
    rassert(sr != NULL);

    if (Streader_is_error_set(sr))
        return false;

    int64_t pat = 0;
    int64_t inst = 0;

    if (!(Streader_match_char(sr, '[') &&
                Streader_read_int(sr, &pat)  &&
                Streader_match_char(sr, ',') &&
                Streader_read_int(sr, &inst) &&
                Streader_match_char(sr, ']')))
    {
        Streader_set_error(sr, "Expected a valid pattern instance");
        return false;
    }

    if (pat < 0 || pat >= KQT_PATTERNS_MAX)
    {
        Streader_set_error(
                sr,
                "Pattern number %" PRId64 " out of range [0..%ld)"
                    " in pattern instance",
                pat,
                KQT_PATTERNS_MAX);
        return false;
    }

    if (inst < 0 || inst >= KQT_PAT_INSTANCES_MAX)
    {
        Streader_set_error(
                sr,
                "Pattern instance number %" PRId64 " out of range [0..%ld)"
                    " in pattern instance",
                inst,
                KQT_PAT_INSTANCES_MAX);
        return false;
    }

    if (dest != NULL)
    {
        dest->pat = (int16_t)pat;
        dest->inst = (int16_t)inst;
    }

    return true;
}
Beispiel #5
0
bool Module_parse_random_seed(Module* module, Streader* sr)
{
    rassert(module != NULL);
    rassert(sr != NULL);

    if (Streader_is_error_set(sr))
        return false;

    int64_t seed = 0;

    if (Streader_has_data(sr))
    {
        if (!Streader_read_int(sr, &seed))
            return false;

        if (seed < 0)
        {
            Streader_set_error(sr, "Random seed must be non-negative");
            return false;
        }
    }

    module->random_seed = (uint64_t)seed;

    return true;
}
Beispiel #6
0
bool Streader_read_bool(Streader* sr, bool* dest)
{
    rassert(sr != NULL);

    if (Streader_is_error_set(sr))
        return false;

    Streader_skip_whitespace(sr);

    bool result = false;

    if (Streader_try_match_char_seq(sr, "true"))
    {
        result = true;
    }
    else
    {
        if (!Streader_match_char_seq(sr, "false"))
        {
            Streader_set_error(sr, "Expected a boolean value");
            return false;
        }
    }

    if (dest != NULL)
        *dest = result;

    return true;
}
Beispiel #7
0
bool Module_read_mixing_volume(Module* module, Streader* sr)
{
    rassert(module != NULL);
    rassert(sr != NULL);

    if (Streader_is_error_set(sr))
        return false;

    double mix_vol = COMP_DEFAULT_MIX_VOL;

    if (Streader_has_data(sr))
    {
        if (!Streader_read_float(sr, &mix_vol))
            return false;

        if (!isfinite(mix_vol) && mix_vol != -INFINITY)
        {
            Streader_set_error(sr, "Invalid mixing volume: %.4f", mix_vol);
            return false;
        }
    }

    module->mix_vol_dB = mix_vol;
    module->mix_vol = exp2(module->mix_vol_dB / 6);

    return true;
}
Beispiel #8
0
END_TEST


static bool test_reported_force(Streader* sr, double expected)
{
    assert(sr != NULL);

    double actual = NAN;

    if (!(Streader_readf(sr, "[[0, [") &&
                Streader_match_string(sr, "qf") &&
                Streader_readf(sr, ", null]], [0, [") &&
                Streader_match_string(sr, "Af") &&
                Streader_readf(sr, ", %f]]]", &actual)))
        return false;

    if (fabs(actual - expected) > 0.1)
    {
        Streader_set_error(
                sr, "Expected force %.4f, got %.4f", expected, actual);
        return false;
    }

    return true;
}
Beispiel #9
0
static bool read_env_var(Streader* sr, int32_t index, void* userdata)
{
    assert(sr != NULL);
    (void)index;
    assert(userdata != NULL);

    AAtree* new_vars = userdata;

    Env_var* var = new_Env_var_from_string(sr);
    if (var == NULL)
        return false;

    if (AAtree_contains(new_vars, Env_var_get_name(var)))
    {
        Streader_set_error(
                sr, "Variable name %s is not unique", Env_var_get_name(var));
        del_Env_var(var);
        return false;
    }

    if (!AAtree_ins(new_vars, var))
    {
        Streader_set_memory_error(
                sr, "Could not allocate memory for environment");
        del_Env_var(var);
        return false;
    }

    return true;
}
Beispiel #10
0
bool Module_read_force_shift(Module* module, Streader* sr)
{
    rassert(module != NULL);
    rassert(sr != NULL);

    if (Streader_is_error_set(sr))
        return false;

    double shift = 0;

    if (Streader_has_data(sr))
    {
        if (!Streader_read_float(sr, &shift))
            return false;

        if (!isfinite(shift) || (shift < -60) || (shift > 0))
        {
            Streader_set_error(sr, "Invalid force shift: %.4f", shift);
            return false;
        }
    }

    module->force_shift = shift;

    return true;
}
Beispiel #11
0
bool read_received_events(Streader* sr, int32_t index, void* userdata)
{
    assert(sr != NULL);
    (void)index;
    assert(userdata != NULL);

    int32_t* expected = userdata;
    double actual = NAN;

    const char* event_name = (*expected % 16 == 0) ? "n+" : "vs";

    if (!(Streader_readf(sr, "[0, [") &&
                Streader_match_string(sr, event_name) &&
                Streader_readf(sr, ", %f]]", &actual))
       )
        return false;

    if ((int)round(actual) != *expected)
    {
        Streader_set_error(
                sr,
                "Received argument %" PRId64 " instead of %" PRId32,
                actual, *expected);
        return false;
    }

    *expected = (int)round(actual) + 1;

    return true;
}
Beispiel #12
0
Connections* new_Connections_from_string(
        Streader* sr, Connection_level level, Au_table* au_table, Device* master)
{
    rassert(sr != NULL);
    rassert(au_table != NULL);
    rassert(master != NULL);

    if (Streader_is_error_set(sr))
        return NULL;

    Connections* graph = memory_alloc_item(Connections);
    if (graph == NULL)
    {
        Streader_set_memory_error(
                sr, "Could not allocate memory for connections");
        return NULL;
    }

    graph->nodes = NULL;
    graph->nodes = new_AAtree(
            (int (*)(const void*, const void*))Device_node_cmp,
            (void (*)(void*))del_Device_node);
    mem_error_if(graph->nodes == NULL, graph, NULL, sr);

    Device_node* master_node = NULL;
    if (level == CONNECTION_LEVEL_AU)
    {
        const Device* iface = Audio_unit_get_output_interface((Audio_unit*)master);
        master_node = new_Device_node("", au_table, iface);
    }
    else
    {
        master_node = new_Device_node("", au_table, master);
    }
    mem_error_if(master_node == NULL, graph, NULL, sr);
    mem_error_if(!AAtree_ins(graph->nodes, master_node), graph, master_node, sr);

    if (!Streader_has_data(sr))
        return graph;

    read_conn_data rcdata = { graph, level, au_table, master };
    if (!Streader_read_list(sr, read_connection, &rcdata))
    {
        del_Connections(graph);
        return NULL;
    }

    if (Connections_is_cyclic(graph))
    {
        Streader_set_error(sr, "The connection graph contains a cycle");
        del_Connections(graph);
        return NULL;
    }

    return graph;
}
Beispiel #13
0
bool Streader_read_dict(Streader* sr, Dict_item_reader ir, void* userdata)
{
    rassert(sr != NULL);

    if (Streader_is_error_set(sr))
        return false;

    // Check opening brace
    if (!(Streader_skip_whitespace(sr) && Streader_match_char(sr, '{')))
    {
        Streader_set_error(sr, "Expected a dictionary opening brace");
        return false;
    }

    // Check empty dictionary
    if (Streader_try_match_char(sr, '}'))
        return true;

    if (ir == NULL)
    {
        Streader_set_error(sr, "Expected an empty dictionary");
        return false;
    }

    // Read key/value pairs
    do
    {
        char key[STREADER_DICT_KEY_LENGTH_MAX + 1] = "";
        if (!(Streader_read_string(sr, STREADER_DICT_KEY_LENGTH_MAX + 1, key) &&
                    Streader_match_char(sr, ':') &&
                    ir(sr, key, userdata)))
            return false;
    } while (Streader_try_match_char(sr, ','));

    // Check closing brace
    if (!Streader_match_char(sr, '}'))
    {
        Streader_set_error(sr, "Expected a dictionary closing brace");
        return false;
    }

    return true;
}
Beispiel #14
0
static bool Streader_match_char_seq(Streader* sr, const char* seq)
{
    rassert(sr != NULL);
    rassert(seq != NULL);

    rassert(!Streader_is_error_set(sr));
    rassert(!Streader_end_reached(sr));

    // Check that we have enough data
    const int64_t expected_len = (int64_t)strlen(seq);
    if (sr->len - sr->pos < expected_len)
    {
        Streader_set_error(
                sr,
                "Too few bytes left to contain expected string `%s`",
                seq);
        return false;
    }

    // Match the string
    if (strncmp(&sr->str[sr->pos], seq, (size_t)expected_len) != 0)
    {
        Streader_set_error(sr, "Unexpected string (expected `%s`)", seq);
        return false;
    }

    // Update position
    for (int64_t i = 0; i < expected_len; ++i)
    {
        if (CUR_CH == '\n')
            ++sr->line;
        ++sr->pos;
    }

    if (!Streader_end_reached(sr) && isalnum(CUR_CH))
    {
        Streader_set_error(
                sr, "Unexpected character after expected string `%s`", seq);
        return false;
    }

    return true;
}
Beispiel #15
0
static bool Streader_read_tuning(Streader* sr, double* cents)
{
    rassert(sr != NULL);
    rassert(cents != NULL);

    if (Streader_is_error_set(sr))
        return false;

    if (Streader_try_match_char(sr, '['))
    {
        int64_t num = 0;
        int64_t den = 0;
        if (!Streader_readf(sr, "%i,%i]", &num, &den))
            return false;

        if (num <= 0)
        {
            Streader_set_error(sr, "Numerator must be positive");
            return false;
        }
        if (den <= 0)
        {
            Streader_set_error(sr, "Denominator must be positive");
            return false;
        }

        *cents = log2((double)num / (double)den) * 1200;
    }
    else
    {
        if (!Streader_read_float(sr, cents))
            return false;

        if (!isfinite(*cents))
        {
            Streader_set_error(sr, "Cents value must be finite");
            return false;
        }
    }

    return true;
}
Beispiel #16
0
bool Streader_read_list(Streader* sr, List_item_reader ir, void* userdata)
{
    rassert(sr != NULL);

    if (Streader_is_error_set(sr))
        return false;

    // Check opening bracket
    if (!(Streader_skip_whitespace(sr) && Streader_match_char(sr, '[')))
    {
        Streader_set_error(sr, "Expected a list opening bracket");
        return false;
    }

    // Check empty list
    if (Streader_try_match_char(sr, ']'))
        return true;

    if (ir == NULL)
    {
        Streader_set_error(sr, "Expected an empty list");
        return false;
    }

    // Read elements
    int32_t index = 0;
    do
    {
        if (!ir(sr, index, userdata))
            return false;
        ++index;
    } while (Streader_try_match_char(sr, ','));

    // Check closing bracket
    if (!Streader_match_char(sr, ']'))
    {
        Streader_set_error(sr, "Expected a list closing bracket");
        return false;
    }

    return true;
}
Beispiel #17
0
static bool read_expressions_def(Streader* sr, const char* key, void* userdata)
{
    rassert(sr != NULL);
    rassert(key != NULL);
    rassert(userdata != NULL);

    Au_expressions* ae = userdata;

    if (string_eq(key, "default_note_expr"))
    {
        char expr[KQT_VAR_NAME_MAX + 1] = "";
        if (!Streader_read_string(sr, KQT_VAR_NAME_MAX + 1, expr))
            return false;

        if ((expr[0] != '\0') && !is_valid_var_name(expr))
        {
            Streader_set_error(sr, "Invalid default note expression: %s", expr);
            return false;
        }

        strcpy(ae->default_note_expr, expr);
    }
    else if (string_eq(key, "expressions"))
    {
        if (!Streader_read_dict(sr, read_expressions, ae))
        {
            rassert(Streader_is_error_set(sr));
            return false;
        }
    }
    else
    {
        Streader_set_error(sr, "Unexpected key in expression specification: %s", key);
        return false;
    }

    return true;
}
Beispiel #18
0
static bool read_ch_defaults_item(Streader* sr, int32_t index, void* userdata)
{
    rassert(sr != NULL);
    rassert(userdata != NULL);

    Channel_defaults_list* cdl = userdata;

    if (index >= KQT_CHANNELS_MAX)
    {
        Streader_set_error(sr, "Too many channel descriptions");
        return false;
    }

    return Channel_defaults_read(&cdl->ch_defaults[index], sr);
}
Beispiel #19
0
Au_expressions* new_Au_expressions(Streader* sr)
{
    rassert(sr != NULL);

    if (Streader_is_error_set(sr))
        return NULL;

    Au_expressions* ae = memory_alloc_item(Au_expressions);
    if (ae == NULL)
    {
        Streader_set_memory_error(
                sr, "Could not allocate memory for audio unit expressions");
        return NULL;
    }

    memset(ae->default_note_expr, '\0', KQT_VAR_NAME_MAX);
    ae->entries = new_AAtree(
            (AAtree_item_cmp*)strcmp, (AAtree_item_destroy*)del_Entry);
    if (ae->entries == NULL)
    {
        Streader_set_memory_error(
                sr, "Could not allocate memory for audio unit expressions");
        del_Au_expressions(ae);
        return NULL;
    }

    if (!Streader_read_dict(sr, read_expressions_def, ae))
    {
        rassert(Streader_is_error_set(sr));
        del_Au_expressions(ae);
        return NULL;
    }

    if (ae->default_note_expr[0] != '\0' &&
            !Au_expressions_get_proc_filter(ae, ae->default_note_expr))
    {
        Streader_set_error(
                sr,
                "Audio unit expressions do not contain the default expression %s",
                ae->default_note_expr);
        del_Au_expressions(ae);
        return NULL;
    }

    return ae;
}
Beispiel #20
0
bool Streader_read_null(Streader* sr)
{
    rassert(sr != NULL);

    if (Streader_is_error_set(sr))
        return false;

    Streader_skip_whitespace(sr);

    if (!Streader_match_char_seq(sr, "null"))
    {
        Streader_set_error(sr, "Expected null");
        return false;
    }

    return true;
}
Beispiel #21
0
static bool read_piref(Streader* sr, int32_t index, void* userdata)
{
    rassert(sr != NULL);
    rassert(userdata != NULL);

    Order_list* ol = userdata;

    // Read the Pattern instance reference
    Pat_inst_ref* p = PAT_INST_REF_AUTO;
    if (!Streader_read_piref(sr, p))
        return false;

    // Check if the Pattern instance is already used
    Index_mapping* key = INDEX_MAPPING_AUTO;
    key->p = *p;
    key->ol_index = index;
    if (AAtree_contains(ol->index_map, key))
    {
        Streader_set_error(
                sr,
                "Duplicate occurrence of pattern instance"
                    " [%" PRId16 ", %" PRId16 "]",
                p->pat, p->inst);
        return false;
    }

    // Add the reference to our containers
    if (!Vector_append(ol->pat_insts, p))
    {
        Streader_set_memory_error(
                sr, "Could not allocate memory for order list");
        return false;
    }

    Index_mapping* im = new_Index_mapping(key);
    if (im == NULL || !AAtree_ins(ol->index_map, im))
    {
        memory_free(im);
        Streader_set_memory_error(
                sr, "Could not allocate memory for order list");
        return false;
    }

    return true;
}
Beispiel #22
0
Tuning_table* new_Tuning_table_from_string(Streader* sr)
{
    rassert(sr != NULL);

    if (Streader_is_error_set(sr))
        return NULL;

    Tuning_table* tt = new_Tuning_table(
            TUNING_TABLE_DEFAULT_REF_PITCH, TUNING_TABLE_DEFAULT_OCTAVE_WIDTH);
    if (tt == NULL)
    {
        Streader_set_memory_error(
                sr, "Couldn't allocate memory for tuning table");
        return NULL;
    }

    if (Streader_has_data(sr))
    {
        if (!Streader_read_dict(sr, read_tuning_table_item, tt))
        {
            del_Tuning_table(tt);
            return NULL;
        }

        if (tt->ref_note >= tt->note_count)
        {
            Streader_set_error(sr,
                     "Reference note doesn't exist: %d", tt->ref_note);
            del_Tuning_table(tt);
            return NULL;
        }
    }

    if (!Tuning_table_build_pitch_map(tt))
    {
        Streader_set_memory_error(sr, "Couldn't allocate memory for tuning table");
        del_Tuning_table(tt);
        return NULL;
    }

    return tt;
}
Beispiel #23
0
static bool read_random_list_entry(Streader* sr, int32_t index, void* userdata)
{
    assert(sr != NULL);
    assert(userdata != NULL);

    if (index >= NOTE_MAP_RANDOMS_MAX)
    {
        Streader_set_error(sr, "Too many note map random list entries");
        return false;
    }

    Random_list* list = userdata;

    if (!Sample_entry_parse(&list->entries[list->entry_count], sr))
        return false;

    list->entries[list->entry_count].ref_freq = list->freq;
    ++list->entry_count;
    return true;
}
Beispiel #24
0
static bool read_random_list_entry(Streader* sr, int32_t index, void* userdata)
{
    rassert(sr != NULL);
    rassert(userdata != NULL);

    Random_list* list = userdata;

    if (index >= HIT_MAP_RANDOMS_MAX)
    {
        Streader_set_error(sr, "Too many hit map random list entries");
        return false;
    }

    if (!Sample_entry_parse(&list->entries[list->entry_count], sr))
        return false;

    ++list->entry_count;

    return true;
}
Beispiel #25
0
static bool read_note(Streader* sr, int32_t index, void* userdata)
{
    rassert(sr != NULL);
    rassert(userdata != NULL);

    if (index >= KQT_TUNING_TABLE_NOTES_MAX)
    {
        Streader_set_error(sr, "Too many notes in the tuning table");
        return false;
    }

    Tuning_table* tt = userdata;

    double cents = NAN;
    if (!Streader_read_tuning(sr, &cents))
        return false;

    Tuning_table_set_note_cents(tt, index, cents);

    return true;
}
Beispiel #26
0
static bool read_expressions(Streader* sr, const char* key, void* userdata)
{
    rassert(sr != NULL);
    rassert(key != NULL);
    rassert(userdata != NULL);

    Au_expressions* ae = userdata;

    if (!is_valid_var_name(key))
    {
        Streader_set_error(sr, "Invalid expression name: %s", key);
        return false;
    }

    Entry* entry = memory_alloc_item(Entry);
    if (entry == NULL)
        return false;

    strcpy(entry->name, key);

    Param_proc_filter* filter = new_Param_proc_filter(sr);
    if (filter == NULL)
    {
        memory_free(entry);
        return false;
    }

    entry->filter = filter;

    if (!AAtree_ins(ae->entries, entry))
    {
        del_Param_proc_filter(filter);
        memory_free(entry);
        return false;
    }

    return true;
}
Beispiel #27
0
bool read_received_events_bind(Streader* sr, int32_t index, void* userdata)
{
    assert(sr != NULL);
    (void)index;
    assert(userdata != NULL);

    int32_t* expected = userdata;
    double actual = NAN;

    if (index == 0 && *expected == 0)
    {
        return Streader_readf(sr, "[0, [") &&
            Streader_match_string(sr, "#") &&
            Streader_match_char(sr, ',') &&
            Streader_read_string(sr, 0, NULL) &&
            Streader_readf(sr, "]]");
    }

    if (!(Streader_readf(sr, "[0, [") &&
                Streader_match_string(sr, "n+") &&
                Streader_readf(sr, ", %f]]", &actual))
       )
        return false;

    if ((int)round(actual) != *expected)
    {
        Streader_set_error(
                sr,
                "Received argument %.0f instead of %" PRId32,
                actual, *expected);
        return false;
    }

    *expected = (int)round(actual) + 1;

    return true;
}
Beispiel #28
0
bool Streader_read_string(Streader* sr, int64_t max_bytes, char* dest)
{
    rassert(sr != NULL);
    rassert(max_bytes >= 0);

    if (Streader_is_error_set(sr))
        return false;

    Streader_skip_whitespace(sr);

    if (Streader_end_reached(sr))
    {
        Streader_set_error(sr, "Unexpected end of data");
        return false;
    }

    // Check opening double quote
    if (CUR_CH != '\"')
    {
        if (isprint(CUR_CH))
            Streader_set_error(
                    sr,
                    "Expected beginning of a string instead of '%c'",
                    CUR_CH);
        else
            Streader_set_error(
                    sr,
                    "Expected beginning of a string instead of %#2x",
                    (unsigned)CUR_CH);
        return false;
    }
    ++sr->pos;

    // Parse and copy the string
    int64_t write_pos = 0;
    while (!Streader_end_reached(sr) && CUR_CH != '\"')
    {
        if (CUR_CH == '\\')
        {
            // Escape sequences
            ++sr->pos;
            if (Streader_end_reached(sr))
            {
                Streader_set_error(sr, "Unexpected end of data");
                return false;
            }

            char special_ch = '\0';
            if (strchr("\"\\/", CUR_CH) != NULL)
                special_ch = CUR_CH;
            else if (CUR_CH == 'b')
                special_ch = '\b';
            else if (CUR_CH == 'f')
                special_ch = '\f';
            else if (CUR_CH == 'n')
                special_ch = '\n';
            else if (CUR_CH == 'r')
                special_ch = '\r';
            else if (CUR_CH == 't')
                special_ch = '\t';
            else if (CUR_CH == 'u')
            {
                static const char* upper_hex_digits = "ABCDEF";
                static const char* lower_hex_digits = "abcdef";

                int32_t code = 0;

                ++sr->pos;
                for (int i = 0; i < 4; ++i)
                {
                    if (Streader_end_reached(sr))
                    {
                        Streader_set_error(sr, "Unexpected end of data");
                        return false;
                    }

                    int32_t value = -1;
                    if (isdigit(CUR_CH))
                        value = CUR_CH - '0';
                    else if (strchr(upper_hex_digits, CUR_CH) != NULL)
                        value = (int32_t)(strchr(upper_hex_digits, CUR_CH) -
                            upper_hex_digits + 0xa);
                    else if (strchr(lower_hex_digits, CUR_CH) != NULL)
                        value = (int32_t)(strchr(lower_hex_digits, CUR_CH) -
                            lower_hex_digits + 0xa);
                    else
                    {
                        char wrong_char[5] = "";
                        print_wrong_char(wrong_char, CUR_CH);
                        Streader_set_error(
                                sr,
                                "Expected a hexadecimal digit instead of %s",
                                wrong_char);
                        return false;
                    }

                    rassert(value >= 0);
                    rassert(value < 0x10);

                    code *= 0x10;
                    code += value;

                    ++sr->pos;
                }

                if (code < 0x20 || code > 0x7e)
                {
                    Streader_set_error(
                            sr,
                            "Unicode character U+%04X outside permitted"
                                " range [U+0020,U+007E]",
                            code);
                    return false;
                }

                special_ch = (char)code;
            }
            else
            {
                if (isprint(CUR_CH))
                    Streader_set_error(
                            sr, "Invalid escape sequence '\\%c'", CUR_CH);
                else
                    Streader_set_error(
                            sr, "Invalid escape sequence %#2x", CUR_CH);
                return false;
            }

            if (special_ch < 0x20 || special_ch > 0x7e)
            {
                char wrong_char[5] = "";
                print_wrong_char(wrong_char, special_ch);
                Streader_set_error(sr, "Invalid special character %s", wrong_char);
                return false;
            }

            if (dest != NULL && write_pos < max_bytes - 1)
                dest[write_pos++] = special_ch;
        }
        else if (iscntrl(CUR_CH))
        {
            Streader_set_error(sr, "Control character %#2x in string");
            return false;
        }
        else
        {
            // Normal characters
            // TODO: check Unicode if needed
            if (dest != NULL && write_pos + 1 < max_bytes)
                dest[write_pos++] = CUR_CH;
        }
        ++sr->pos;
    }

    // Check closing double quote
    if (Streader_end_reached(sr))
    {
        Streader_set_error(sr, "Unexpected end of data");
        return false;
    }
    rassert(CUR_CH == '\"');
    ++sr->pos;

    if (max_bytes > 0 && dest != NULL)
    {
        rassert(write_pos < max_bytes);
        dest[write_pos] = '\0';
    }

    return true;
}
Beispiel #29
0
static bool read_tuning_table_item(Streader* sr, const char* key, void* userdata)
{
    rassert(sr != NULL);
    rassert(key != NULL);
    rassert(userdata != NULL);

    Tuning_table* tt = userdata;

    if (string_eq(key, "ref_note"))
    {
        int64_t num = 0;
        if (!Streader_read_int(sr, &num))
            return false;

        if (num < 0 || num >= KQT_TUNING_TABLE_NOTES_MAX)
        {
            Streader_set_error(
                     sr, "Invalid reference note number: %" PRId64, num);
            return false;
        }

        tt->ref_note = (int)num;
    }
    else if (string_eq(key, "ref_pitch"))
    {
        double num = NAN;
        if (!Streader_read_float(sr, &num))
            return false;

        if (!isfinite(num))
        {
            Streader_set_error(sr, "Invalid reference pitch: %f", num);
            return false;
        }

        tt->ref_pitch = num;
    }
    else if (string_eq(key, "pitch_offset"))
    {
        double cents = NAN;
        if (!Streader_read_float(sr, &cents))
            return false;

        if (!isfinite(cents))
        {
            Streader_set_error(sr, "Pitch offset is not finite");
            return false;
        }

        tt->global_offset = cents;
    }
    else if (string_eq(key, "octave_width"))
    {
        double cents = NAN;
        if (!Streader_read_tuning(sr, &cents))
            return false;

        if (cents <= 0)
        {
            Streader_set_error(sr, "Octave width must be positive");
            return false;
        }

        Tuning_table_set_octave_width(tt, cents);
    }
    else if (string_eq(key, "centre_octave"))
    {
        int64_t octave = -1;
        if (!Streader_read_int(sr, &octave))
            return false;

        if (octave < 0 || octave >= KQT_TUNING_TABLE_OCTAVES)
        {
            Streader_set_error(sr, "Invalid centre octave: %" PRId64, octave);
            return false;
        }

        tt->centre_octave = (int)octave;
        Tuning_table_set_octave_width(tt, tt->octave_width);
    }
    else if (string_eq(key, "notes"))
    {
        for (int i = 0; i < KQT_TUNING_TABLE_NOTES_MAX; ++i)
            tt->note_offsets[i] = NAN;

        if (!Streader_read_list(sr, read_note, tt))
            return false;
    }
    else
    {
        Streader_set_error(sr, "Unrecognised key in tuning table: %s", key);
        return false;
    }

    return true;
}
Beispiel #30
0
bool Streader_read_float(Streader* sr, double* dest)
{
    rassert(sr != NULL);

    if (Streader_is_error_set(sr))
        return false;

    Streader_skip_whitespace(sr);

    // Note: Not completely accurate, but not supposed to be portable anyway...

    bool is_negative = false;
    int64_t significand = 0;
    int significand_shift = 0;
    int significant_digits_read = 0;

    int exponent = 0;
    bool exponent_is_negative = false;

    // Negation
    if (Streader_try_match_char(sr, '-'))
        is_negative = true;

    if (Streader_end_reached(sr))
    {
        Streader_set_error(sr, "No digits found");
        return false;
    }

    // Significand
    if (CUR_CH == '0')
    {
        ++sr->pos;
    }
    else if (strchr(NONZERO_DIGITS, CUR_CH) != NULL)
    {
        while (!Streader_end_reached(sr) && isdigit(CUR_CH))
        {
            if (significant_digits_read < SIGNIFICANT_MAX)
            {
                // Store the digit into our significand
                rassert(significand < INT64_MAX / 10);
                significand *= 10;
                significand += (int64_t)(CUR_CH - '0');
                ++significant_digits_read;
            }
            else
            {
                // We have run out of accuracy, just update magnitude
                ++significand_shift;
            }

            ++sr->pos;
        }
    }
    else
    {
        Streader_set_error(sr, "No digits found");
        return false;
    }

    // Decimal part
    if (!Streader_end_reached(sr) && CUR_CH == '.')
    {
        ++sr->pos;

        while (!Streader_end_reached(sr) && isdigit(CUR_CH))
        {
            if (significant_digits_read < SIGNIFICANT_MAX)
            {
                // Append digit to our significand and compensate in shift
                rassert(significand < INT64_MAX / 10);
                significand *= 10;
                significand += (int64_t)(CUR_CH - '0');
                --significand_shift;

                if (significand != 0)
                    ++significant_digits_read;
            }

            ++sr->pos;
        }

        // Require at least one digit
        if (sr->str[sr->pos - 1] == '.')
        {
            Streader_set_error(sr, "No digits found after decimal point");
            return false;
        }
    }

    // Exponent part
    if (!Streader_end_reached(sr) &&
            ((CUR_CH == 'e') || (CUR_CH == 'E'))
       )
    {
        ++sr->pos;

        if (Streader_end_reached(sr))
        {
            Streader_set_error(sr, "No digits found after exponent indicator");
            return false;
        }

        if (CUR_CH == '+')
        {
            ++sr->pos;
        }
        else if (CUR_CH == '-')
        {
            exponent_is_negative = true;
            ++sr->pos;
        }

        while (!Streader_end_reached(sr) && isdigit(CUR_CH))
        {
            rassert(exponent < INT_MAX / 10);
            exponent *= 10;
            exponent += (int)(CUR_CH - '0');

            ++sr->pos;
        }

        // Require at least one digit
        if (!isdigit(sr->str[sr->pos - 1]))
        {
            Streader_set_error(sr, "No digits found after exponent indicator");
            return false;
        }
    }

    if (!Streader_end_reached(sr) && isalpha(CUR_CH))
    {
        Streader_set_error(sr, "Trailing letters after a number");
        return false;
    }

    // Optimise trailing zeros away from the significand
    if (significand != 0)
    {
        while (significand % 10 == 0)
        {
            significand /= 10;
            ++significand_shift;
        }
    }

    // Convert the number
    if (exponent_is_negative)
        exponent = -exponent;
    int final_shift = significand_shift + exponent;

    double result = (double)significand;

    double abs_magnitude = pow(10, abs(final_shift));
    if (final_shift >= 0)
        result *= abs_magnitude;
    else
        result /= abs_magnitude;

    if (is_negative)
        result = -result;

    if (dest != NULL)
        *dest = result;

    return true;
}