Allow asset map parser to process empty tags correctly
[vlc.git] / modules / access / dcp / dcpparser.cpp
1 /*****************************************************************************
2  * Copyright (C) 2013 VLC authors and VideoLAN
3  *
4  * Authors:
5  *          Nicolas Bertrand <nico@isf.cc>
6  *          Jean-Baptiste Kempf <jb@videolan.org>
7  *          Guillaume Gonnaud
8  *          Valentin Vetter <vvetter@outlook.com>
9  *          Anthony Giniers
10  *          Ludovic Hoareau
11  *          Loukmane Dessai
12  *          Simona-Marinela Prodea <simona dot marinela dot prodea at gmail dot com>
13  *
14  * This program is free software; you can redistribute it and/or modify it
15  * under the terms of the GNU Lesser General Public License as published by
16  * the Free Software Foundation; either version 2.1 of the License, or
17  * (at your option) any later version.
18  *
19  * This program is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22  * GNU Lesser General Public License for more details.
23  *
24  * You should have received a copy of the GNU Lesser General Public License
25  * along with this program; if not, write to the Free Software Foundation,
26  * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
27  *****************************************************************************/
28
29 /**
30  * @file dcpparser.cpp
31  * @brief Parsing of DCP XML files
32  */
33 #ifdef HAVE_CONFIG_H
34 # include "config.h"
35 #endif
36
37 /* VLC core API headers */
38 #include <vlc_common.h>
39 #include <vlc_plugin.h>
40 #include <vlc_xml.h>
41 #include <vlc_url.h>
42
43 #include <iostream>
44 #include <string>
45 #include <list>
46 #include <vector>
47
48 #include "dcpparser.h"
49
50 using namespace std;
51
52 typedef enum {
53     CHUNK_UNKNOWN = 0,
54     CHUNK_PATH,
55     CHUNK_VOL_INDEX,
56     CHUNK_OFFSET,
57     CHUNK_LENGTH
58 } ChunkTag_t;
59
60
61 typedef enum {
62     ASSET_UNKNOWN = 0,
63     ASSET_ID,
64     ASSET_ANNOTATION_TEXT,
65     ASSET_PACKING_LIST,
66     ASSET_CHUNK_LIST,
67     ASSET_HASH,
68     ASSET_SIZE,
69     ASSET_TYPE,
70     ASSET_ORIGINAL_FILENAME
71 } AssetTag_t;
72
73 static const string g_asset_names[] = {
74     "Id",
75     "AnnotationText",
76     "PackingList",
77     "ChunkList",
78     "Hash",
79     "Size",
80     "Type",
81     "OriginalFileName"
82 };
83
84
85 typedef enum {
86     PKL_UNKNOWN = 0,
87     PKL_ID,
88     PKL_ISSUE_DATE,
89     PKL_ISSUER,
90     PKL_CREATOR,
91     PKL_ASSET_LIST,
92     PKL_ANNOTATION_TEXT, /* start of optional tags */
93     PKL_ICON_ID,
94     PKL_GROUP_ID,
95     PKL_SIGNER,
96     PKL_SIGNATURE,
97 } PKLTag_t;
98
99 typedef enum {
100     CPL_UNKNOWN = 0,
101     CPL_ID,
102     CPL_ANNOTATION_TEXT,        /* optional */
103     CPL_ICON_ID,                /* optional */
104     CPL_ISSUE_DATE,
105     CPL_ISSUER,                 /* optional */
106     CPL_CREATOR,                /* optional */
107     CPL_CONTENT_TITLE,
108     CPL_CONTENT_KIND,
109     CPL_CONTENT_VERSION,        /* not optional, but not always present*/
110     CPL_RATING_LIST,            /* not handled */
111     CPL_REEL_LIST,
112     CPL_SIGNER,                 /* optional - not handled */
113     CPL_SIGNATURE               /* optional - not handled */
114 } CPLTag_t;
115
116
117 class ChunkList: public std::list<Chunk> {
118 public :
119     ChunkList();
120     ~ChunkList();
121 };
122
123 /*
124  * Chunk Class
125  */
126 int Chunk::Parse( xml_reader_t *p_xmlReader, string p_node, int p_type){
127     string node;
128     int type;
129     string s_value;
130     static const string names[] = {"Path", "VolumeIndex", "Offset",
131                                "Length"};
132     if (p_type != XML_READER_STARTELEM)
133         return -1;
134     if( p_node != "Chunk")
135         return -1;
136     /* loop on Chunks Node */
137     while( ( type = XmlFile::ReadNextNode( this->p_demux, p_xmlReader, node ) ) > 0 ) {
138         switch (type) {
139             case XML_READER_STARTELEM:
140             {
141                 ChunkTag_t chunk_tag = CHUNK_UNKNOWN;
142                 for(ChunkTag_t i = CHUNK_PATH; i <= CHUNK_LENGTH; i = ChunkTag_t(i+1)) {
143                     if( node == names[i-1]) {
144                         chunk_tag = i;
145                         if ( XmlFile::ReadEndNode( this->p_demux, p_xmlReader, node, type, s_value ) )
146                             return -1;
147                         switch (chunk_tag) {
148                             case CHUNK_PATH:
149                                 this->s_path = s_value;
150                                 break;
151                             case CHUNK_VOL_INDEX:
152                                 this->i_vol_index = atoi(s_value.c_str());
153                                 break;
154                             case CHUNK_OFFSET:
155                                 this->i_offset = atoi(s_value.c_str());
156                                 break;
157                             case CHUNK_LENGTH:
158                                 this->i_length = atoi(s_value.c_str());
159                                 break;
160                             case CHUNK_UNKNOWN:
161                             default:
162                                 break;
163                         }
164                         /* break the for loop as a tag is found*/
165                         break;
166                     }
167                 }
168                 if(chunk_tag == CHUNK_UNKNOWN)
169                     return -1;
170                 break;
171             }
172             case XML_READER_TEXT:
173                 s_value = node;
174                 if (unlikely(node.empty()))
175                     return -1;
176                 break;
177             case XML_READER_ENDELEM:
178                 /* Verify if we reach Chuk endelem  */
179                 if ( node == p_node) {
180                     /* verify path */
181                     if ( this->s_path.empty() ) {
182                         msg_Err(this->p_demux, "Chunk::Parse No path found");
183                         return -1;
184                     }
185                     if ( this->i_vol_index != 1 ) {
186                         msg_Err(this->p_demux, "Only one VOLINDEX suported. Patch welcome.");
187                         return -1;
188                     }
189                     /* end of chunk tag parse */
190                     return 0;
191                 }
192                 break;
193         }
194     }
195     return -1;
196 }
197 /*
198  * AssetMap Class
199  */
200
201 AssetMap::~AssetMap() { }
202
203 int AssetMap::Parse ( )
204 {
205     int type = 0;
206     int retval;
207     int reel_nbr = 0;
208     int index = 0;
209     int sum_duration_vid = 0;
210     int sum_duration_aud = 0;
211     string node;
212     char *psz_kdm_path;
213
214     CPL  *cpl;
215     Reel *reel;
216     PKL  *pkl;
217     AssetList *_p_asset_list = NULL;
218
219     vector<string> pklfiles;
220
221     /* init XML parser */
222     if( this->OpenXml() ) {
223         msg_Err( p_demux, "Failed to initialize Assetmap XML parser" );
224         return -1;
225     }
226
227     /* reading ASSETMAP file to get the asset_list */
228     msg_Dbg( p_demux, "reading ASSETMAP file..." );
229     while( ( type = XmlFile::ReadNextNode( this->p_demux, this->p_xmlReader, node ) ) ) {
230         if( type == -1 )
231         {
232             this->CloseXml();
233             return -1;
234         }
235         if ( (type == XML_READER_STARTELEM) && ( node =="AssetList")) {
236             _p_asset_list =  new (nothrow) AssetList();
237             if ( unlikely(_p_asset_list == NULL) ) {
238                 this->CloseXml();
239                 return -1;
240             }
241             p_dcp->p_asset_list = _p_asset_list;
242             if (this->ParseAssetList(p_xmlReader, node, type )) {
243                 this->CloseXml();
244                 return -1;
245             }
246             /* asset list found so break*/
247             break;
248         }
249     }
250
251     /* Look for PKLs path */
252     if ( (_p_asset_list == NULL) ||  (_p_asset_list->size() == 0) ) {
253         msg_Err( p_demux, "Asset list empty" );
254         this->CloseXml();
255         return -1;
256     }
257
258     for (AssetList::iterator iter = _p_asset_list->begin();
259             iter != _p_asset_list->end() ; ++iter) {
260         string s_filepath;
261         s_filepath = (*iter)->getPath();
262         if (s_filepath.empty()) {
263             msg_Err( p_demux, "No path element for asset" );
264             continue;
265         }
266         /* set an absolute file path */
267         s_filepath = p_dcp->path + s_filepath;
268
269         /* case of packing list */
270         if ((*iter)->isPackingList()) {
271             pklfiles.push_back( s_filepath );
272         }
273     }
274
275     /* TODO: case of only on PKL managed.
276      * Future work needed for managing severals
277      * the PKL vector will be used to select the required PKL  */
278     if( (pklfiles.size() == 0)  || (pklfiles[0].empty()) )
279     {
280         msg_Err( p_demux, "Could not find PKL file in ASSETMAP" );
281         this->CloseXml();
282         return -1;
283     }
284
285     /* Create the first PKL */
286     pkl = new (nothrow) PKL(p_demux, pklfiles[0], _p_asset_list, p_dcp->path);
287     if ( unlikely(pkl == NULL) ) {
288         this->CloseXml();
289         return -1;
290         }
291     if (pkl->Parse()) {
292         delete pkl;
293         this->CloseXml();
294         return -1;
295         }
296     p_dcp->pkls.push_back( pkl );
297
298     /* Now, CPL */
299     if ( pkl->FindCPLs() <= 0 ) {
300         msg_Err(p_demux, " No CPL found");
301         this->CloseXml();
302         return -1;
303     }
304     /* TODO: Only one CPL managed.
305      * Future work needed for managing severals
306      */
307
308     cpl = pkl->getCPL(0);
309     if( cpl == NULL ) {
310         msg_Err(p_demux, " No CPL found");
311         this->CloseXml();
312         return -1;
313     }
314     if ( cpl->Parse() ) {
315         this->CloseXml();
316         return -1;
317     }
318
319     /* KDM, if needed */
320     for( AssetList::iterator iter = _p_asset_list->begin(); iter != _p_asset_list->end(); ++iter )
321         if( ! (*iter)->getKeyId().empty() )
322         {
323             msg_Dbg( p_demux, "DCP is encrypted, searching KDM file...");
324             psz_kdm_path = var_InheritString( p_demux, "kdm" );
325             if( !psz_kdm_path || !*psz_kdm_path )
326             {
327                 msg_Err( p_demux, "cryptographic key IDs found in CPL and no path to KDM given");
328                 free( psz_kdm_path );
329                 this->CloseXml();
330                 return VLC_EGENERIC;
331             }
332             KDM p_kdm( p_demux, psz_kdm_path, p_dcp );
333             free( psz_kdm_path );
334             if( ( retval = p_kdm.Parse() ) )
335             {
336                 this->CloseXml();
337                 return retval;
338             }
339             break;
340         }
341
342     reel_nbr = cpl->getReelList().size();
343     for(index = 0; index != reel_nbr; ++index)
344     {
345         reel = cpl->getReel(index);
346
347         Asset *asset;
348         struct info_reel video;
349         struct info_reel audio;
350
351         /* Get picture */
352         asset = reel->getTrack(TRACK_PICTURE);
353         if (asset != NULL)
354         {
355             sum_duration_vid += asset->getDuration();
356             video.filename = p_dcp->path + asset->getPath();
357             video.i_entrypoint = asset->getEntryPoint();
358             video.i_duration = asset->getDuration();
359             video.i_correction = video.i_entrypoint - sum_duration_vid + video.i_duration;
360             video.i_absolute_end = sum_duration_vid;
361             video.p_key = asset->getAESKeyById( p_dcp->p_key_list, asset->getKeyId() );
362             p_dcp->video_reels.push_back(video);
363             msg_Dbg( this->p_demux, "Video Track: %s",asset->getPath().c_str());
364             msg_Dbg( this->p_demux, "Entry point: %i",asset->getEntryPoint());
365         }
366         /* Get audio */
367         asset = reel->getTrack(TRACK_SOUND);
368         if (asset != NULL)
369         {
370             /*if (!p_dcp->audio_reels.empty())
371             {
372                 sum_duration_aud = 0;
373                 for (int i = 0; i != p_dcp->audio_reels.size(); ++i)
374                 {
375                     sum_duration_aud += p_dcp->audio_reels(i).i_duration;
376                 }
377             }*/
378             sum_duration_aud += asset->getDuration();
379             audio.filename = p_dcp->path + asset->getPath();
380             audio.i_entrypoint = asset->getEntryPoint();
381             audio.i_duration = asset->getDuration();
382             audio.i_correction = audio.i_entrypoint - sum_duration_aud + audio.i_duration;
383             audio.i_absolute_end = sum_duration_aud;
384             audio.p_key = asset->getAESKeyById( p_dcp->p_key_list, asset->getKeyId() );
385             p_dcp->audio_reels.push_back(audio);
386             msg_Dbg( this->p_demux, "Audio Track: %s",asset->getPath().c_str());
387             msg_Dbg( this->p_demux, "Entry point: %i",asset->getEntryPoint());
388         }
389     }
390     /* free memory */
391     this->CloseXml();
392     return VLC_SUCCESS;
393 }
394
395
396
397 /*
398  * Asset Class
399  */
400 Asset::~Asset() {}
401
402 int Asset::Parse( xml_reader_t *p_xmlReader, string p_node, int p_type)
403 {
404     string node;
405     int type;
406     string s_value;
407     const string s_root_node = "Asset";
408
409     if (p_type != XML_READER_STARTELEM)
410         return -1;
411     if( p_node != s_root_node)
412         return -1;
413     /* loop on Assets Node */
414     while( ( type = XmlFile::ReadNextNode( this->p_demux, p_xmlReader, node ) ) > 0 ) {
415         switch (type) {
416             case XML_READER_STARTELEM:
417                 {
418                     AssetTag_t _tag = ASSET_UNKNOWN;
419                     for(AssetTag_t i = ASSET_ID; i <= ASSET_ORIGINAL_FILENAME; i = AssetTag_t(i+1)) {
420                         if( node == g_asset_names[i-1]) {
421                             _tag = i;
422                             switch(_tag) {
423                                 /* Case of complex nodes */
424                                 case ASSET_PACKING_LIST:
425                                     /* case of <PackingList/> tag, bur not compliant with SMPTE-429-9 2007*/
426                                     if (xml_ReaderIsEmptyElement( p_xmlReader))
427                                     {
428                                         this->b_is_packing_list = true;
429                                     }
430                                     else if ( XmlFile::ReadEndNode( this->p_demux, p_xmlReader, node, type, s_value ) )
431                                     {
432                                         msg_Err(this->p_demux, "Missing end node in %s", node.c_str());
433                                         return -1;
434                                     }
435                                     if ( s_value == "true" )
436                                         this->b_is_packing_list = true;
437                                     break;
438                                 case ASSET_CHUNK_LIST:
439                                     if ( this->parseChunkList(p_xmlReader, node, type ) )
440                                     {
441                                         msg_Err(this->p_demux, "Error parsing chunk list: %s", node.c_str());
442                                         return -1;
443                                     }
444                                     this->s_path = this->chunk_vec[0].getPath();
445                                     break;
446                                 case ASSET_ID:
447                                     if ( XmlFile::ReadEndNode( this->p_demux, p_xmlReader, node, type, s_value ) )
448                                     {
449                                         msg_Err(this->p_demux, "Missing end node in %s", node.c_str());
450                                         return -1;
451                                     }
452                                     this->s_id = s_value;
453                                     break;
454                                 case ASSET_ANNOTATION_TEXT:
455                                     if ( XmlFile::ReadEndNode( this->p_demux, p_xmlReader, node, type, s_value ) )
456                                     {
457                                         msg_Err(this->p_demux, "Missing end node in %s", node.c_str());
458                                         return -1;
459                                     }
460                                     this->s_annotation = s_value;
461                                     break;
462                                 case ASSET_ORIGINAL_FILENAME:
463                                 case ASSET_HASH:
464                                 case ASSET_TYPE:
465                                 case ASSET_SIZE:
466                                     /* Asset tags not in AssetMap */
467                                     break;
468                                 default:
469                                     msg_Warn(this->p_demux, "Unknown ASSET_TAG: %i", _tag );
470                                     break;
471                             }
472                             /* break the for loop as a tag is found*/
473                             break;
474                         }
475                     }
476                     if( _tag == ASSET_UNKNOWN )
477                     {
478                         msg_Err(this->p_demux, "Unknown ASSET_TAG: %s", node.c_str());
479                         return -1;
480                     }
481                     break;
482                 }
483             case XML_READER_TEXT:
484                 msg_Err(this->p_demux, " Text element found in Asset");
485                 return -1;
486             case XML_READER_ENDELEM:
487                 if ( node != s_root_node) {
488                     msg_Err(this->p_demux,
489                             "Something goes wrong in Asset parsing on Assetmap (node %s)", node.c_str());
490                     return -1;
491                 } else {
492                     /*Check Presence of Id and Chunklist */
493                     if ( this->s_id.empty() ) {
494                         msg_Err(this->p_demux, " No Id element found in Asset");
495                         return -1;
496                     }
497                     if ( this->s_path.empty() ) {
498                         msg_Err(this->p_demux, " No path element found in Asset");
499                         return -1;
500                     }
501                     return 0;
502                 }
503                 break;
504         }
505     }
506     return -1;
507 }
508
509
510
511 int Asset::ParsePKL( xml_reader_t *p_xmlReader)
512 {
513     string node;
514     int type;
515     string s_value;
516     const string s_root_node = "Asset";
517
518     while( ( type = XmlFile::ReadNextNode( this->p_demux, p_xmlReader, node ) ) > 0 ) {
519         switch (type) {
520             case XML_READER_STARTELEM:
521                 {
522                     AssetTag_t _tag = ASSET_UNKNOWN;
523                     for(AssetTag_t i = ASSET_ID; i <= ASSET_ORIGINAL_FILENAME; i = AssetTag_t(i+1)) {
524                         if( node == g_asset_names[i-1]) {
525                             _tag = i;
526                             switch(_tag) {
527                                 case ASSET_ANNOTATION_TEXT:
528                                     if ( XmlFile::ReadEndNode( this->p_demux, p_xmlReader, node, type, s_value ) )
529                                         return -1;
530                                     if ( this->s_annotation.empty() )
531                                         this->s_annotation = s_value;
532                                     else
533                                         this->s_annotation = this->s_annotation + "--" + s_value;
534                                     break;
535                                 case ASSET_HASH:
536                                     if ( XmlFile::ReadEndNode( this->p_demux, p_xmlReader, node, type, s_value ) )
537                                         return -1;
538                                     this->s_hash = s_value;
539                                     break;
540                                 case ASSET_SIZE:
541                                     if ( XmlFile::ReadEndNode( this->p_demux, p_xmlReader, node, type, s_value ) )
542                                         return -1;
543                                     this->ui_size = atol(s_value.c_str());
544                                     break;
545                                 case ASSET_TYPE:
546                                     if ( XmlFile::ReadEndNode( this->p_demux, p_xmlReader, node, type, s_value ) )
547                                         return -1;
548                                     this->s_type = s_value;
549                                     break;
550                                 case ASSET_ORIGINAL_FILENAME:
551                                     if ( XmlFile::ReadEndNode( this->p_demux, p_xmlReader, node, type, s_value ) )
552                                         return -1;
553                                     this->s_original_filename = s_value;
554                                     break;
555                                 case ASSET_ID: /* already verified */
556                                 case ASSET_PACKING_LIST:
557                                 case ASSET_CHUNK_LIST:
558                                     /* Asset tags not in PKL */
559                                     break;
560                                 default:
561                                     msg_Warn(this->p_demux, "Unknow ASSET_TAG: %i", _tag );
562                                     break;
563                             }
564                             /* break the for loop as a tag is found*/
565                             break;
566                         }
567                     }
568                     if( _tag == ASSET_UNKNOWN )
569                         return -1;
570                 break;
571             }
572             case XML_READER_TEXT:
573                 return -1;
574             case XML_READER_ENDELEM:
575                 if ( node != s_root_node) {
576                     msg_Err(this->p_demux,
577                             "Something goes wrong in Asset parsing on PKL (node %s)", node.c_str());
578                     return -1;
579                 } else {
580                     /* Verify that mandatory attributes are filled */
581                     if (this->s_hash.empty()) {
582                         msg_Err(this->p_demux,"Asset Hash tag invalid");
583                         return -1;
584                     }
585                     if (this->ui_size == 0) {
586                         msg_Err(this->p_demux,"Asset Size tag invalid");
587                         return -1;
588                     }
589                     if (this->s_type.empty()) {
590                         msg_Err(this->p_demux,"Asset Type tag invalid");
591                         return -1;
592                     }
593                     return 0;
594                 }
595                 break;
596         }
597
598     }
599
600     return -1;
601 }
602
603 void Asset::Dump()
604 {
605     msg_Dbg(this->p_demux,"Id              = %s", this->s_id.c_str());
606     msg_Dbg(this->p_demux,"Path            = %s", this->s_path.c_str());
607     msg_Dbg(this->p_demux,"Is PKL          = %s", this->b_is_packing_list ? "True" : "False");
608     msg_Dbg(this->p_demux,"Hash            = %s", this->s_hash.c_str());
609     msg_Dbg(this->p_demux,"Size            = %i", this->ui_size);
610     msg_Dbg(this->p_demux,"Type            = %s", this->s_type.c_str());
611     msg_Dbg(this->p_demux,"OrignalFileName = %s", this->s_original_filename.c_str());
612     msg_Dbg(this->p_demux,"AnnotationText  = %s", this->s_annotation.c_str());
613 }
614
615 int Asset::parseChunkList( xml_reader_t *p_xmlReader, string p_node, int p_type)
616 {
617     string node;
618     int type;
619     string s_value;
620     std::vector<Chunk> chunk_vec;
621
622     if (p_type != XML_READER_STARTELEM)
623         return -1;
624     if( p_node != "ChunkList" )
625         return -1;
626     /* loop on Assets Node */
627     while( ( type = XmlFile::ReadNextNode( this->p_demux, p_xmlReader, node ) ) > 0 ) {
628          switch (type) {
629             case XML_READER_STARTELEM:
630                 {
631                     Chunk chunk(this->p_demux);
632                     if (node != "Chunk" )
633                         return -1;
634                     if ( chunk.Parse(p_xmlReader, node, type) )
635                         return -1;
636                     chunk_vec.push_back(chunk);
637                     break;
638                 }
639             case XML_READER_ENDELEM:
640                 if ( node == p_node) {
641                     if (chunk_vec.size() != 1 ) {
642                         msg_Err(this->p_demux, "chunklist of size greater than one not supported");
643                         return -1;
644                         }
645                     this->chunk_vec = chunk_vec;
646                     return 0;
647                 }
648                 break;
649         }
650     }
651     return -1;
652 }
653
654 AESKey * Asset::getAESKeyById( AESKeyList* p_key_list, const string s_id )
655 {
656     /* return NULL if DCP is not encrypted */
657     if( !p_key_list || s_id.empty() )
658         return NULL;
659
660     for( AESKeyList::iterator index = p_key_list->begin(); index != p_key_list->end(); ++index )
661         if( (*index)->getKeyId() == s_id )
662             return *index;
663
664     return NULL;
665 }
666
667
668 int AssetMap::ParseAssetList (xml_reader_t *p_xmlReader, const string p_node, int p_type)
669 {
670     string node;
671     int type;
672     Asset *asset;
673
674     if (p_type != XML_READER_STARTELEM)
675         return -1;
676     if( p_node != "AssetList" )
677         return -1;
678     /* loop on AssetList nodes */
679     while( ( type = XmlFile::ReadNextNode( this->p_demux, p_xmlReader, node ) ) > 0 ) {
680         switch (type) {
681             case XML_READER_STARTELEM:
682                 if (node != "Asset" )
683                     return -1;
684                 asset = new (nothrow) Asset(this->p_demux);
685                 if ( unlikely(asset == NULL) )
686                     return -1;
687                 if (asset->Parse(p_xmlReader, node, type)){
688                     msg_Err(this->p_demux, "Error parsing Asset in AssetMap");
689                     delete asset;
690                     return -1;
691                 }
692                 p_dcp->p_asset_list->push_back(asset);
693                 break;
694
695             case XML_READER_ENDELEM:
696                 if (node == p_node )
697                     return 0;
698                 break;
699             default:
700             case XML_READER_TEXT:
701                 msg_Err(this->p_demux, "Error parsing AssetList in AssetMap");
702                 return -1;
703         }
704     }
705     return -1;
706 }
707
708 Asset * AssetMap::getAssetById(AssetList *asset_list, const string p_id)
709 {
710     AssetList::iterator index = asset_list->begin() ;
711     for (index = asset_list->begin(); index != asset_list->end(); ++index)
712         if ((*index)->getId() == p_id )
713             return *index;
714     return NULL;
715 }
716
717 /*
718  * XmlFile Class
719  */
720 XmlFile::~XmlFile() {}
721
722 int XmlFile::OpenXml()
723 {
724     char *psz_uri;
725
726     this->p_xml = xml_Create( this->p_demux );
727     if (! this->p_xml) {
728         return -1;
729     }
730     psz_uri = vlc_path2uri( this->s_path.c_str(), "file" );
731     this->p_stream = stream_UrlNew(this->p_demux, psz_uri );
732     free(psz_uri);
733     if( ! this->p_stream ) {
734         xml_Delete(this->p_xml );
735         return -1;
736     }
737
738     this->p_xmlReader = xml_ReaderCreate( this->p_xml, this->p_stream);
739     if( ! this->p_xmlReader ) {
740         stream_Delete( this->p_stream );
741         xml_Delete(this->p_xml );
742         return -1;
743     }
744     return 0;
745 }
746
747 int XmlFile::ReadNextNode( demux_t *p_demux, xml_reader_t *p_xmlReader, string& p_node )
748 {
749     string s_node;
750     const char * c_node;
751     int i;
752     size_t ui_pos;
753
754     i = xml_ReaderNextNode( p_xmlReader, &c_node );
755
756     /* remove namespaces, if there are any */
757     s_node = c_node;
758     ui_pos = s_node.find( ":" );
759     if( ( i == XML_READER_STARTELEM || i == XML_READER_ENDELEM ) && ( ui_pos != string::npos ) )
760     {
761         try
762         {
763             p_node = s_node.substr( ui_pos + 1 );
764         }
765         catch( ... )
766         {
767             msg_Err( p_demux, "error while handling string" );
768             return -1;
769         }
770     }
771     else
772         p_node = s_node;
773
774     return i;
775 }
776
777 int XmlFile::ReadEndNode( demux_t *p_demux, xml_reader_t *p_xmlReader, string p_node, int p_type, string &s_value)
778 {
779     string node;
780
781     if ( xml_ReaderIsEmptyElement( p_xmlReader) )
782             return 0;
783
784     if (p_type != XML_READER_STARTELEM)
785         return -1;
786
787     int n = XmlFile::ReadNextNode( p_demux, p_xmlReader, node );
788     if( n == XML_READER_TEXT )
789     {
790         s_value = node;
791         n = XmlFile::ReadNextNode( p_demux, p_xmlReader, node );
792         if( ( n == XML_READER_ENDELEM ) && node == p_node)
793             return 0;
794     }
795     return n == XML_READER_ENDELEM ? 0 : -1;
796 }
797 /*
798  * Reads first node in XML and returns
799  * 1 if XML is CPL,
800  * 0 if not
801  * -1 on error
802  */
803 int XmlFile::isCPL()
804 {
805     string node;
806     int type, ret = 0;
807
808     if( this->OpenXml() )
809     {
810         msg_Err( this->p_demux, "Failed to open CPL XML file" );
811         return -1;
812     }
813
814     /* read 1st node  and verify that is a CPL */
815     type = XmlFile::ReadNextNode( this->p_demux, p_xmlReader, node );
816     if( type == -1 ) /* error */
817         ret = -1;
818     if( type == XML_READER_STARTELEM &&  node == "CompositionPlaylist" )
819         ret = 1;
820
821     /* close xml */
822     this->CloseXml();
823     return ret;
824 }
825
826 void XmlFile::CloseXml() {
827     if( this->p_stream )
828         stream_Delete( this->p_stream );
829     if( this->p_xmlReader )
830         xml_ReaderDelete( this->p_xmlReader );
831     if( this->p_xml )
832         xml_Delete( this->p_xml );
833
834 }
835
836 /*
837  * PKL Class
838  */
839
840 PKL::~PKL() {
841     vlc_delete_all(vec_cpl);
842 }
843
844 int PKL::Parse()
845 {
846     string node;
847     int type;
848     string s_value;
849     const string s_root_node = "PackingList";
850
851     static const string names[] = {
852         "Id",
853         "IssueDate",
854         "Issuer",
855         "Creator",
856         "AssetList",
857         "AnnotationText",
858         "IconId",
859         "GroupId",
860         "Signer",
861         "Signature"
862     };
863
864     if (this->OpenXml())
865         return -1;
866
867     /* read 1st node  and verify that is a PKL*/
868     if ( ! ( ( XML_READER_STARTELEM == XmlFile::ReadNextNode( this->p_demux, this->p_xmlReader, node ) ) &&
869                 (node == s_root_node) ) ) {
870         msg_Err( this->p_demux, "Not a valid XML Packing List");
871         goto error;
872     }
873     while( ( type = XmlFile::ReadNextNode( this->p_demux, this->p_xmlReader, node ) ) ) {
874         switch (type) {
875             case XML_READER_STARTELEM: {
876                 PKLTag_t _tag = PKL_UNKNOWN;
877                 for(PKLTag_t i = PKL_ID; i <= PKL_SIGNATURE; i = PKLTag_t(i+1)) {
878                     if( node == names[i-1]) {
879                         _tag = i;
880                         switch (_tag) {
881                             /* case for parsing non terminal nodes */
882                             case PKL_ASSET_LIST:
883                                 if ( this->ParseAssetList(node, type) )
884                                     goto error;
885                                 break;
886                             case PKL_SIGNER:
887                                 if ( this->ParseSigner(node, type) )
888                                     goto error;
889                                 break;
890                             case PKL_SIGNATURE:
891                                 if ( this->ParseSignature(node, type) )
892                                     goto error;
893                                 break;
894                             /* Parse simple/end nodes */
895                             case PKL_ID:
896                                 if ( XmlFile::ReadEndNode( this->p_demux, p_xmlReader, node, type, s_value ) )
897                                     goto error;
898                                 this->s_id = s_value;
899                                 break;
900                             case PKL_ISSUE_DATE:
901                                 if ( XmlFile::ReadEndNode( this->p_demux, p_xmlReader, node, type, s_value ) )
902                                     goto error;
903                                 this->s_issue_date = s_value;
904                                 break;
905                             case PKL_ISSUER:
906                                 if ( XmlFile::ReadEndNode( this->p_demux, p_xmlReader, node, type, s_value ) )
907                                     goto error;
908                                 this->s_issuer = s_value;
909                                 break;
910                             case PKL_CREATOR:
911                                 if ( XmlFile::ReadEndNode( this->p_demux, p_xmlReader, node, type, s_value ) )
912                                     goto error;
913                                 this->s_creator = s_value;
914                                 break;
915                             case PKL_ANNOTATION_TEXT:
916                                 if ( XmlFile::ReadEndNode( this->p_demux, p_xmlReader, node, type, s_value ) )
917                                     goto error;
918                                 this->s_annotation = s_value;
919                                 break;
920                             case PKL_ICON_ID:
921                                 if ( XmlFile::ReadEndNode( this->p_demux, p_xmlReader, node, type, s_value ) )
922                                     goto error;
923                                 this->s_icon_id = s_value;
924                                 break;
925                             case PKL_GROUP_ID:
926                                 if ( XmlFile::ReadEndNode( this->p_demux, p_xmlReader, node, type, s_value ) )
927                                     goto error;
928                                 this->s_group_id = s_value;
929                                 break;
930                             default:
931                                 msg_Warn(this->p_demux, "Unknow PKG_TAG: %i", _tag );
932                                 break;
933                         }
934                         /* break the for loop as a tag is found*/
935                         break;
936                     }
937                 }
938                 if( _tag == PKL_UNKNOWN )
939                     goto error;
940                 break;
941             }
942             case XML_READER_TEXT:
943             case -1:
944                 goto error;
945             case XML_READER_ENDELEM:
946                 if ( node != s_root_node) {
947                     msg_Err(this->p_demux,
948                         "Something goes wrong in PKL parsing (node %s)", node.c_str());
949                     goto error;
950                 }
951                 break;
952         }
953     }
954     /* TODO verify presence of mandatory fields*/
955
956     /* Close PKL XML*/
957     this->CloseXml();
958     return 0;
959 error:
960     msg_Err( this->p_demux, "PKL parsing failed");
961     this->CloseXml();
962     return -1;
963 }
964
965 int PKL::FindCPLs()
966 {
967     if ( this->vec_cpl.size() != 0 ) {
968         msg_Err(this->p_demux, "CPLs already checked");
969         return -1;
970     }
971
972     for (AssetList::iterator index = this->asset_list->begin();
973             index != this->asset_list->end(); ++index) {
974         Asset *asset = *index;
975         if ( asset->getType().find("text/xml") == string::npos) {
976             /* not an xml file */
977             continue;
978         }
979
980         CPL *cpl = new (nothrow) CPL(this->p_demux,
981                       this->s_dcp_path + asset->getPath(),
982                       this->asset_list);
983         if ( unlikely(cpl == NULL) )
984                     return -1;
985         switch( cpl->isCPL() )
986         {
987             case 1:
988                 /* CPL Found */
989                 this->vec_cpl.push_back(cpl);
990                 break;
991             case -1:
992                 /* error */
993                 return -1;
994             case 0:
995             default:
996                 delete cpl;
997                 break;
998         }
999     }
1000     return this->vec_cpl.size();
1001 }
1002
1003
1004 int PKL::ParseAssetList(string p_node, int p_type) {
1005     string node;
1006     int type;
1007
1008     if (p_type != XML_READER_STARTELEM)
1009         return -1;
1010     if( p_node != "AssetList")
1011         return -1;
1012     while( ( type = XmlFile::ReadNextNode( this->p_demux, this->p_xmlReader, node ) ) ) {
1013         switch (type) {
1014             case XML_READER_STARTELEM:
1015                 if( node =="Asset") {
1016                     if ( this->ParseAsset(node, type) )
1017                         return -1;
1018                 } else
1019                     return -1;
1020                 break;
1021             case XML_READER_ENDELEM:
1022                 if ( node == p_node) {
1023                     /* parse of chunklist finished */
1024                     goto end;
1025                 }
1026                 break;
1027             case -1:
1028                 /* error */
1029                 return -1;
1030         }
1031     }
1032 end:
1033     return 0;
1034 }
1035
1036 int PKL::ParseAsset(string p_node, int p_type) {
1037     string node;
1038     int type;
1039     string s_value;
1040     Asset *asset = NULL;
1041
1042     if (p_type != XML_READER_STARTELEM)
1043         return -1;
1044     if( p_node != "Asset")
1045         return -1;
1046
1047     /* 1st node shall be Id" */
1048     if( ( type = XmlFile::ReadNextNode( this->p_demux, this->p_xmlReader, node ) ) )
1049         if ( ! ( ( type == XML_READER_STARTELEM ) && ( node == "Id" ) ) || type == -1 )
1050             return -1;
1051     if( ( type = XmlFile::ReadNextNode( this->p_demux, this->p_xmlReader, node ) ) != -1 )
1052     {
1053         if( type == XML_READER_TEXT )
1054         {
1055             s_value = node;
1056             if (unlikely(node.empty()))
1057                 return -1;
1058         }
1059     }
1060     else
1061         return -1;
1062
1063     if( ( type = XmlFile::ReadNextNode( this->p_demux, this->p_xmlReader, node ) ) != -1 )
1064     {
1065         if( type == XML_READER_ENDELEM )
1066         {
1067             asset = AssetMap::getAssetById(this->asset_list, s_value);
1068             if (asset  == NULL)
1069                 return -1;
1070         }
1071     }
1072     else
1073         return -1;
1074
1075      if (asset == NULL)
1076         return -1;
1077      if ( asset->ParsePKL(this->p_xmlReader) )
1078         return -1;
1079     return 0;
1080 }
1081
1082 int PKL::ParseSigner(string p_node, int p_type)
1083 {
1084     string node;
1085     int type;
1086
1087     if (p_type != XML_READER_STARTELEM)
1088         return -1;
1089     if( p_node != "Signer")
1090         return -1;
1091
1092     while( ( type = XmlFile::ReadNextNode( this->p_demux, this->p_xmlReader, node ) ) > 0 ) {
1093         /* TODO not implemented. Just parse until end of Signer node */
1094             if ((node == p_node) && (type = XML_READER_ENDELEM))
1095                 return 0;
1096     }
1097
1098     msg_Err(this->p_demux, "Parse of Signer finished bad");
1099     return -1;
1100 }
1101
1102 int PKL::ParseSignature(string p_node, int p_type)
1103 {
1104     string node;
1105     int type;
1106
1107     if (p_type != XML_READER_STARTELEM)
1108         return -1;
1109     if( p_node != "Signature")
1110         return -1;
1111
1112     while( ( type = XmlFile::ReadNextNode( this->p_demux, this->p_xmlReader, node ) ) > 0 ) {
1113         /* TODO not implemented. Just parse until end of Signature node */
1114             if ((node == p_node) && (type = XML_READER_ENDELEM))
1115                 return 0;
1116     }
1117     msg_Err(this->p_demux, "Parse of Signature finished bad");
1118     return -1;
1119 }
1120
1121 /*
1122  * Reel Class
1123  */
1124 int Reel::Parse(string p_node, int p_type) {
1125     string node;
1126     int type;
1127     string s_value;
1128
1129     if (p_type != XML_READER_STARTELEM)
1130         return -1;
1131     if( p_node != "Reel")
1132         return -1;
1133
1134     while( ( type = XmlFile::ReadNextNode( this->p_demux, this->p_xmlReader, node ) ) > 0 ) {
1135         switch (type) {
1136             case XML_READER_STARTELEM:
1137                 if (node =="Id") {
1138                     if ( XmlFile::ReadEndNode( this->p_demux, this->p_xmlReader, node, type, s_value ) )
1139                         return -1;
1140                     this->s_id = s_value;
1141                 } else if (node == "AnnotationText") {
1142                     if ( XmlFile::ReadEndNode( this->p_demux, this->p_xmlReader, node, type, s_value ) )
1143                         return -1;
1144                     this->s_annotation = s_value;
1145                 } else if ( node =="AssetList" ) {
1146                     if (this->ParseAssetList(node, type))
1147                         return -1;
1148                 } else {
1149                     /* unknown tag */
1150                     msg_Err(this->p_demux, "Reel::Parse, unknown tag:%s", node.c_str());
1151                     return -1;
1152                 }
1153                 break;
1154             case XML_READER_TEXT:
1155                 /* Error */
1156                 msg_Err(this->p_demux, "Reel parsing error");
1157                 return -1;
1158             case XML_READER_ENDELEM:
1159                 /* verify correctness of end node */
1160                 if ( node == p_node) {
1161                     /* TODO : verify Reel id */
1162                     return 0;
1163                 }
1164                 break;
1165         }
1166     }
1167     return -1;
1168 }
1169
1170
1171 Asset * Reel::getTrack(TrackType_t e_track)
1172 {
1173     switch (e_track) {
1174         case TRACK_PICTURE:
1175             return this->p_picture_track;
1176         case TRACK_SOUND:
1177             return this->p_sound_track;
1178         case TRACK_SUBTITLE:
1179             return this->p_subtitle_track;
1180         case TRACK_UNKNOWN:
1181         default:
1182             break;
1183     }
1184     return NULL;
1185 }
1186
1187 int Reel::ParseAssetList(string p_node, int p_type) {
1188     string node;
1189     int type;
1190     string s_value;
1191
1192     if (p_type != XML_READER_STARTELEM)
1193         return -1;
1194     if( p_node != "AssetList")
1195         return -1;
1196
1197     while( ( type = XmlFile::ReadNextNode( this->p_demux, this->p_xmlReader, node ) ) > 0 )  {
1198         switch (type) {
1199             case XML_READER_STARTELEM:
1200                 if (node =="MainPicture") {
1201                     if ( this->ParseAsset(node, type, TRACK_PICTURE) )
1202                         return -1;
1203                 } else if (node =="MainSound") {
1204                     if ( this->ParseAsset(node, type, TRACK_SOUND) )
1205                         return -1;
1206                 } else if (node =="MainSubtitle") {
1207                     if ( this->ParseAsset(node, type, TRACK_SUBTITLE) )
1208                         return -1;
1209                 } else {
1210                     /* unknown tag */
1211                     msg_Err(this->p_demux, "Reel::ParseAssetList, unknown tag:%s", node.c_str());
1212                     return -1;
1213                 }
1214                 break;
1215             case XML_READER_TEXT:
1216                 /* Parsing error */
1217                 msg_Err(this->p_demux, "AssetList parsing error");
1218                 return -1;
1219             case XML_READER_ENDELEM:
1220                 /* verify correctness of end node */
1221                 if ( node == p_node) {
1222                     /* TODO : verify id */
1223                     return 0;
1224                 }
1225                 break;
1226         }
1227     }
1228     return -1;
1229 }
1230
1231 int Reel::ParseAsset(string p_node, int p_type, TrackType_t e_track) {
1232     string node;
1233     int type;
1234     string s_value;
1235     bool b_stop_parse = false;
1236     Asset *asset = NULL;
1237
1238     if (p_type != XML_READER_STARTELEM)
1239         return -1;
1240
1241     /* 1st node shall be Id */
1242     if( ( type = XmlFile::ReadNextNode( this->p_demux, this->p_xmlReader, node ) ) )
1243         if( ! ( ( type == XML_READER_STARTELEM ) && ( node == "Id" ) ) || type == -1 )
1244             return -1;
1245
1246     if ( XmlFile::ReadEndNode( this->p_demux, this->p_xmlReader, node, type, s_value ) )
1247         return -1;
1248
1249     asset = AssetMap::getAssetById(this->p_asset_list, s_value);
1250     if (asset  == NULL)
1251         return -1;
1252
1253     while(  (! b_stop_parse) &&
1254             ( type = XmlFile::ReadNextNode( this->p_demux, this->p_xmlReader, node ) ) ) {
1255         switch (type) {
1256             case XML_READER_STARTELEM:
1257                 if (node =="EditRate") {
1258                     if ( XmlFile::ReadEndNode( this->p_demux, this->p_xmlReader, node, type, s_value ) )
1259                         return -1;
1260                 } else if (node == "AnnotationText") {
1261                     if ( XmlFile::ReadEndNode( this->p_demux, this->p_xmlReader, node, type, s_value ) )
1262                         return -1;
1263                         asset->setAnnotation(s_value);
1264                 } else if (node == "IntrinsicDuration") {
1265                     if ( XmlFile::ReadEndNode( this->p_demux, this->p_xmlReader, node, type, s_value ) )
1266                         return -1;
1267                         asset->setIntrinsicDuration(atoi(s_value.c_str()));
1268                 } else if (node == "EntryPoint") {
1269                     if ( XmlFile::ReadEndNode( this->p_demux, this->p_xmlReader, node, type, s_value ) )
1270                         return -1;
1271                         asset->setEntryPoint(atoi(s_value.c_str()));
1272                 } else if (node == "Duration") {
1273                     if ( XmlFile::ReadEndNode( this->p_demux, this->p_xmlReader, node, type, s_value ) )
1274                         return -1;
1275                         asset->setDuration(atoi(s_value.c_str()));
1276                 } else if (node == "KeyId") {
1277                     if ( XmlFile::ReadEndNode( this->p_demux, this->p_xmlReader, node, type, s_value ) )
1278                         return -1;
1279                     asset->setKeyId( s_value );
1280                 } else if (node == "Hash") {
1281                     if ( XmlFile::ReadEndNode( this->p_demux, this->p_xmlReader, node, type, s_value ) )
1282                         return -1;
1283                 } else if (node == "FrameRate") {
1284                     if ( XmlFile::ReadEndNode( this->p_demux, this->p_xmlReader, node, type, s_value ) )
1285                         return -1;
1286                 } else if (node == "ScreenAspectRatio") {
1287                     if ( XmlFile::ReadEndNode( this->p_demux, this->p_xmlReader, node, type, s_value ) )
1288                         return -1;
1289                 } else if (node == "Language") {
1290                     if ( XmlFile::ReadEndNode( this->p_demux, this->p_xmlReader, node, type, s_value ) )
1291                         return -1;
1292                 } else {
1293                     /* unknown tag */
1294                     msg_Err(this->p_demux, "Reel::ParseAsset unknown tag:%s", node.c_str());
1295                     return -1;
1296                 }
1297                 break;
1298             case XML_READER_TEXT:
1299             case -1:
1300                 /* error */
1301                 return -1;
1302                 break;
1303             case XML_READER_ENDELEM:
1304                 /* verify correctness of end node */
1305                 if ( node == p_node) {
1306                     /* TODO : verify id */
1307                     b_stop_parse = true;
1308                 }
1309         }
1310     }
1311     /* store by track */
1312     switch (e_track) {
1313         case TRACK_PICTURE:
1314             this->p_picture_track = asset;
1315             break;
1316         case TRACK_SOUND:
1317             this->p_sound_track = asset;
1318             break;
1319         case TRACK_SUBTITLE:
1320             this->p_subtitle_track = asset;
1321             break;
1322         case TRACK_UNKNOWN:
1323         default:
1324             break;
1325     }
1326     return 0;
1327 }
1328
1329 /*
1330  * CPL Class
1331  */
1332
1333 CPL::~CPL() {
1334     vlc_delete_all(vec_reel);
1335 }
1336
1337 int CPL::Parse()
1338 {
1339     string node;
1340     int type;
1341     string s_value;
1342     const string s_root_node = "CompositionPlaylist";
1343
1344     static const string names[] = {
1345         "Id",
1346         "AnnotationText",
1347         "IconId",
1348         "IssueDate",
1349         "Issuer",
1350         "Creator",
1351         "ContentTitleText",
1352         "ContentKind",
1353         "ContentVersion",
1354         "RatingList",
1355         "ReelList",
1356         "Signer",
1357         "Signature"
1358     };
1359
1360     if (this->OpenXml())
1361         return -1;
1362
1363     /* read 1st node  and verify that is a CPL*/
1364     if( ! ( ( XML_READER_STARTELEM == XmlFile::ReadNextNode( this->p_demux, this->p_xmlReader, node ) ) &&
1365                 (node == s_root_node) ) ) {
1366         msg_Err( this->p_demux, "Not a valid XML Packing List");
1367         goto error;
1368     }
1369
1370     while( ( type = XmlFile::ReadNextNode( this->p_demux, this->p_xmlReader, node ) ) ) {
1371         switch (type) {
1372             case XML_READER_STARTELEM: {
1373                 CPLTag_t _tag = CPL_UNKNOWN;
1374                 for(CPLTag_t i = CPL_ID; i <= CPL_SIGNATURE; i = CPLTag_t(i+1)) {
1375                     if( node == names[i-1]) {
1376                         _tag = i;
1377                         switch (_tag) {
1378                             /* case for parsing non terminal nodes */
1379                             case CPL_REEL_LIST:
1380                                 if ( this->ParseReelList(node, type) )
1381                                     goto error;
1382                                 break;
1383                             case CPL_CONTENT_VERSION:
1384                             case CPL_SIGNER:
1385                             case CPL_SIGNATURE:
1386                             case CPL_RATING_LIST:
1387                                 if ( this->DummyParse(node,type) )
1388                                     goto error;
1389                                 break;
1390                                 /* Parse simple/end nodes */
1391                             case CPL_ID:
1392                                 if ( XmlFile::ReadEndNode( this->p_demux, p_xmlReader, node, type, s_value ) )
1393                                     goto error;
1394                                 this->s_id = s_value;
1395                                 break;
1396                             case CPL_ANNOTATION_TEXT:
1397                                 if ( XmlFile::ReadEndNode( this->p_demux, p_xmlReader, node, type, s_value ) )
1398                                     goto error;
1399                                 this->s_annotation = s_value;
1400                                 break;
1401                             case CPL_ICON_ID:
1402                                 if ( XmlFile::ReadEndNode( this->p_demux, p_xmlReader, node, type, s_value ) )
1403                                     goto error;
1404                                 this->s_icon_id = s_value;
1405                                 break;
1406                             case CPL_ISSUE_DATE:
1407                                 if ( XmlFile::ReadEndNode( this->p_demux, p_xmlReader, node, type, s_value ) )
1408                                     goto error;
1409                                 this->s_issue_date= s_value;
1410                                 break;
1411                             case CPL_ISSUER:
1412                                 if ( XmlFile::ReadEndNode( this->p_demux, p_xmlReader, node, type, s_value ) )
1413                                     goto error;
1414                                 this->s_issuer = s_value;
1415                                 break;
1416                             case CPL_CREATOR:
1417                                 if ( XmlFile::ReadEndNode( this->p_demux, p_xmlReader, node, type, s_value ) )
1418                                     goto error;
1419                                 this->s_creator = s_value;
1420                                 break;
1421                             case CPL_CONTENT_TITLE:
1422                                 if ( XmlFile::ReadEndNode( this->p_demux, p_xmlReader, node, type, s_value ) )
1423                                     goto error;
1424                                 this->s_content_title = s_value;
1425                                 break;
1426                             case CPL_CONTENT_KIND:
1427                                 if ( XmlFile::ReadEndNode( this->p_demux, p_xmlReader, node, type, s_value ) )
1428                                     goto error;
1429                                 this->s_content_kind = s_value;
1430                                 break;
1431                             default:
1432                                 msg_Warn(this->p_demux, "Unknow CPL_TAG: %i", _tag );
1433                                 break;
1434                         }
1435
1436                         /* break the for loop as a tag is found*/
1437                         break;
1438                     }
1439                 }
1440                 if( _tag == CPL_UNKNOWN )
1441                     goto error;
1442                 break;
1443             }
1444             case XML_READER_TEXT:
1445             case -1:
1446                goto error;
1447             case XML_READER_ENDELEM:
1448                if ( node != s_root_node) {
1449                    msg_Err(this->p_demux,
1450                            "Something goes wrong in CKL parsing (node %s)", node.c_str());
1451                    goto error;
1452                }
1453                break;
1454         }
1455     }
1456
1457     /* TODO verify presence of mandatory fields*/
1458
1459     /* Close CPL XML*/
1460     this->CloseXml();
1461     return 0;
1462 error:
1463     this->CloseXml();
1464     return -1;
1465 }
1466
1467 int CPL::ParseReelList(string p_node, int p_type) {
1468     string node;
1469     int type;
1470
1471     if (p_type != XML_READER_STARTELEM)
1472         return -1;
1473     if( p_node != "ReelList")
1474         return -1;
1475     while( ( type = XmlFile::ReadNextNode( this->p_demux, this->p_xmlReader, node ) ) > 0 ) {
1476         switch (type) {
1477             case XML_READER_STARTELEM: {
1478                 Reel *p_reel = new (nothrow) Reel( this->p_demux, this->asset_list, this->p_xmlReader);
1479                 if ( unlikely(p_reel == NULL) )
1480                     return -1;
1481                 if( node =="Reel") {
1482                     if ( p_reel->Parse(node, type) ) {
1483                         delete p_reel;
1484                         return -1;
1485                     }
1486                 } else {
1487                     delete p_reel;
1488                     return -1;
1489                 }
1490                 this->vec_reel.push_back(p_reel);
1491
1492                 break;
1493             }
1494             case XML_READER_TEXT:
1495                 /* impossible */
1496                 break;
1497             case XML_READER_ENDELEM:
1498                 if ( node == p_node)
1499                     return 0;
1500                 break;
1501             }
1502     }
1503     return -1;
1504 }
1505
1506
1507 int CPL::DummyParse(string p_node, int p_type)
1508 {
1509     string node;
1510     int type;
1511
1512     if (p_type != XML_READER_STARTELEM)
1513         return -1;
1514
1515     if (xml_ReaderIsEmptyElement( this->p_xmlReader))
1516         return 0;
1517
1518     while( ( type = XmlFile::ReadNextNode( this->p_demux, this->p_xmlReader, node ) ) > 0 ) {
1519         /* TODO not implemented. Just pase until end of input node */
1520         if ((node == p_node) && (type = XML_READER_ENDELEM))
1521             return 0;
1522     }
1523
1524     return -1;
1525 }