<commit_before>/*
    This file is part of Sylverant PSO Server.

    Copyright (C) 2009, 2010, 2011 <NAME>

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License version 3
    as published by the Free Software Foundation.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Affero General Public License for more details.

    You should have received a copy of the GNU Affero General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>

#include <libxml/parser.h>
#include <libxml/tree.h>

#include "sylverant/quest.h"
#include "sylverant/debug.h"

#ifndef LIBXML_TREE_ENABLED
#error You must have libxml2 with tree support built-in.
#endif

#define XC (const xmlChar *)

static int handle_long(xmlNode *n, sylverant_quest_t *q) {
    xmlChar *desc;

    /* Grab the long description from the node */
    if((desc = xmlNodeListGetString(n->doc, n->children, 1))) {
        q->long_desc = (char *)desc;
    }

    return 0;
}

static int handle_short(xmlNode *n, sylverant_quest_t *q) {
    xmlChar *desc;

    /* Grab the short description from the node */
    if((desc = xmlNodeListGetString(n->doc, n->children, 1))) {
        strncpy(q->desc, desc, 111);
        q->desc[111] = '\0';
        xmlFree(desc);
    }

    return 0;
}

static int handle_quest(xmlNode *n, sylverant_quest_category_t *c) {
    xmlChar *name, *prefix, *v1, *v2, *gc, *bb, *ep, *event, *fmt, *id;
    int rv = 0, format;
    void *tmp;
    unsigned long episode, id_num;
    long event_num;
    sylverant_quest_t *q;

    /* Grab the attributes we're expecting */
    name = xmlGetProp(n, XC"name");
    prefix = xmlGetProp(n, XC"prefix");
    v1 = xmlGetProp(n, XC"v1");
    v2 = xmlGetProp(n, XC"v2");
    gc = xmlGetProp(n, XC"gc");
    bb = xmlGetProp(n, XC"bb");
    ep = xmlGetProp(n, XC"episode");
    event = xmlGetProp(n, XC"event");
    fmt = xmlGetProp(n, XC"format");
    id = xmlGetProp(n, XC"id");

    /* Make sure we have all of them... */
    if(!name || !prefix || !v1 || !v2 || !gc || !bb || !ep || !event || !fmt ||
       !id) {
        debug(DBG_ERROR, "One or more required quest attributes missing\n");
        rv = -1;
        goto err;
    }

    /* Make sure the episode is sane */
    episode = strtoul(ep, NULL, 0);

    if(episode < 1 || episode > 4) {
        debug(DBG_ERROR, "Invalid episode given: %s\n", ep);
        rv = -2;
        goto err;
    }

    /* Make sure the format is sane */
    if(!xmlStrcmp(fmt, XC"qst")) {
        format = SYLVERANT_QUEST_QST;
    }
    else if(!xmlStrcmp(fmt, XC"bindat")) {
        format = SYLVERANT_QUEST_BINDAT;
    }
    else {
        debug(DBG_ERROR, "Invalid format given for quest: %s\n", fmt);
        rv = -3;
        goto err;
    }

    /* Make sure the event is sane */
    errno = 0;
    event_num = strtol(event, NULL, 0);

    if(errno || event_num < -1 || event_num > 14) {
        debug(DBG_ERROR, "Invalid event given for quest: %s\n", event);
        rv = -4;
        goto err;
    }

    /* Make sure the id is sane */
    errno = 0;
    id_num = strtoul(id, NULL, 0);

    if(errno) {
        debug(DBG_ERROR, "Invalid ID given for quest: %s\n", id);
        rv = -5;
        goto err;
    }

    /* Allocate space for the quest */
    tmp = realloc(c->quests, (c->quest_count + 1) * sizeof(sylverant_quest_t));

    if(!tmp) {
        debug(DBG_ERROR, "Couldn't allocate space for quest\n");
        perror("realloc");
        rv = -6;
        goto err;
    }

    c->quests = (sylverant_quest_t *)tmp;
    q = c->quests + c->quest_count++;

    /* Clear the quest out */
    memset(q, 0, sizeof(sylverant_quest_t));

    /* Copy over what we have so far */
    q->qid = (uint32_t)id_num;
    q->episode = (int)episode;
    q->event = (int)event_num;
    q->format = (int)format;

    strncpy(q->name, name, 31);
    q->name[31] = '\0';
    q->prefix = prefix;

    /* Fill in the versions */
    if(!xmlStrcmp(v1, XC"true")) {
        q->versions |= SYLVERANT_QUEST_V1;
    }
    if(!xmlStrcmp(v2, XC"true")) {
        q->versions |= SYLVERANT_QUEST_V2;
    }
    if(!xmlStrcmp(gc, XC"true")) {
        q->versions |= SYLVERANT_QUEST_GC;
    }
    if(!xmlStrcmp(bb, XC"true")) {
        q->versions |= SYLVERANT_QUEST_BB;
    }

    /* Now that we're done with that, deal with any children of the node */
    n = n->children;
    while(n) {
        if(n->type != XML_ELEMENT_NODE) {
            /* Ignore non-elements. */
            n = n->next;
            continue;<commit_msg>Allow multiple events to be specified in the quests XML. They can be separated by commas and/or spaces.<commit_after>/*
    This file is part of Sylverant PSO Server.

    Copyright (C) 2009, 2010, 2011 <NAME>

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License version 3
    as published by the Free Software Foundation.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Affero General Public License for more details.

    You should have received a copy of the GNU Affero General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>

#include <libxml/parser.h>
#include <libxml/tree.h>

#include "sylverant/quest.h"
#include "sylverant/debug.h"

#ifndef LIBXML_TREE_ENABLED
#error You must have libxml2 with tree support built-in.
#endif

#define XC (const xmlChar *)

static int handle_long(xmlNode *n, sylverant_quest_t *q) {
    xmlChar *desc;

    /* Grab the long description from the node */
    if((desc = xmlNodeListGetString(n->doc, n->children, 1))) {
        q->long_desc = (char *)desc;
    }

    return 0;
}

static int handle_short(xmlNode *n, sylverant_quest_t *q) {
    xmlChar *desc;

    /* Grab the short description from the node */
    if((desc = xmlNodeListGetString(n->doc, n->children, 1))) {
        strncpy(q->desc, desc, 111);
        q->desc[111] = '\0';
        xmlFree(desc);
    }

    return 0;
}

static int handle_quest(xmlNode *n, sylverant_quest_category_t *c) {
    xmlChar *name, *prefix, *v1, *v2, *gc, *bb, *ep, *event, *fmt, *id;
    int rv = 0, format;
    void *tmp;
    unsigned long episode, id_num;
    long event_num;
    sylverant_quest_t *q;
    char *lasts, *token;
    int event_list = 0;

    /* Grab the attributes we're expecting */
    name = xmlGetProp(n, XC"name");
    prefix = xmlGetProp(n, XC"prefix");
    v1 = xmlGetProp(n, XC"v1");
    v2 = xmlGetProp(n, XC"v2");
    gc = xmlGetProp(n, XC"gc");
    bb = xmlGetProp(n, XC"bb");
    ep = xmlGetProp(n, XC"episode");
    event = xmlGetProp(n, XC"event");
    fmt = xmlGetProp(n, XC"format");
    id = xmlGetProp(n, XC"id");

    /* Make sure we have all of them... */
    if(!name || !prefix || !v1 || !v2 || !gc || !bb || !ep || !event || !fmt ||
       !id) {
        debug(DBG_ERROR, "One or more required quest attributes missing\n");
        rv = -1;
        goto err;
    }

    /* Make sure the episode is sane */
    episode = strtoul(ep, NULL, 0);

    if(episode < 1 || episode > 4) {
        debug(DBG_ERROR, "Invalid episode given: %s\n", ep);
        rv = -2;
        goto err;
    }

    /* Make sure the format is sane */
    if(!xmlStrcmp(fmt, XC"qst")) {
        format = SYLVERANT_QUEST_QST;
    }
    else if(!xmlStrcmp(fmt, XC"bindat")) {
        format = SYLVERANT_QUEST_BINDAT;
    }
    else {
        debug(DBG_ERROR, "Invalid format given for quest: %s\n", fmt);
        rv = -3;
        goto err;
    }

    /* Make sure the event list is sane */
    token = strtok_r((char *)event, ", ", &lasts);

    if(!token) {
        debug(DBG_ERROR, "Invalid event given for quest: %s\n", event);
        rv = -4;
        goto err;
    }

    while(token) {
        /* Parse the token */
        errno = 0;
        event_num = strtol(token, NULL, 0);

        if(errno || event_num < -1 || event_num > 14) {
            debug(DBG_ERROR, "Invalid token in event: %s\n", token);
            rv = -9;
            goto err;
        }

        /* Make sure its valid now */
        if(event_list == -1) {
            debug(DBG_ERROR, "Invalid event number specified after -1: %s\n",
                  token);
            rv = -10;
            goto err;
        }
        else if(event_list != 0 && event_num == -1) {
            debug(DBG_ERROR, "Invalid to specify -1 after an event\n");
            rv = -11;
            goto err;
        }

        /* Set the bit for the specified event */
        if(event_num == -1) {
            event_list = -1;
        }
        else {
            event_list |= (1 << event_num);
        }

        /* Read the next event in, if any */
        token = strtok_r(NULL, ", ", &lasts);
    }

    /* Make sure the id is sane */
    errno = 0;
    id_num = strtoul(id, NULL, 0);

    if(errno) {
        debug(DBG_ERROR, "Invalid ID given for quest: %s\n", id);
        rv = -5;
        goto err;
    }

    /* Allocate space for the quest */
    tmp = realloc(c->quests, (c->quest_count + 1) * sizeof(sylverant_quest_t));

    if(!tmp) {
        debug(DBG_ERROR, "Couldn't allocate space for quest\n");
        perror("realloc");
        rv = -6;
        goto err;
    }

    c->quests = (sylverant_quest_t *)tmp;
    q = c->quests + c->quest_count++;

    /* Clear the quest out */
    memset(q, 0, sizeof(sylverant_quest_t));

    /* Copy over what we have so far */
    q->qid = (uint32_t)id_num;
    q->episode = (int)episode;
    q->event = (int)event_list;
    q->format = (int)format;

    strncpy(q->name, name, 31);
    q->name[31] = '\0';
    q->prefix = prefix;

    /* Fill in the versions */
    if(!xmlStrcmp(v1, XC"true")) {
        q->versions |= SYLVERANT_QUEST_V1;
    }
    if(!xmlStrcmp(v2, XC"true")) {
        q->versions |= SYLVERANT_QUEST_V2;
    }
    if(!xmlStrcmp(gc, XC"true")) {
        q->versions |= SYLVERANT_QUEST_GC;
    }
    if(!xmlStrcmp(bb, XC"true")) {
        q->versions |= SYLVERANT_QUEST_BB;
    }

    /* Now that we're done with that, deal with any children of the node */
    n = n->children;
    while(n) {
        if(n->type != XML_ELEMENT_NODE) {
            /* Ignore non-elements. */
            n = n->next;
            continue;
{'fraction_non_alphanumeric': 0.13912881954119066, 'fraction_numerical': 0.01300269341506455, 'mean_word_length': 2.2899480598838986, 'pattern_counts': {'":': 0, '<': 27, '<?xml version=': 0, '>': 77, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 58}, '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': '1953889', 'n_tokens_mistral': 3890, 'n_tokens_neox': 3726, 'n_words': 1089}