/* parse stations returned by pandora * @param piano handle * @param xml returned by pandora * @return _RET_OK or error */ PianoReturn_t PianoXmlParseStations (PianoHandle_t *ph, char *xml) { ezxml_t xmlDoc, dataNode; PianoReturn_t ret; char **quickMixIds = NULL, **curQuickMixId = NULL; if ((ret = PianoXmlInitDoc (xml, &xmlDoc)) != PIANO_RET_OK) { return ret; } dataNode = ezxml_get (xmlDoc, "params", 0, "param", 0, "value", 0, "array", 0, "data", -1); for (dataNode = ezxml_child (dataNode, "value"); dataNode; dataNode = dataNode->next) { PianoStation_t *tmpStation; if ((tmpStation = calloc (1, sizeof (*tmpStation))) == NULL) { ezxml_free (xmlDoc); return PIANO_RET_OUT_OF_MEMORY; } PianoXmlStructParser (ezxml_child (dataNode, "struct"), PianoXmlParseStationsCb, tmpStation); /* get stations selected for quickmix */ if (tmpStation->isQuickMix) { PianoXmlStructParser (ezxml_child (dataNode, "struct"), PianoXmlParseQuickMixStationsCb, &quickMixIds); } /* start new linked list or append */ if (ph->stations == NULL) { ph->stations = tmpStation; } else { PianoStation_t *curStation = ph->stations; while (curStation->next != NULL) { curStation = curStation->next; } curStation->next = tmpStation; } } /* set quickmix flags after all stations are read */ if (quickMixIds != NULL) { curQuickMixId = quickMixIds; while (*curQuickMixId != NULL) { PianoStation_t *curStation = PianoFindStationById (ph->stations, *curQuickMixId); if (curStation != NULL) { curStation->useQuickMix = 1; } free (*curQuickMixId); curQuickMixId++; } free (quickMixIds); } ezxml_free (xmlDoc); return PIANO_RET_OK; }
/* callback for xml struct parser used in PianoXmlParseSearch, "switch" for * PianoXmlParseSearchArtistCb and PianoXmlParsePlaylistCb */ static void PianoXmlParseSearchCb (const char *key, const ezxml_t value, void *data) { PianoSearchResult_t *searchResult = data; ezxml_t curNode; if (strcmp ("artists", key) == 0) { /* skip <value><array><data> */ for (curNode = ezxml_child (ezxml_get (value, "array", 0, "data", -1), "value"); curNode; curNode = curNode->next) { PianoArtist_t *artist; if ((artist = calloc (1, sizeof (*artist))) == NULL) { /* fail silently */ break; } memset (artist, 0, sizeof (*artist)); PianoXmlStructParser (ezxml_child (curNode, "struct"), PianoXmlParseSearchArtistCb, artist); /* add result to linked list */ if (searchResult->artists == NULL) { searchResult->artists = artist; } else { PianoArtist_t *curArtist = searchResult->artists; while (curArtist->next != NULL) { curArtist = curArtist->next; } curArtist->next = artist; } } } else if (strcmp ("songs", key) == 0) { for (curNode = ezxml_child (ezxml_get (value, "array", 0, "data", -1), "value"); curNode; curNode = curNode->next) { /* FIXME: copy & waste */ PianoSong_t *tmpSong; if ((tmpSong = calloc (1, sizeof (*tmpSong))) == NULL) { /* fail silently */ break; } PianoXmlStructParser (ezxml_child (curNode, "struct"), PianoXmlParsePlaylistCb, tmpSong); /* begin linked list or append */ if (searchResult->songs == NULL) { searchResult->songs = tmpSong; } else { PianoSong_t *curSong = searchResult->songs; while (curSong->next != NULL) { curSong = curSong->next; } curSong->next = tmpSong; } } } }
/* parse "create station" answer (it returns a new station structure) * @param piano handle * @param xml document * @return nothing yet */ PianoReturn_t PianoXmlParseCreateStation (PianoHandle_t *ph, char *xml) { ezxml_t xmlDoc, dataNode; PianoStation_t *tmpStation; PianoReturn_t ret; if ((ret = PianoXmlInitDoc (xml, &xmlDoc)) != PIANO_RET_OK) { return ret; } dataNode = ezxml_get (xmlDoc, "params", 0, "param", 0, "value", 0, "struct", -1); if ((tmpStation = calloc (1, sizeof (*tmpStation))) == NULL) { ezxml_free (xmlDoc); return PIANO_RET_OUT_OF_MEMORY; } PianoXmlStructParser (dataNode, PianoXmlParseStationsCb, tmpStation); /* FIXME: copy & waste */ /* start new linked list or append */ if (ph->stations == NULL) { ph->stations = tmpStation; } else { PianoStation_t *curStation = ph->stations; while (curStation->next != NULL) { curStation = curStation->next; } curStation->next = tmpStation; } ezxml_free (xmlDoc); return PIANO_RET_OK; }
static PianoReturn_t PianoXmlParsePlaylistStruct (ezxml_t xml, PianoSong_t **retSong) { PianoSong_t *playlist = *retSong, *tmpSong; if ((tmpSong = calloc (1, sizeof (*tmpSong))) == NULL) { return PIANO_RET_OUT_OF_MEMORY; } PianoXmlStructParser (ezxml_child (xml, "struct"), PianoXmlParsePlaylistCb, tmpSong); /* begin linked list or append */ if (playlist == NULL) { playlist = tmpSong; } else { PianoSong_t *curSong = playlist; while (curSong->next != NULL) { curSong = curSong->next; } curSong->next = tmpSong; } *retSong = playlist; return PIANO_RET_OK; }
/* parse getStation xml struct */ static void PianoXmlParseGetStationInfoCb (const char *key, const ezxml_t value, void *data) { PianoStationInfo_t *info = data; if (strcmp ("seeds", key) == 0) { const ezxml_t dataNode = ezxml_get (value, "array", 0, "data", -1); for (ezxml_t seedNode = ezxml_child (dataNode, "value"); seedNode; seedNode = seedNode->next) { struct PianoXmlParseSeedBag bag; memset (&bag, 0, sizeof (bag)); PianoXmlStructParser (ezxml_child (seedNode, "struct"), PianoXmlParseSeedCb, &bag); /* FIXME: use if-clause */ assert (bag.seedId != NULL); assert (bag.song != NULL || bag.artist != NULL); if (bag.song != NULL) { bag.song->seedId = bag.seedId; if (info->songSeeds == NULL) { info->songSeeds = bag.song; } else { PianoSong_t *curSong = info->songSeeds; while (curSong->next != NULL) { curSong = curSong->next; } curSong->next = bag.song; } } else if (bag.artist != NULL) { bag.artist->seedId = bag.seedId; if (info->artistSeeds == NULL) { info->artistSeeds = bag.artist; } else { PianoArtist_t *curSong = info->artistSeeds; while (curSong->next != NULL) { curSong = curSong->next; } curSong->next = bag.artist; } } else { free (bag.seedId); } } } else if (strcmp ("feedback", key) == 0) { const ezxml_t dataNode = ezxml_get (value, "array", 0, "data", -1); for (ezxml_t feedbackNode = ezxml_child (dataNode, "value"); feedbackNode; feedbackNode = feedbackNode->next) { if (PianoXmlParsePlaylistStruct (feedbackNode, &info->feedback) != PIANO_RET_OK) { break; } } } }
/* check whether pandora returned an error or not * @param document root of xml doc * @return _RET_OK or fault code (_RET_*) */ static PianoReturn_t PianoXmlIsFault (ezxml_t xmlDoc) { PianoReturn_t ret; if ((xmlDoc = ezxml_child (xmlDoc, "fault")) != NULL) { xmlDoc = ezxml_get (xmlDoc, "value", 0, "struct", -1); PianoXmlStructParser (xmlDoc, PianoXmlIsFaultCb, &ret); return ret; } return PIANO_RET_OK; }
/* parse seed struct */ static void PianoXmlParseSeedCb (const char *key, const ezxml_t value, void *data) { struct PianoXmlParseSeedBag *bag = data; assert (bag != NULL); if (strcmp ("song", key) == 0) { assert (bag->song == NULL); if ((bag->song = calloc (1, sizeof (*bag->song))) == NULL) { return; } PianoXmlStructParser (ezxml_child (value, "struct"), PianoXmlParsePlaylistCb, bag->song); } else if (strcmp ("artist", key) == 0) { assert (bag->artist == NULL); if ((bag->artist = calloc (1, sizeof (*bag->artist))) == NULL) { return; } PianoXmlStructParser (ezxml_child (value, "struct"), PianoXmlParseSearchArtistCb, bag->artist); } else if (strcmp ("nonGenomeStation", key) == 0) { /* genre stations are "non genome" station seeds */ assert (bag->station == NULL); if ((bag->station = calloc (1, sizeof (*bag->station))) == NULL) { return; } PianoXmlStructParser (ezxml_child (value, "struct"), PianoXmlParseStationsCb, bag->station); } else if (strcmp ("seedId", key) == 0) { char *valueStr = PianoXmlGetNodeText (value); bag->seedId = strdup (valueStr); } }
/* parses userinfos sent by pandora as login response * @param piano handle * @param utf-8 string * @return _RET_OK or error */ PianoReturn_t PianoXmlParseUserinfo (PianoHandle_t *ph, char *xml) { ezxml_t xmlDoc, structNode; PianoReturn_t ret; if ((ret = PianoXmlInitDoc (xml, &xmlDoc)) != PIANO_RET_OK) { return ret; } /* <methodResponse> <params> <param> <value> <struct> */ structNode = ezxml_get (xmlDoc, "params", 0, "param", 0, "value", 0, "struct", -1); PianoXmlStructParser (structNode, PianoXmlParseUserinfoCb, &ph->user); ezxml_free (xmlDoc); return PIANO_RET_OK; }
/* parse getStation response */ PianoReturn_t PianoXmlParseGetStationInfo (char *xml, PianoStationInfo_t *stationInfo) { ezxml_t xmlDoc, dataNode; PianoReturn_t ret; if ((ret = PianoXmlInitDoc (xml, &xmlDoc)) != PIANO_RET_OK) { return ret; } dataNode = ezxml_get (xmlDoc, "params", 0, "param", 0, "value", 0, "struct", -1); PianoXmlStructParser (dataNode, PianoXmlParseGetStationInfoCb, stationInfo); ezxml_free (xmlDoc); return PIANO_RET_OK; }
/* parse "add seed" answer, nearly the same as ParseCreateStation * @param piano handle * @param xml document * @param update this station */ PianoReturn_t PianoXmlParseAddSeed (char *xml, PianoStation_t *station) { ezxml_t xmlDoc, dataNode; PianoReturn_t ret; if ((ret = PianoXmlInitDoc (xml, &xmlDoc)) != PIANO_RET_OK) { return ret; } dataNode = ezxml_get (xmlDoc, "params", 0, "param", 0, "value", 0, "struct", -1); PianoDestroyStation (station); PianoXmlStructParser (dataNode, PianoXmlParseStationsCb, station); ezxml_free (xmlDoc); return PIANO_RET_OK; }
/* parse search result; searchResult is nulled before use * @param xml document * @param returns search result * @return nothing yet */ PianoReturn_t PianoXmlParseSearch (char *xml, PianoSearchResult_t *searchResult) { ezxml_t xmlDoc, dataNode; PianoReturn_t ret; if ((ret = PianoXmlInitDoc (xml, &xmlDoc)) != PIANO_RET_OK) { return ret; } dataNode = ezxml_get (xmlDoc, "params", 0, "param", 0, "value", 0, "struct", -1); /* we need a "clean" search result (with null pointers) */ memset (searchResult, 0, sizeof (*searchResult)); PianoXmlStructParser (dataNode, PianoXmlParseSearchCb, searchResult); ezxml_free (xmlDoc); return PIANO_RET_OK; }
/* callback for xml struct parser used in PianoXmlParseSearch, "switch" for * PianoXmlParseSearchArtistCb and PianoXmlParsePlaylistCb */ static void PianoXmlParseSearchCb (const char *key, const ezxml_t value, void *data) { PianoSearchResult_t *searchResult = data; ezxml_t curNode; if (strcmp ("artists", key) == 0) { /* skip <value><array><data> */ for (curNode = ezxml_child (ezxml_get (value, "array", 0, "data", -1), "value"); curNode; curNode = curNode->next) { PianoArtist_t *artist; if ((artist = calloc (1, sizeof (*artist))) == NULL) { /* fail silently */ break; } memset (artist, 0, sizeof (*artist)); PianoXmlStructParser (ezxml_child (curNode, "struct"), PianoXmlParseSearchArtistCb, artist); /* add result to linked list */ if (searchResult->artists == NULL) { searchResult->artists = artist; } else { PianoArtist_t *curArtist = searchResult->artists; while (curArtist->next != NULL) { curArtist = curArtist->next; } curArtist->next = artist; } } } else if (strcmp ("songs", key) == 0) { for (curNode = ezxml_child (ezxml_get (value, "array", 0, "data", -1), "value"); curNode; curNode = curNode->next) { if (PianoXmlParsePlaylistStruct (curNode, &searchResult->songs) != PIANO_RET_OK) { break; } } } }
/* parses playlist; used when searching too * @param piano handle * @param xml document * @param return: playlist */ PianoReturn_t PianoXmlParsePlaylist (PianoHandle_t *ph, char *xml, PianoSong_t **retPlaylist) { ezxml_t xmlDoc, dataNode; PianoReturn_t ret; if ((ret = PianoXmlInitDoc (xml, &xmlDoc)) != PIANO_RET_OK) { return ret; } dataNode = ezxml_get (xmlDoc, "params", 0, "param", 0, "value", 0, "array", 0, "data", -1); for (dataNode = ezxml_child (dataNode, "value"); dataNode; dataNode = dataNode->next) { PianoSong_t *tmpSong; if ((tmpSong = calloc (1, sizeof (*tmpSong))) == NULL) { ezxml_free (xmlDoc); return PIANO_RET_OUT_OF_MEMORY; } PianoXmlStructParser (ezxml_child (dataNode, "struct"), PianoXmlParsePlaylistCb, tmpSong); /* begin linked list or append */ if (*retPlaylist == NULL) { *retPlaylist = tmpSong; } else { PianoSong_t *curSong = *retPlaylist; while (curSong->next != NULL) { curSong = curSong->next; } curSong->next = tmpSong; } } ezxml_free (xmlDoc); return PIANO_RET_OK; }