Exemple #1
0
status_t
CDDBServer::Read(const BString& category, const BString& cddbID,
	const BString& artist, ReadResponseData& readResponse, bool verbose)
{
	if (_OpenConnection() != B_OK)
		return B_ERROR;

	// Assemble the Read command.
	BString cddbCommand("cddb read ");
	cddbCommand << category << " " << cddbID;

	BString output;
	status_t result = _SendCommand(cddbCommand, output);
	if (result == B_OK) {
		if (verbose)
			puts(output);

		// Remove the header from the reply.
		output.Remove(0, output.FindFirst("\r\n\r\n") + 4);

		// Check status code.
		BString statusCode;
		output.MoveInto(statusCode, 0, 3);
		if (statusCode == "210") {
			// Remove first line and parse the others.
			output.Remove(0, output.FindFirst("\r\n") + 2);
		} else {
			// Something bad happened.
			return B_ERROR;
		}

		// Process all entries.
		bool done = false;
		while (!done) {
			if (output[0] == '#') {
				// Comment. Remove it.
				output.Remove(0, output.FindFirst("\r\n") + 2);
				continue;
			}

			// Extract one line to reduce the scope of processing to it.
			BString line;
			output.MoveInto(line, 0, output.FindFirst("\r\n"));
			output.Remove(0, 2);

			// Obtain prefix.
			BString prefix;
			line.MoveInto(prefix, 0, line.FindFirst("="));
			line.Remove(0, 1);

			if (prefix == "DTITLE") {
				// Disk title.
				BString artist;
				line.MoveInto(artist, 0, line.FindFirst(" / "));
				line.Remove(0, 3);
				readResponse.title = line;
				readResponse.artist = artist;
			} else if (prefix == "DYEAR") {
				// Disk year.
				char* firstInvalid;
				errno = 0;
				uint32 year = strtoul(line.String(), &firstInvalid, 10);
				if ((errno == ERANGE &&
					(year == (uint32)LONG_MAX || year == (uint32)LONG_MIN))
					|| (errno != 0 && year == 0)) {
					// Year out of range.
					printf("Year out of range: %s\n", line.String());
					year = 0;
				}

				if (firstInvalid == line.String()) {
					printf("Invalid year: %s\n", line.String());
					year = 0;
				}

				readResponse.year = year;
			} else if (prefix == "DGENRE") {
				// Disk genre.
				readResponse.genre = line;
			} else if (prefix.FindFirst("TTITLE") == 0) {
				// Track title.
				BString index;
				prefix.MoveInto(index, 6, prefix.Length() - 6);

				char* firstInvalid;
				errno = 0;
				uint32 track = strtoul(index.String(), &firstInvalid, 10);
				if (errno != 0 || track > 99) {
					// Track out of range.
					printf("Track out of range: %s\n", index.String());
					return B_ERROR;
				}

				if (firstInvalid == index.String()) {
					printf("Invalid track: %s\n", index.String());
					return B_ERROR;
				}

				BString trackArtist;
				int32 pos = line.FindFirst(" / ");
				if (pos >= 0 && artist.ICompare("Various") == 0) {
					// Disk is set to have a compilation artist and
					// we have track specific artist information.
					line.MoveInto(trackArtist, 0, pos);
						// Move artist information from line to artist.
					line.Remove(0, 3);
						// Remove " / " from line.
				} else {
					trackArtist = artist;
				}

				TrackData* trackData = _Track(readResponse, track);
				trackData->artist += trackArtist;
				trackData->title += line;
			}

			if (output == "" || output == ".\r\n") {
				// All returned data was processed exit the loop.
				done = true;
			}
		}
	} else {
		printf("Error sending CDDB command : \"%s\".\n", cddbCommand.String());
	}

	_CloseConnection();
	return B_OK;
}
Exemple #2
0
status_t
CDDBServer::Query(uint32 cddbID, const scsi_toc_toc* toc,
	QueryResponseList& queryResponses)
{
	if (_OpenConnection() != B_OK)
		return B_ERROR;

	// Convert CDDB id to hexadecimal format.
	char hexCddbId[9];
	sprintf(hexCddbId, "%08" B_PRIx32, cddbID);

	// Assemble the Query command.
	int32 numTracks = toc->last_track + 1 - toc->first_track;

	BString cddbCommand("cddb query ");
	cddbCommand << hexCddbId << " " << numTracks << " ";

	// Add track offsets in frames.
	for (int32 i = 0; i < numTracks; ++i) {
		const scsi_cd_msf& start = toc->tracks[i].start.time;

		uint32 startFrameOffset = start.minute * kFramesPerMinute +
			start.second * kFramesPerSecond + start.frame;

		cddbCommand << startFrameOffset << " ";
	}

	// Add total disc time in seconds. Last track is lead-out.
	const scsi_cd_msf& lastTrack = toc->tracks[numTracks].start.time;
	uint32 totalTimeInSeconds = lastTrack.minute * 60 + lastTrack.second;
	cddbCommand << totalTimeInSeconds;

	BString output;
	status_t result = _SendCommand(cddbCommand, output);
	if (result == B_OK) {
		// Remove the header from the reply.
		output.Remove(0, output.FindFirst("\r\n\r\n") + 4);

		// Check status code.
		BString statusCode;
		output.MoveInto(statusCode, 0, 3);
		if (statusCode == "210" || statusCode == "211") {
			// TODO(bga): We can get around with returning the first result
			// in case of multiple matches, but we most definitely need a
			// better handling of inexact matches.
			if (statusCode == "211")
				printf("Warning : Inexact match found.\n");

			// Multiple results, remove the first line and parse the others.
			output.Remove(0, output.FindFirst("\r\n") + 2);
		} else if (statusCode == "200") {
			// Remove the first char which is a left over space.
			output.Remove(0, 1);
		} else if (statusCode == "202") {
			// No match found.
			printf("Error : CDDB entry for id %s not found.\n", hexCddbId);

			return B_ENTRY_NOT_FOUND;
		} else {
			// Something bad happened.
			if (statusCode.Trim() != "") {
				printf("Error : CDDB server status code is %s.\n",
					statusCode.String());
			} else {
				printf("Error : Could not find any status code.\n");
			}

			return B_ERROR;
		}

		// Process all entries.
		bool done = false;
		while (!done) {
			QueryResponseData* responseData = new QueryResponseData;

			output.MoveInto(responseData->category, 0, output.FindFirst(" "));
			output.Remove(0, 1);

			output.MoveInto(responseData->cddbID, 0, output.FindFirst(" "));
			output.Remove(0, 1);

			output.MoveInto(responseData->artist, 0, output.FindFirst(" / "));
			output.Remove(0, 3);

			output.MoveInto(responseData->title, 0, output.FindFirst("\r\n"));
			output.Remove(0, 2);

			queryResponses.AddItem(responseData);

			if (output == "" || output == ".\r\n") {
				// All returned data was processed exit the loop.
				done = true;
			}
		}
	} else {
		printf("Error sending CDDB command : \"%s\".\n", cddbCommand.String());
	}

	_CloseConnection();
	return result;
}
Exemple #3
0
status_t
CDDBServer::Read(QueryResponseData* diskData, ReadResponseData* readResponse)
{
	if (_OpenConnection() != B_OK)
		return B_ERROR;

	// Assemble the Read command.
	BString cddbCommand("cddb read ");
	cddbCommand << diskData->category << " " << diskData->cddbId;

	BString output;
	status_t result;
	result = _SendCddbCommand(cddbCommand, &output);

	if (result == B_OK) {
		// Remove the header from the reply.
		output.Remove(0, output.FindFirst("\r\n\r\n") + 4);
		
		// Check status code.
		BString statusCode;
		output.MoveInto(statusCode, 0, 3);
		if (statusCode == "210") {
			// Remove first line and parse the others.
			output.Remove(0, output.FindFirst("\r\n") + 2);
		} else {
			// Something bad happened.
			return B_ERROR;
		}
		
		// Process all entries.
		bool done = false;
		while (!done) {
			if (output[0] == '#') {
				// Comment. Remove it.
				output.Remove(0, output.FindFirst("\r\n") + 2);
				continue;
			}
			
			// Extract one line to reduce the scope of processing to it.
			BString line;
			output.MoveInto(line, 0, output.FindFirst("\r\n"));
			output.Remove(0, 2);

			// Obtain prefix.
			BString prefix;
			line.MoveInto(prefix, 0, line.FindFirst("="));
			line.Remove(0, 1);
			
			if (prefix == "DTITLE") {
				// Disk title.
				BString artist;
				line.MoveInto(artist, 0, line.FindFirst(" / "));
				line.Remove(0, 3);
				readResponse->title = line;
				readResponse->artist = artist;
			} else if (prefix == "DYEAR") {
				// Disk year.
				char* firstInvalid;
				errno = 0;
				uint32 year = strtoul(line.String(), &firstInvalid, 10);
				if ((errno == ERANGE &&
					(year == (uint32)LONG_MAX || year == (uint32)LONG_MIN))
					|| (errno != 0 && year == 0)) {
					// Year out of range.
					printf("Year out of range: %s\n", line.String());
					return B_ERROR;
				}
				
				if (firstInvalid == line.String()) {
					printf("Invalid year: %s\n", line.String());
					return B_ERROR;
				}
							
				readResponse->year = year;
			} else if (prefix == "DGENRE") {
				// Disk genre.
				readResponse->genre = line;
			} else if (prefix.FindFirst("TTITLE") == 0) {
				// Track title.
				BString index;					
				prefix.MoveInto(index, 6, prefix.Length() - 6);

				TrackData* trackData = new TrackData;

				char* firstInvalid;
				errno = 0;
				uint32 track = strtoul(index.String(), &firstInvalid, 10);
				if ((errno == ERANGE &&
					(track == (uint32)LONG_MAX || track == (uint32)LONG_MIN))
					|| (errno != 0 && track == 0)) {
					// Track out of range.
					printf("Track out of range: %s\n", index.String());
					delete trackData;
					return B_ERROR;
				}
				
				if (firstInvalid == index.String()) {
					printf("Invalid track: %s\n", index.String());
					delete trackData;
					return B_ERROR;	
				}

				trackData->trackNumber = track;

				int32 pos = line.FindFirst(" / " );
				if (pos != B_ERROR) {
					// We have track specific artist information.
					BString artist;
					line.MoveInto(artist, 0, pos);
					line.Remove(0, 3);
					trackData->artist = artist;
				} else {
					trackData->artist = diskData->artist;
				}

				trackData->title = line;
					
				(readResponse->tracks).AddItem(trackData);
			}
			
			if (output == "" || output == ".\r\n") {
				// All returned data was processed exit the loop.
				done = true;
			}			
		}		
	} else {
		printf("Error sending CDDB command : \"%s\".\n", cddbCommand.String());		
	}	

	_CloseConnection();
	return B_OK;
}