30 #include <nsComponentManagerUtils.h>
31 #include <nsCRTGlue.h>
32 #include <nsISAXAttributes.h>
33 #include <nsISAXLocator.h>
34 #include <nsIInputStreamPump.h>
35 #include <nsThreadUtils.h>
37 #include <sbIiTunesXMLParserListener.h>
40 #include <sbFileUtils.h>
44 nsISAXLocator * aLocator,
45 nsAString
const & aError) {
48 aLocator->GetLineNumber(&line);
49 aLocator->GetColumnNumber(&column);
51 msg.AppendLiteral(aType);
52 msg.AppendLiteral(
" occurred at line ");
53 msg.AppendInt(line, 10);
54 msg.AppendLiteral(
" column ");
55 msg.AppendInt(column, 10);
61 static PRLogModuleInfo* giTunesXMLParserLog = nsnull;
64 if (!giTunesXMLParserLog) \
65 giTunesXMLParserLog = PR_NewLogModule("sbiTunesXMLParser"); \
66 PR_LOG(giTunesXMLParserLog, PR_LOG_DEBUG, args); \
70 if (!giTunesXMLParserLog) \
71 giTunesXMLParserLog = PR_NewLogModule("sbiTunesXMLParser"); \
72 PR_LOG(giTunesXMLParserLog, PR_LOG_WARN, args); \
80 const nsAString & aLocalName,
81 const nsAString & aQName,
82 nsISAXAttributes * aAttributes) {
83 LOG((
"StartElement: URI=%s localName=%s qName=%s\n",
84 NS_LossyConvertUTF16toASCII(aURI).
get(),
85 NS_LossyConvertUTF16toASCII(aLocalName).
get(),
86 NS_LossyConvertUTF16toASCII(aQName).
get()));
88 aAttributes->GetLength(&length);
91 for (PRInt32 index = 0; index < length; ++index) {
92 aAttributes->GetLocalName(index, name);
93 aAttributes->GetValue(index, value);
95 NS_LossyConvertUTF16toASCII(name).
get(),
96 NS_LossyConvertUTF16toASCII(value).
get()));
105 nsISAXLocator * aLocator,
106 nsAString
const & aError) {
115 const nsAString & aLocalName,
116 const nsAString & qName,
117 nsISAXAttributes * aAttributes) {
121 nsISAXLocator * aLocator,
122 nsAString
const & aError) {
128 nsISAXContentHandler,
132 char const XML_CONTENT_TYPE[] = "text/xml";
150 NS_IMETHODIMP sbiTunesXMLParser::Parse(nsIInputStream * aiTunesXMLStream,
155 NS_ENSURE_ARG_POINTER(aiTunesXMLStream);
156 NS_ENSURE_ARG_POINTER(aListener);
159 mListener = aListener;
161 rv = InitializeProperties();
162 NS_ENSURE_SUCCESS(rv, rv);
166 rv = reader->SetContentHandler(
this);
167 NS_ENSURE_SUCCESS(rv, rv);
169 rv = reader->SetErrorHandler(
this);
170 NS_ENSURE_SUCCESS(rv, rv);
172 rv = reader->ParseAsync(nsnull);
174 mPump = do_CreateInstance(
"@mozilla.org/network/input-stream-pump;1", &rv);
175 NS_ENSURE_SUCCESS(rv, rv);
177 rv = mPump->Init(aiTunesXMLStream, -1, -1, 0, 0, PR_TRUE);
178 NS_ENSURE_SUCCESS(rv, rv);
180 nsCOMPtr<nsIStreamListener> streamListener = do_QueryInterface(reader);
181 rv = mPump->AsyncRead(streamListener, nsnull);
183 NS_ENSURE_SUCCESS(rv, rv);
189 NS_IMETHODIMP sbiTunesXMLParser::Finalize() {
191 mProperties = nsnull;
201 NS_WARN_IF_FALSE(NS_SUCCEEDED(rv),
"Unable to create xmlreader");
210 sbiTunesXMLParser::StartDocument() {
211 LOG((
"StartDocument\n"));
214 mBytesRead = 38 + 112 + 21;
221 sbiTunesXMLParser::EndDocument() {
222 LOG((
"EndDocument\n"));
229 sbiTunesXMLParser::StartElement(
const nsAString &
uri,
230 const nsAString & localName,
231 const nsAString & qName,
236 if (mState == DONE) {
240 if (localName.EqualsLiteral(
"true") || localName.EqualsLiteral(
"false")) {
242 if (!mPropertyName.IsEmpty()) {
243 mProperties->Set(mPropertyName, localName);
244 mPropertyName.Truncate();
246 mCharacters.Truncate();
249 mListener->OnProgress(mBytesRead);
252 mBytesRead += localName.Length() + 2;
254 if (localName.EqualsLiteral(
"dict")) {
258 mState = TOP_LEVEL_PROPERTIES;
262 mState = TRACKS_COLLECTION;
265 case TRACKS_COLLECTION: {
269 case PLAYLISTS_COLLECTION: {
273 case PLAYLIST_ITEMS: {
274 mState = PLAYLIST_ITEM;
279 else if (localName.EqualsLiteral(
"array")) {
284 mState = PLAYLISTS_COLLECTION;
289 mCharacters.Truncate();
294 NS_IMETHODIMP sbiTunesXMLParser::EndElement(
const nsAString & uri,
295 const nsAString & localName,
296 const nsAString & qName) {
297 LOG((
"EndElement: URI=%s localName=%s qName=%s\n",
298 NS_LossyConvertUTF16toASCII(uri).
get(),
299 NS_LossyConvertUTF16toASCII(localName).
get(),
300 NS_LossyConvertUTF16toASCII(qName).
get()));
302 mListener->OnProgress(mBytesRead);
304 mBytesRead += localName.Length() + 3;
307 if (mState == DONE) {
312 nsString characters(mCharacters);
313 mCharacters.Truncate();
315 nsString
const propertyName(mPropertyName);
316 mPropertyName.Truncate();
318 if (localName.EqualsLiteral(
"key")) {
320 case TOP_LEVEL_PROPERTIES: {
321 if (characters.EqualsLiteral(
"Tracks")) {
322 rv = mListener->OnTopLevelProperties(mProperties);
323 NS_ENSURE_SUCCESS(rv, rv);
324 mProperties->Clear();
327 else if (characters.EqualsLiteral(
"Playlists")) {
331 mPropertyName = characters;
336 if (characters.EqualsLiteral(
"Playlist Items")) {
337 mState = PLAYLIST_ITEMS;
340 mPropertyName = characters;
345 case PLAYLIST_ITEM: {
346 mPropertyName = characters;
350 case TRACKS_COLLECTION:
353 NS_WARNING(
"Unexpected state in sbiTunesXMLParser::EndElement (dict)");
359 else if (localName.EqualsLiteral(
"dict")) {
362 case TRACKS_COLLECTION:
363 mState = TOP_LEVEL_PROPERTIES;
364 rv = mListener->OnTracksComplete();
365 NS_ENSURE_SUCCESS(rv, rv);
369 mState = TRACKS_COLLECTION;
373 nsString isMovieProp;
374 mProperties->Get(NS_LITERAL_STRING(
"Movie"), isMovieProp);
375 if (isMovieProp.IsEmpty()) {
376 rv = mListener->OnTrack(mProperties);
377 NS_ENSURE_SUCCESS(rv, rv);
380 mProperties->Clear();
385 mState = PLAYLISTS_COLLECTION;
386 LOG((
"onPlaylist\n"));
387 rv = mListener->OnPlaylist(mProperties, mTracks.Elements(), mTracks.Length());
388 NS_ENSURE_SUCCESS(rv, rv);
390 mProperties->Clear();
393 case PLAYLIST_ITEM: {
395 mState = PLAYLIST_ITEMS;
399 NS_WARNING(
"Unexpected state in sbiTunesXMLParser::EndElement (dict)");
406 else if (localName.EqualsLiteral(
"array")) {
408 case PLAYLIST_ITEMS: {
413 case PLAYLISTS_COLLECTION: {
414 mState = TOP_LEVEL_PROPERTIES;
415 rv = mListener->OnPlaylistsComplete();
416 NS_ENSURE_SUCCESS(rv, rv);
421 NS_WARNING(
"Unexpected state in sbiTunesXMLParser::EndElement (array)");
427 if (mState == PLAYLIST_ITEM && propertyName.EqualsLiteral(
"Track ID")) {
428 PRInt32
const trackID = characters.ToInteger(&rv, 10);
429 if (NS_SUCCEEDED(rv)) {
430 PRInt32
const * newTrackID = mTracks.AppendElement(trackID);
431 NS_ENSURE_TRUE(newTrackID, NS_ERROR_OUT_OF_MEMORY);
434 else if (!propertyName.IsEmpty()) {
435 mProperties->Set(propertyName, characters);
442 NS_IMETHODIMP sbiTunesXMLParser::Characters(
const nsAString & value) {
443 LOG((
"Characters: %s\n", NS_LossyConvertUTF16toASCII(value).
get()));
446 PRUnichar
const * begin;
447 PRUnichar
const * end;
448 value.BeginReading(&begin, &end);
449 while (begin != end) {
450 mBytesRead += NS_IsAscii(*begin++) ? 1 : 2;
453 mCharacters.Append(value);
458 NS_IMETHODIMP sbiTunesXMLParser::ProcessingInstruction(
const nsAString &
target,
459 const nsAString &
data) {
465 NS_IMETHODIMP sbiTunesXMLParser::IgnorableWhitespace(
const nsAString & whitespace) {
471 NS_IMETHODIMP sbiTunesXMLParser::StartPrefixMapping(
const nsAString & prefix,
472 const nsAString & uri) {
478 NS_IMETHODIMP sbiTunesXMLParser::EndPrefixMapping(
const nsAString & prefix) {
486 NS_IMETHODIMP sbiTunesXMLParser::Error(nsISAXLocator *locator,
487 const nsAString & error) {
489 PRBool continueParsing = PR_FALSE;
490 nsresult rv = mListener->OnError(
BuildErrorMessage(
"Error", locator, error), &continueParsing);
491 NS_ENSURE_SUCCESS(rv, rv);
493 return continueParsing ?
NS_OK : NS_ERROR_FAILURE;
497 NS_IMETHODIMP sbiTunesXMLParser::FatalError(nsISAXLocator *locator,
498 const nsAString & error) {
499 LogError(
"Fatal error", locator, error);
500 PRBool continueParsing = PR_FALSE;
501 nsresult rv = mListener->OnError(
BuildErrorMessage(
"Fatal error", locator, error), &continueParsing);
502 NS_ENSURE_SUCCESS(rv, rv);
504 return continueParsing ?
NS_OK : NS_ERROR_FAILURE;
508 NS_IMETHODIMP sbiTunesXMLParser::IgnorableWarning(nsISAXLocator *locator,
509 const nsAString & error) {
510 LogError(
"Warning", locator, error);
511 PRBool continueParsing = PR_FALSE;
512 nsresult rv = mListener->OnError(
BuildErrorMessage(
"Warning", locator, error), &continueParsing);
513 NS_ENSURE_SUCCESS(rv, rv);
515 return continueParsing ?
NS_OK : NS_ERROR_FAILURE;
518 nsresult sbiTunesXMLParser::InitializeProperties() {
525 mProperties->Clear();
NS_IMPL_THREADSAFE_ISUPPORTS3(sbiTunesXMLParser, sbIiTunesXMLParser, nsISAXContentHandler, nsISAXErrorHandler) char const XML_CONTENT_TYPE[]
char const NS_SAXXMLREADER_CONTRACTID[]
void LogError(char const *aType, nsISAXLocator *aLocator, nsAString const &aError)
#define SB_STRINGMAP_CONTRACTID
void LogStartElement(const nsAString &aURI, const nsAString &aLocalName, const nsAString &qName, nsISAXAttributes *aAttributes)
nsCOMPtr< nsISAXXMLReader > nsISAXXMLReaderPtr
nsString BuildErrorMessage(char const *aType, nsISAXLocator *aLocator, nsAString const &aError)