diff options
Diffstat (limited to 'src/libpiano')
| -rw-r--r-- | src/libpiano/response.c | 179 | 
1 files changed, 105 insertions, 74 deletions
| diff --git a/src/libpiano/response.c b/src/libpiano/response.c index 8b6ed52..e37824e 100644 --- a/src/libpiano/response.c +++ b/src/libpiano/response.c @@ -1,5 +1,5 @@  /* -Copyright (c) 2008-2013 +Copyright (c) 2008-2017  	Lars-Dominik Braun <lars@6xq.net>  Permission is hereby granted, free of charge, to any person obtaining a copy @@ -34,16 +34,34 @@ THE SOFTWARE.  #include "crypt.h"  static char *PianoJsonStrdup (json_object *j, const char *key) { -	return strdup (json_object_get_string (json_object_object_get (j, key))); +	assert (j != NULL); +	assert (key != NULL); + +	json_object *v; +	if (json_object_object_get_ex (j, key, &v)) { +		return strdup (json_object_get_string (v)); +	} else { +		return NULL; +	} +} + +static bool getBoolDefault (json_object * const j, const char * const key, const bool def) { +	assert (j != NULL); +	assert (key != NULL); + +	json_object *v; +	if (json_object_object_get_ex (j, key, &v)) { +		return json_object_get_boolean (v); +	} else { +		return def; +	}  }  static void PianoJsonParseStation (json_object *j, PianoStation_t *s) {  	s->name = PianoJsonStrdup (j, "stationName");  	s->id = PianoJsonStrdup (j, "stationToken"); -	s->isCreator = !json_object_get_boolean (json_object_object_get (j, -			"isShared")); -	s->isQuickMix = json_object_get_boolean (json_object_object_get (j, -			"isQuickMix")); +	s->isCreator = !getBoolDefault (j, "isShared", !false); +	s->isQuickMix = getBoolDefault (j, "isQuickMix", false);  }  /*	concat strings @@ -77,23 +95,22 @@ static void PianoStrpcat (char * restrict dest, const char * restrict src,   */  PianoReturn_t PianoResponse (PianoHandle_t *ph, PianoRequest_t *req) {  	PianoReturn_t ret = PIANO_RET_OK; -	json_object *j, *result, *status;  	assert (ph != NULL);  	assert (req != NULL); -	j = json_tokener_parse (req->responseData); +	json_object * const j = json_tokener_parse (req->responseData); -	status = json_object_object_get (j, "stat"); -	if (status == NULL) { -		json_object_put (j); -		return PIANO_RET_INVALID_RESPONSE; +	json_object *status; +	if (!json_object_object_get_ex (j, "stat", &status)) { +		ret = PIANO_RET_INVALID_RESPONSE; +		goto cleanup;  	}  	/* error handling */  	if (strcmp (json_object_get_string (status), "ok") != 0) { -		json_object *code = json_object_object_get (j, "code"); -		if (code == NULL) { +		json_object *code; +		if (!json_object_object_get_ex (j, "code", &code)) {  			ret = PIANO_RET_INVALID_RESPONSE;  		} else {  			ret = json_object_get_int (code)+PIANO_RET_OFFSET; @@ -110,11 +127,12 @@ PianoReturn_t PianoResponse (PianoHandle_t *ph, PianoRequest_t *req) {  			}  		} -		json_object_put (j); -		return ret; +		goto cleanup;  	} -	result = json_object_object_get (j, "result"); +	json_object *result = NULL; +	/* missing for some request types */ +	json_object_object_get_ex (j, "result", &result);  	switch (req->type) {  		case PIANO_REQUEST_LOGIN: { @@ -127,8 +145,14 @@ PianoReturn_t PianoResponse (PianoHandle_t *ph, PianoRequest_t *req) {  			switch (reqData->step) {  				case 0: {  					/* decrypt timestamp */ -					const char * const cryptedTimestamp = json_object_get_string ( -							json_object_object_get (result, "syncTime")); +					json_object *jsonTimestamp; +					if (!json_object_object_get_ex (result, "syncTime", &jsonTimestamp)) { +						ret = PIANO_RET_INVALID_RESPONSE; +						break; +					} +					assert (jsonTimestamp != NULL); +					const char * const cryptedTimestamp = json_object_get_string (jsonTimestamp); +					assert (cryptedTimestamp != NULL);  					const time_t realTimestamp = time (NULL);  					char *decryptedTimestamp = NULL;  					size_t decryptedSize; @@ -148,8 +172,12 @@ PianoReturn_t PianoResponse (PianoHandle_t *ph, PianoRequest_t *req) {  					/* get auth token */  					ph->partner.authToken = PianoJsonStrdup (result,  							"partnerAuthToken"); -					ph->partner.id = json_object_get_int ( -							json_object_object_get (result, "partnerId")); +					json_object *partnerId; +					if (!json_object_object_get_ex (result, "partnerId", &partnerId)) { +						ret = PIANO_RET_INVALID_RESPONSE; +						break; +					} +					ph->partner.id = json_object_get_int (partnerId);  					++reqData->step;  					break;  				} @@ -172,8 +200,11 @@ PianoReturn_t PianoResponse (PianoHandle_t *ph, PianoRequest_t *req) {  			/* get stations */  			assert (req->responseData != NULL); -			json_object *stations = json_object_object_get (result, -					"stations"), *mix = NULL; +			json_object *stations, *mix = NULL; + +			if (!json_object_object_get_ex (result, "stations", &stations)) { +				break; +			}  			for (int i = 0; i < json_object_array_length (stations); i++) {  				PianoStation_t *tmpStation; @@ -187,7 +218,7 @@ PianoReturn_t PianoResponse (PianoHandle_t *ph, PianoRequest_t *req) {  				if (tmpStation->isQuickMix) {  					/* fix flags on other stations later */ -					mix = json_object_object_get (s, "quickMixStationIds"); +					json_object_object_get_ex (s, "quickMixStationIds", &mix);  				}  				/* start new linked list or append */ @@ -219,7 +250,10 @@ PianoReturn_t PianoResponse (PianoHandle_t *ph, PianoRequest_t *req) {  			assert (reqData != NULL);  			assert (reqData->quality != PIANO_AQ_UNKNOWN); -			json_object *items = json_object_object_get (result, "items"); +			json_object *items = NULL; +			if (!json_object_object_get_ex (result, "items", &items)) { +				break; +			}  			assert (items != NULL);  			for (int i = 0; i < json_object_array_length (items); i++) { @@ -230,7 +264,7 @@ PianoReturn_t PianoResponse (PianoHandle_t *ph, PianoRequest_t *req) {  					return PIANO_RET_OUT_OF_MEMORY;  				} -				if (json_object_object_get (s, "artistName") == NULL) { +				if (!json_object_object_get_ex (s, "artistName", NULL)) {  					free (song);  					continue;  				} @@ -240,15 +274,15 @@ PianoReturn_t PianoResponse (PianoHandle_t *ph, PianoRequest_t *req) {  						"highQuality"};  				assert (reqData->quality < sizeof (qualityMap)/sizeof (*qualityMap));  				static const char *formatMap[] = {"", "aacplus", "mp3"}; -				json_object *map = json_object_object_get (s, "audioUrlMap"); -				assert (map != NULL); -				if (map != NULL) { -					map = json_object_object_get (map, qualityMap[reqData->quality]); - -					if (map != NULL) { -						const char *encoding = json_object_get_string ( -								json_object_object_get (map, "encoding")); +				json_object *umap; +				if (json_object_object_get_ex (s, "audioUrlMap", &umap)) { +					assert (umap != NULL); +					json_object *jsonEncoding, *qmap; +					if (json_object_object_get_ex (umap, qualityMap[reqData->quality], &qmap) && +							json_object_object_get_ex (qmap, "encoding", &jsonEncoding)) { +						assert (qmap != NULL); +						const char *encoding = json_object_get_string (jsonEncoding);  						assert (encoding != NULL);  						for (size_t k = 0; k < sizeof (formatMap)/sizeof (*formatMap); k++) {  							if (strcmp (formatMap[k], encoding) == 0) { @@ -256,7 +290,7 @@ PianoReturn_t PianoResponse (PianoHandle_t *ph, PianoRequest_t *req) {  								break;  							}  						} -						song->audioUrl = PianoJsonStrdup (map, "audioUrl"); +						song->audioUrl = PianoJsonStrdup (qmap, "audioUrl");  					} else {  						/* requested quality is not available */  						ret = PIANO_RET_QUALITY_UNAVAILABLE; @@ -266,6 +300,7 @@ PianoReturn_t PianoResponse (PianoHandle_t *ph, PianoRequest_t *req) {  					}  				} +				json_object *v;  				song->artist = PianoJsonStrdup (s, "artistName");  				song->album = PianoJsonStrdup (s, "albumName");  				song->title = PianoJsonStrdup (s, "songName"); @@ -273,12 +308,12 @@ PianoReturn_t PianoResponse (PianoHandle_t *ph, PianoRequest_t *req) {  				song->stationId = PianoJsonStrdup (s, "stationId");  				song->coverArt = PianoJsonStrdup (s, "albumArtUrl");  				song->detailUrl = PianoJsonStrdup (s, "songDetailUrl"); -				song->fileGain = (float)json_object_get_double ( -						json_object_object_get (s, "trackGain")); -				song->length = json_object_get_int ( -						json_object_object_get (s, "trackLength")); -				switch (json_object_get_int (json_object_object_get (s, -						"songRating"))) { +				song->fileGain = json_object_object_get_ex (s, "trackGain", &v) ? +						(float)json_object_get_double (v) : 0.0f; +				song->length = json_object_object_get_ex (s, "trackLength", &v) ? +						json_object_get_int (v) : 0; +				switch (json_object_object_get_ex (s, "songRating", &v) ? +						json_object_get_int (v) : 0) {  					case 1:  						song->rating = PIANO_RATE_LOVE;  						break; @@ -340,8 +375,8 @@ PianoReturn_t PianoResponse (PianoHandle_t *ph, PianoRequest_t *req) {  			memset (searchResult, 0, sizeof (*searchResult));  			/* get artists */ -			json_object *artists = json_object_object_get (result, "artists"); -			if (artists != NULL) { +			json_object *artists; +			if (json_object_object_get_ex (result, "artists", &artists)) {  				for (int i = 0; i < json_object_array_length (artists); i++) {  					json_object *a = json_object_array_get_idx (artists, i);  					PianoArtist_t *artist; @@ -359,8 +394,8 @@ PianoReturn_t PianoResponse (PianoHandle_t *ph, PianoRequest_t *req) {  			}  			/* get songs */ -			json_object *songs = json_object_object_get (result, "songs"); -			if (songs != NULL) { +			json_object *songs; +			if (json_object_object_get_ex (result, "songs", &songs)) {  				for (int i = 0; i < json_object_array_length (songs); i++) {  					json_object *s = json_object_array_get_idx (songs, i);  					PianoSong_t *song; @@ -414,8 +449,8 @@ PianoReturn_t PianoResponse (PianoHandle_t *ph, PianoRequest_t *req) {  		case PIANO_REQUEST_GET_GENRE_STATIONS: {  			/* get genre stations */ -			json_object *categories = json_object_object_get (result, "categories"); -			if (categories != NULL) { +			json_object *categories; +			if (json_object_object_get_ex (result, "categories", &categories)) {  				for (int i = 0; i < json_object_array_length (categories); i++) {  					json_object *c = json_object_array_get_idx (categories, i);  					PianoGenreCategory_t *tmpGenreCategory; @@ -429,9 +464,8 @@ PianoReturn_t PianoResponse (PianoHandle_t *ph, PianoRequest_t *req) {  							"categoryName");  					/* get genre subnodes */ -					json_object *stations = json_object_object_get (c, -							"stations"); -					if (stations != NULL) { +					json_object *stations; +					if (json_object_object_get_ex (c, "stations", &stations)) {  						for (int k = 0;  								k < json_object_array_length (stations); k++) {  							json_object *s = @@ -480,9 +514,8 @@ PianoReturn_t PianoResponse (PianoHandle_t *ph, PianoRequest_t *req) {  			assert (reqData != NULL); -			json_object *explanations = json_object_object_get (result, -					"explanations"); -			if (explanations != NULL) { +			json_object *explanations; +			if (json_object_object_get_ex (result, "explanations", &explanations)) {  				reqData->retExplain = malloc (strSize *  						sizeof (*reqData->retExplain));  				strncpy (reqData->retExplain, "We're playing this track " @@ -490,9 +523,11 @@ PianoReturn_t PianoResponse (PianoHandle_t *ph, PianoRequest_t *req) {  				for (int i = 0; i < json_object_array_length (explanations); i++) {  					json_object *e = json_object_array_get_idx (explanations,  							i); -					const char *s = json_object_get_string ( -							json_object_object_get (e, "focusTraitName")); - +					json_object *f; +					if (!json_object_object_get_ex (e, "focusTraitName", &f)) { +						continue; +					} +					const char *s = json_object_get_string (f);  					PianoStrpcat (reqData->retExplain, s, strSize);  					if (i < json_object_array_length (explanations)-2) {  						PianoStrpcat (reqData->retExplain, ", ", strSize); @@ -511,8 +546,8 @@ PianoReturn_t PianoResponse (PianoHandle_t *ph, PianoRequest_t *req) {  			assert (settings != NULL); -			settings->explicitContentFilter = json_object_get_boolean ( -					json_object_object_get (result, "isExplicitContentFilterEnabled")); +			settings->explicitContentFilter = getBoolDefault (result, +					"isExplicitContentFilterEnabled", false);  			settings->username = PianoJsonStrdup (result, "username");  			break;  		} @@ -528,11 +563,11 @@ PianoReturn_t PianoResponse (PianoHandle_t *ph, PianoRequest_t *req) {  			assert (info != NULL);  			/* parse music seeds */ -			json_object *music = json_object_object_get (result, "music"); -			if (music != NULL) { +			json_object *music; +			if (json_object_object_get_ex (result, "music", &music)) {  				/* songs */ -				json_object *songs = json_object_object_get (music, "songs"); -				if (songs != NULL) { +				json_object *songs; +				if (json_object_object_get_ex (music, "songs", &songs)) {  					for (int i = 0; i < json_object_array_length (songs); i++) {  						json_object *s = json_object_array_get_idx (songs, i);  						PianoSong_t *seedSong; @@ -552,9 +587,8 @@ PianoReturn_t PianoResponse (PianoHandle_t *ph, PianoRequest_t *req) {  				}  				/* artists */ -				json_object *artists = json_object_object_get (music, -						"artists"); -				if (artists != NULL) { +				json_object *artists; +				if (json_object_object_get_ex (music, "artists", &artists)) {  					for (int i = 0; i < json_object_array_length (artists); i++) {  						json_object *a = json_object_array_get_idx (artists, i);  						PianoArtist_t *seedArtist; @@ -574,14 +608,12 @@ PianoReturn_t PianoResponse (PianoHandle_t *ph, PianoRequest_t *req) {  			}  			/* parse feedback */ -			json_object *feedback = json_object_object_get (result, -					"feedback"); -			if (feedback != NULL) { +			json_object *feedback; +			if (json_object_object_get_ex (result, "feedback", &feedback)) {  				static const char * const keys[] = {"thumbsUp", "thumbsDown"};  				for (size_t i = 0; i < sizeof (keys)/sizeof (*keys); i++) { -					json_object * const val = json_object_object_get (feedback, -							keys[i]); -					if (val == NULL) { +					json_object *val; +					if (!json_object_object_get_ex (feedback, keys[i], &val)) {  						continue;  					}  					assert (json_object_is_type (val, json_type_array)); @@ -599,9 +631,8 @@ PianoReturn_t PianoResponse (PianoHandle_t *ph, PianoRequest_t *req) {  								"artistName");  						feedbackSong->feedbackId = PianoJsonStrdup (s,  								"feedbackId"); -						feedbackSong->rating = json_object_get_boolean ( -								json_object_object_get (s, "isPositive")) ? -								PIANO_RATE_LOVE : PIANO_RATE_BAN; +						feedbackSong->rating = getBoolDefault (s, "isPositive", +								false) ?  PIANO_RATE_LOVE : PIANO_RATE_BAN;  						info->feedback = PianoListAppendP (info->feedback,  								feedbackSong); | 
