lib: fix track count in get_track_from_id()
[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 supported. 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     psz_uri = vlc_path2uri( this->s_path.c_str(), "file" );
727     this->p_stream = vlc_stream_NewURL(this->p_demux, psz_uri );
728     free(psz_uri);
729     if( ! this->p_stream ) {
730         return -1;
731     }
732
733     this->p_xmlReader = xml_ReaderCreate( this->p_demux, this->p_stream);
734     if( ! this->p_xmlReader ) {
735         vlc_stream_Delete( this->p_stream );
736         return -1;
737     }
738     return 0;
739 }
740
741 int XmlFile::ReadNextNode( demux_t *p_demux, xml_reader_t *p_xmlReader, string& p_node )
742 {
743     const char * c_node;
744     int i = xml_ReaderNextNode( p_xmlReader, &c_node );
745
746     if( i <= XML_READER_NONE )
747         return i;
748
749     /* remove namespaces, if there are any */
750     string s_node = c_node;
751     size_t ui_pos = s_node.find( ":" );
752
753     if( ( i == XML_READER_STARTELEM || i == XML_READER_ENDELEM ) && ( ui_pos != string::npos ) )
754     {
755         try
756         {
757             p_node = s_node.substr( ui_pos + 1 );
758         }
759         catch( ... )
760         {
761             msg_Err( p_demux, "error while handling string" );
762             return -1;
763         }
764     }
765     else
766         p_node = s_node;
767
768     return i;
769 }
770
771 int XmlFile::ReadEndNode( demux_t *p_demux, xml_reader_t *p_xmlReader, string p_node, int p_type, string &s_value)
772 {
773     string node;
774
775     if ( xml_ReaderIsEmptyElement( p_xmlReader) )
776             return 0;
777
778     if (p_type != XML_READER_STARTELEM)
779         return -1;
780
781     int n = XmlFile::ReadNextNode( p_demux, p_xmlReader, node );
782     if( n == XML_READER_TEXT )
783     {
784         s_value = node;
785         n = XmlFile::ReadNextNode( p_demux, p_xmlReader, node );
786         if( ( n == XML_READER_ENDELEM ) && node == p_node)
787             return 0;
788     }
789     return n == XML_READER_ENDELEM ? 0 : -1;
790 }
791 /*
792  * Reads first node in XML and returns
793  * 1 if XML is CPL,
794  * 0 if not
795  * -1 on error
796  */
797 int XmlFile::isCPL()
798 {
799     string node;
800     int type, ret = 0;
801
802     if( this->OpenXml() )
803     {
804         msg_Err( this->p_demux, "Failed to open CPL XML file" );
805         return -1;
806     }
807
808     /* read 1st node  and verify that is a CPL */
809     type = XmlFile::ReadNextNode( this->p_demux, p_xmlReader, node );
810     if( type == -1 ) /* error */
811         ret = -1;
812     if( type == XML_READER_STARTELEM &&  node == "CompositionPlaylist" )
813         ret = 1;
814
815     /* close xml */
816     this->CloseXml();
817     return ret;
818 }
819
820 void XmlFile::CloseXml() {
821     if( this->p_stream )
822         vlc_stream_Delete( this->p_stream );
823     if( this->p_xmlReader )
824         xml_ReaderDelete( this->p_xmlReader );
825 }
826
827 /*
828  * PKL Class
829  */
830
831 PKL::~PKL() {
832     vlc_delete_all(vec_cpl);
833 }
834
835 int PKL::Parse()
836 {
837     string node;
838     int type;
839     string s_value;
840     const string s_root_node = "PackingList";
841
842     static const string names[] = {
843         "Id",
844         "IssueDate",
845         "Issuer",
846         "Creator",
847         "AssetList",
848         "AnnotationText",
849         "IconId",
850         "GroupId",
851         "Signer",
852         "Signature"
853     };
854
855     if (this->OpenXml())
856         return -1;
857
858     /* read 1st node  and verify that is a PKL*/
859     if ( ! ( ( XML_READER_STARTELEM == XmlFile::ReadNextNode( this->p_demux, this->p_xmlReader, node ) ) &&
860                 (node == s_root_node) ) ) {
861         msg_Err( this->p_demux, "Not a valid XML Packing List");
862         goto error;
863     }
864     while( ( type = XmlFile::ReadNextNode( this->p_demux, this->p_xmlReader, node ) ) ) {
865         switch (type) {
866             case XML_READER_STARTELEM: {
867                 PKLTag_t _tag = PKL_UNKNOWN;
868                 for(PKLTag_t i = PKL_ID; i <= PKL_SIGNATURE; i = PKLTag_t(i+1)) {
869                     if( node == names[i-1]) {
870                         _tag = i;
871                         switch (_tag) {
872                             /* case for parsing non terminal nodes */
873                             case PKL_ASSET_LIST:
874                                 if ( this->ParseAssetList(node, type) )
875                                     goto error;
876                                 break;
877                             case PKL_SIGNER:
878                                 if ( this->ParseSigner(node, type) )
879                                     goto error;
880                                 break;
881                             case PKL_SIGNATURE:
882                                 if ( this->ParseSignature(node, type) )
883                                     goto error;
884                                 break;
885                             /* Parse simple/end nodes */
886                             case PKL_ID:
887                                 if ( XmlFile::ReadEndNode( this->p_demux, p_xmlReader, node, type, s_value ) )
888                                     goto error;
889                                 this->s_id = s_value;
890                                 break;
891                             case PKL_ISSUE_DATE:
892                                 if ( XmlFile::ReadEndNode( this->p_demux, p_xmlReader, node, type, s_value ) )
893                                     goto error;
894                                 this->s_issue_date = s_value;
895                                 break;
896                             case PKL_ISSUER:
897                                 if ( XmlFile::ReadEndNode( this->p_demux, p_xmlReader, node, type, s_value ) )
898                                     goto error;
899                                 this->s_issuer = s_value;
900                                 break;
901                             case PKL_CREATOR:
902                                 if ( XmlFile::ReadEndNode( this->p_demux, p_xmlReader, node, type, s_value ) )
903                                     goto error;
904                                 this->s_creator = s_value;
905                                 break;
906                             case PKL_ANNOTATION_TEXT:
907                                 if ( XmlFile::ReadEndNode( this->p_demux, p_xmlReader, node, type, s_value ) )
908                                     goto error;
909                                 this->s_annotation = s_value;
910                                 break;
911                             case PKL_ICON_ID:
912                                 if ( XmlFile::ReadEndNode( this->p_demux, p_xmlReader, node, type, s_value ) )
913                                     goto error;
914                                 this->s_icon_id = s_value;
915                                 break;
916                             case PKL_GROUP_ID:
917                                 if ( XmlFile::ReadEndNode( this->p_demux, p_xmlReader, node, type, s_value ) )
918                                     goto error;
919                                 this->s_group_id = s_value;
920                                 break;
921                             default:
922                                 msg_Warn(this->p_demux, "Unknow PKG_TAG: %i", _tag );
923                                 break;
924                         }
925                         /* break the for loop as a tag is found*/
926                         break;
927                     }
928                 }
929                 if( _tag == PKL_UNKNOWN )
930                     goto error;
931                 break;
932             }
933             case XML_READER_TEXT:
934             case -1:
935                 goto error;
936             case XML_READER_ENDELEM:
937                 if ( node != s_root_node) {
938                     msg_Err(this->p_demux,
939                         "Something goes wrong in PKL parsing (node %s)", node.c_str());
940                     goto error;
941                 }
942                 break;
943         }
944     }
945     /* TODO verify presence of mandatory fields*/
946
947     /* Close PKL XML*/
948     this->CloseXml();
949     return 0;
950 error:
951     msg_Err( this->p_demux, "PKL parsing failed");
952     this->CloseXml();
953     return -1;
954 }
955
956 int PKL::FindCPLs()
957 {
958     if ( this->vec_cpl.size() != 0 ) {
959         msg_Err(this->p_demux, "CPLs already checked");
960         return -1;
961     }
962
963     for (AssetList::iterator index = this->asset_list->begin();
964             index != this->asset_list->end(); ++index) {
965         Asset *asset = *index;
966         if ( asset->getType().find("text/xml") == string::npos) {
967             /* not an xml file */
968             continue;
969         }
970
971         CPL *cpl = new (nothrow) CPL(this->p_demux,
972                       this->s_dcp_path + asset->getPath(),
973                       this->asset_list);
974         if ( unlikely(cpl == NULL) )
975                     return -1;
976         switch( cpl->isCPL() )
977         {
978             case 1:
979                 /* CPL Found */
980                 this->vec_cpl.push_back(cpl);
981                 break;
982             case -1:
983                 /* error */
984                 delete cpl;
985                 return -1;
986             case 0:
987             default:
988                 delete cpl;
989                 break;
990         }
991     }
992     return this->vec_cpl.size();
993 }
994
995
996 int PKL::ParseAssetList(string p_node, int p_type) {
997     string node;
998     int type;
999
1000     if (p_type != XML_READER_STARTELEM)
1001         return -1;
1002     if( p_node != "AssetList")
1003         return -1;
1004     while( ( type = XmlFile::ReadNextNode( this->p_demux, this->p_xmlReader, node ) ) ) {
1005         switch (type) {
1006             case XML_READER_STARTELEM:
1007                 if( node =="Asset") {
1008                     if ( this->ParseAsset(node, type) )
1009                         return -1;
1010                 } else
1011                     return -1;
1012                 break;
1013             case XML_READER_ENDELEM:
1014                 if ( node == p_node) {
1015                     /* parse of chunklist finished */
1016                     goto end;
1017                 }
1018                 break;
1019             case -1:
1020                 /* error */
1021                 return -1;
1022         }
1023     }
1024 end:
1025     return 0;
1026 }
1027
1028 int PKL::ParseAsset(string p_node, int p_type) {
1029     string node;
1030     int type;
1031     string s_value;
1032     Asset *asset = NULL;
1033
1034     if (p_type != XML_READER_STARTELEM)
1035         return -1;
1036     if( p_node != "Asset")
1037         return -1;
1038
1039     /* 1st node shall be Id" */
1040     if( ( type = XmlFile::ReadNextNode( this->p_demux, this->p_xmlReader, node ) ) )
1041         if ( ! ( ( type == XML_READER_STARTELEM ) && ( node == "Id" ) ) || type == -1 )
1042             return -1;
1043     if( ( type = XmlFile::ReadNextNode( this->p_demux, this->p_xmlReader, node ) ) != -1 )
1044     {
1045         if( type == XML_READER_TEXT )
1046         {
1047             s_value = node;
1048             if (unlikely(node.empty()))
1049                 return -1;
1050         }
1051     }
1052     else
1053         return -1;
1054
1055     if( ( type = XmlFile::ReadNextNode( this->p_demux, this->p_xmlReader, node ) ) != -1 )
1056     {
1057         if( type == XML_READER_ENDELEM )
1058         {
1059             asset = AssetMap::getAssetById(this->asset_list, s_value);
1060             if (asset  == NULL)
1061                 return -1;
1062         }
1063     }
1064     else
1065         return -1;
1066
1067      if (asset == NULL)
1068         return -1;
1069      if ( asset->ParsePKL(this->p_xmlReader) )
1070         return -1;
1071     return 0;
1072 }
1073
1074 int PKL::ParseSigner(string p_node, int p_type)
1075 {
1076     string node;
1077     int type;
1078
1079     if (p_type != XML_READER_STARTELEM)
1080         return -1;
1081     if( p_node != "Signer")
1082         return -1;
1083
1084     while( ( type = XmlFile::ReadNextNode( this->p_demux, this->p_xmlReader, node ) ) > 0 ) {
1085         /* TODO not implemented. Just parse until end of Signer node */
1086             if ((node == p_node) && (type == XML_READER_ENDELEM))
1087                 return 0;
1088     }
1089
1090     msg_Err(this->p_demux, "Parse of Signer finished bad");
1091     return -1;
1092 }
1093
1094 int PKL::ParseSignature(string p_node, int p_type)
1095 {
1096     string node;
1097     int type;
1098
1099     if (p_type != XML_READER_STARTELEM)
1100         return -1;
1101     if( p_node != "Signature")
1102         return -1;
1103
1104     while( ( type = XmlFile::ReadNextNode( this->p_demux, this->p_xmlReader, node ) ) > 0 ) {
1105         /* TODO not implemented. Just parse until end of Signature node */
1106             if ((node == p_node) && (type == XML_READER_ENDELEM))
1107                 return 0;
1108     }
1109     msg_Err(this->p_demux, "Parse of Signature finished bad");
1110     return -1;
1111 }
1112
1113 /*
1114  * Reel Class
1115  */
1116 int Reel::Parse(string p_node, int p_type) {
1117     string node;
1118     int type;
1119     string s_value;
1120
1121     if (p_type != XML_READER_STARTELEM)
1122         return -1;
1123     if( p_node != "Reel")
1124         return -1;
1125
1126     while( ( type = XmlFile::ReadNextNode( this->p_demux, this->p_xmlReader, node ) ) > 0 ) {
1127         switch (type) {
1128             case XML_READER_STARTELEM:
1129                 if (node =="Id") {
1130                     if ( XmlFile::ReadEndNode( this->p_demux, this->p_xmlReader, node, type, s_value ) )
1131                         return -1;
1132                     this->s_id = s_value;
1133                 } else if (node == "AnnotationText") {
1134                     if ( XmlFile::ReadEndNode( this->p_demux, this->p_xmlReader, node, type, s_value ) )
1135                         return -1;
1136                     this->s_annotation = s_value;
1137                 } else if ( node =="AssetList" ) {
1138                     if (this->ParseAssetList(node, type))
1139                         return -1;
1140                 } else {
1141                     /* unknown tag */
1142                     msg_Err(this->p_demux, "Reel::Parse, unknown tag:%s", node.c_str());
1143                     return -1;
1144                 }
1145                 break;
1146             case XML_READER_TEXT:
1147                 /* Error */
1148                 msg_Err(this->p_demux, "Reel parsing error");
1149                 return -1;
1150             case XML_READER_ENDELEM:
1151                 /* verify correctness of end node */
1152                 if ( node == p_node) {
1153                     /* TODO : verify Reel id */
1154                     return 0;
1155                 }
1156                 break;
1157         }
1158     }
1159     return -1;
1160 }
1161
1162
1163 Asset * Reel::getTrack(TrackType_t e_track)
1164 {
1165     switch (e_track) {
1166         case TRACK_PICTURE:
1167             return this->p_picture_track;
1168         case TRACK_SOUND:
1169             return this->p_sound_track;
1170         case TRACK_SUBTITLE:
1171             return this->p_subtitle_track;
1172         case TRACK_UNKNOWN:
1173         default:
1174             break;
1175     }
1176     return NULL;
1177 }
1178
1179 int Reel::ParseAssetList(string p_node, int p_type) {
1180     string node;
1181     int type;
1182     string s_value;
1183
1184     if (p_type != XML_READER_STARTELEM)
1185         return -1;
1186     if( p_node != "AssetList")
1187         return -1;
1188
1189     while( ( type = XmlFile::ReadNextNode( this->p_demux, this->p_xmlReader, node ) ) > 0 )  {
1190         switch (type) {
1191             case XML_READER_STARTELEM:
1192                 if (node =="MainPicture") {
1193                     if ( this->ParseAsset(node, type, TRACK_PICTURE) )
1194                         return -1;
1195                 } else if (node =="MainSound") {
1196                     if ( this->ParseAsset(node, type, TRACK_SOUND) )
1197                         return -1;
1198                 } else if (node =="MainSubtitle") {
1199                     if ( this->ParseAsset(node, type, TRACK_SUBTITLE) )
1200                         return -1;
1201                 } else {
1202                     /* unknown tag */
1203                     msg_Err(this->p_demux, "Reel::ParseAssetList, unknown tag:%s", node.c_str());
1204                     return -1;
1205                 }
1206                 break;
1207             case XML_READER_TEXT:
1208                 /* Parsing error */
1209                 msg_Err(this->p_demux, "AssetList parsing error");
1210                 return -1;
1211             case XML_READER_ENDELEM:
1212                 /* verify correctness of end node */
1213                 if ( node == p_node) {
1214                     /* TODO : verify id */
1215                     return 0;
1216                 }
1217                 break;
1218         }
1219     }
1220     return -1;
1221 }
1222
1223 int Reel::ParseAsset(string p_node, int p_type, TrackType_t e_track) {
1224     string node;
1225     int type;
1226     string s_value;
1227     bool b_stop_parse = false;
1228     Asset *asset = NULL;
1229
1230     if (p_type != XML_READER_STARTELEM)
1231         return -1;
1232
1233     /* 1st node shall be Id */
1234     if( ( type = XmlFile::ReadNextNode( this->p_demux, this->p_xmlReader, node ) ) )
1235         if( ! ( ( type == XML_READER_STARTELEM ) && ( node == "Id" ) ) || type == -1 )
1236             return -1;
1237
1238     if ( XmlFile::ReadEndNode( this->p_demux, this->p_xmlReader, node, type, s_value ) )
1239         return -1;
1240
1241     asset = AssetMap::getAssetById(this->p_asset_list, s_value);
1242     if (asset  == NULL)
1243         return -1;
1244
1245     while(  (! b_stop_parse) &&
1246             ( type = XmlFile::ReadNextNode( this->p_demux, this->p_xmlReader, node ) ) ) {
1247         switch (type) {
1248             case XML_READER_STARTELEM:
1249                 if (node =="EditRate") {
1250                     if ( XmlFile::ReadEndNode( this->p_demux, this->p_xmlReader, node, type, s_value ) )
1251                         return -1;
1252                 } else if (node == "AnnotationText") {
1253                     if ( XmlFile::ReadEndNode( this->p_demux, this->p_xmlReader, node, type, s_value ) )
1254                         return -1;
1255                     asset->setAnnotation(s_value);
1256                 } else if (node == "IntrinsicDuration") {
1257                     if ( XmlFile::ReadEndNode( this->p_demux, this->p_xmlReader, node, type, s_value ) )
1258                         return -1;
1259                     asset->setIntrinsicDuration(atoi(s_value.c_str()));
1260                 } else if (node == "EntryPoint") {
1261                     if ( XmlFile::ReadEndNode( this->p_demux, this->p_xmlReader, node, type, s_value ) )
1262                         return -1;
1263                     asset->setEntryPoint(atoi(s_value.c_str()));
1264                 } else if (node == "Duration") {
1265                     if ( XmlFile::ReadEndNode( this->p_demux, this->p_xmlReader, node, type, s_value ) )
1266                         return -1;
1267                     asset->setDuration(atoi(s_value.c_str()));
1268                 } else if (node == "KeyId") {
1269                     if ( XmlFile::ReadEndNode( this->p_demux, this->p_xmlReader, node, type, s_value ) )
1270                         return -1;
1271                     asset->setKeyId( s_value );
1272                 } else if (node == "Hash") {
1273                     if ( XmlFile::ReadEndNode( this->p_demux, this->p_xmlReader, node, type, s_value ) )
1274                         return -1;
1275                 } else if (node == "FrameRate") {
1276                     if ( XmlFile::ReadEndNode( this->p_demux, this->p_xmlReader, node, type, s_value ) )
1277                         return -1;
1278                 } else if (node == "ScreenAspectRatio") {
1279                     if ( XmlFile::ReadEndNode( this->p_demux, this->p_xmlReader, node, type, s_value ) )
1280                         return -1;
1281                 } else if (node == "Language") {
1282                     if ( XmlFile::ReadEndNode( this->p_demux, this->p_xmlReader, node, type, s_value ) )
1283                         return -1;
1284                 } else {
1285                     /* unknown tag */
1286                     msg_Err(this->p_demux, "Reel::ParseAsset unknown tag:%s", node.c_str());
1287                     return -1;
1288                 }
1289                 break;
1290             case XML_READER_TEXT:
1291             case -1:
1292                 /* error */
1293                 return -1;
1294                 break;
1295             case XML_READER_ENDELEM:
1296                 /* verify correctness of end node */
1297                 if ( node == p_node) {
1298                     /* TODO : verify id */
1299                     b_stop_parse = true;
1300                 }
1301         }
1302     }
1303     /* store by track */
1304     switch (e_track) {
1305         case TRACK_PICTURE:
1306             this->p_picture_track = asset;
1307             break;
1308         case TRACK_SOUND:
1309             this->p_sound_track = asset;
1310             break;
1311         case TRACK_SUBTITLE:
1312             this->p_subtitle_track = asset;
1313             break;
1314         case TRACK_UNKNOWN:
1315         default:
1316             break;
1317     }
1318     return 0;
1319 }
1320
1321 /*
1322  * CPL Class
1323  */
1324
1325 CPL::~CPL() {
1326     vlc_delete_all(vec_reel);
1327 }
1328
1329 int CPL::Parse()
1330 {
1331     string node;
1332     int type;
1333     string s_value;
1334     const string s_root_node = "CompositionPlaylist";
1335
1336     static const string names[] = {
1337         "Id",
1338         "AnnotationText",
1339         "IconId",
1340         "IssueDate",
1341         "Issuer",
1342         "Creator",
1343         "ContentTitleText",
1344         "ContentKind",
1345         "ContentVersion",
1346         "RatingList",
1347         "ReelList",
1348         "Signer",
1349         "Signature"
1350     };
1351
1352     if (this->OpenXml())
1353         return -1;
1354
1355     /* read 1st node  and verify that is a CPL*/
1356     if( ! ( ( XML_READER_STARTELEM == XmlFile::ReadNextNode( this->p_demux, this->p_xmlReader, node ) ) &&
1357                 (node == s_root_node) ) ) {
1358         msg_Err( this->p_demux, "Not a valid XML Packing List");
1359         goto error;
1360     }
1361
1362     while( ( type = XmlFile::ReadNextNode( this->p_demux, this->p_xmlReader, node ) ) ) {
1363         switch (type) {
1364             case XML_READER_STARTELEM: {
1365                 CPLTag_t _tag = CPL_UNKNOWN;
1366                 for(CPLTag_t i = CPL_ID; i <= CPL_SIGNATURE; i = CPLTag_t(i+1)) {
1367                     if( node == names[i-1]) {
1368                         _tag = i;
1369                         switch (_tag) {
1370                             /* case for parsing non terminal nodes */
1371                             case CPL_REEL_LIST:
1372                                 if ( this->ParseReelList(node, type) )
1373                                     goto error;
1374                                 break;
1375                             case CPL_CONTENT_VERSION:
1376                             case CPL_SIGNER:
1377                             case CPL_SIGNATURE:
1378                             case CPL_RATING_LIST:
1379                                 if ( this->DummyParse(node,type) )
1380                                     goto error;
1381                                 break;
1382                                 /* Parse simple/end nodes */
1383                             case CPL_ID:
1384                                 if ( XmlFile::ReadEndNode( this->p_demux, p_xmlReader, node, type, s_value ) )
1385                                     goto error;
1386                                 this->s_id = s_value;
1387                                 break;
1388                             case CPL_ANNOTATION_TEXT:
1389                                 if ( XmlFile::ReadEndNode( this->p_demux, p_xmlReader, node, type, s_value ) )
1390                                     goto error;
1391                                 this->s_annotation = s_value;
1392                                 break;
1393                             case CPL_ICON_ID:
1394                                 if ( XmlFile::ReadEndNode( this->p_demux, p_xmlReader, node, type, s_value ) )
1395                                     goto error;
1396                                 this->s_icon_id = s_value;
1397                                 break;
1398                             case CPL_ISSUE_DATE:
1399                                 if ( XmlFile::ReadEndNode( this->p_demux, p_xmlReader, node, type, s_value ) )
1400                                     goto error;
1401                                 this->s_issue_date= s_value;
1402                                 break;
1403                             case CPL_ISSUER:
1404                                 if ( XmlFile::ReadEndNode( this->p_demux, p_xmlReader, node, type, s_value ) )
1405                                     goto error;
1406                                 this->s_issuer = s_value;
1407                                 break;
1408                             case CPL_CREATOR:
1409                                 if ( XmlFile::ReadEndNode( this->p_demux, p_xmlReader, node, type, s_value ) )
1410                                     goto error;
1411                                 this->s_creator = s_value;
1412                                 break;
1413                             case CPL_CONTENT_TITLE:
1414                                 if ( XmlFile::ReadEndNode( this->p_demux, p_xmlReader, node, type, s_value ) )
1415                                     goto error;
1416                                 this->s_content_title = s_value;
1417                                 break;
1418                             case CPL_CONTENT_KIND:
1419                                 if ( XmlFile::ReadEndNode( this->p_demux, p_xmlReader, node, type, s_value ) )
1420                                     goto error;
1421                                 this->s_content_kind = s_value;
1422                                 break;
1423                             default:
1424                                 msg_Warn(this->p_demux, "Unknow CPL_TAG: %i", _tag );
1425                                 break;
1426                         }
1427
1428                         /* break the for loop as a tag is found*/
1429                         break;
1430                     }
1431                 }
1432                 if( _tag == CPL_UNKNOWN )
1433                     goto error;
1434                 break;
1435             }
1436             case XML_READER_TEXT:
1437             case -1:
1438                goto error;
1439             case XML_READER_ENDELEM:
1440                if ( node != s_root_node) {
1441                    msg_Err(this->p_demux,
1442                            "Something goes wrong in CKL parsing (node %s)", node.c_str());
1443                    goto error;
1444                }
1445                break;
1446         }
1447     }
1448
1449     /* TODO verify presence of mandatory fields*/
1450
1451     /* Close CPL XML*/
1452     this->CloseXml();
1453     return 0;
1454 error:
1455     this->CloseXml();
1456     return -1;
1457 }
1458
1459 int CPL::ParseReelList(string p_node, int p_type) {
1460     string node;
1461     int type;
1462
1463     if (p_type != XML_READER_STARTELEM)
1464         return -1;
1465     if( p_node != "ReelList")
1466         return -1;
1467     while( ( type = XmlFile::ReadNextNode( this->p_demux, this->p_xmlReader, node ) ) > 0 ) {
1468         switch (type) {
1469             case XML_READER_STARTELEM: {
1470                 Reel *p_reel = new (nothrow) Reel( this->p_demux, this->asset_list, this->p_xmlReader);
1471                 if ( unlikely(p_reel == NULL) )
1472                     return -1;
1473                 if( node =="Reel") {
1474                     if ( p_reel->Parse(node, type) ) {
1475                         delete p_reel;
1476                         return -1;
1477                     }
1478                 } else {
1479                     delete p_reel;
1480                     return -1;
1481                 }
1482                 this->vec_reel.push_back(p_reel);
1483
1484                 break;
1485             }
1486             case XML_READER_TEXT:
1487                 /* impossible */
1488                 break;
1489             case XML_READER_ENDELEM:
1490                 if ( node == p_node)
1491                     return 0;
1492                 break;
1493             }
1494     }
1495     return -1;
1496 }
1497
1498
1499 int CPL::DummyParse(string p_node, int p_type)
1500 {
1501     string node;
1502     int type;
1503
1504     if (p_type != XML_READER_STARTELEM)
1505         return -1;
1506
1507     if (xml_ReaderIsEmptyElement( this->p_xmlReader))
1508         return 0;
1509
1510     while( ( type = XmlFile::ReadNextNode( this->p_demux, this->p_xmlReader, node ) ) > 0 ) {
1511         /* TODO not implemented. Just pase until end of input node */
1512         if ((node == p_node) && (type == XML_READER_ENDELEM))
1513             return 0;
1514     }
1515
1516     return -1;
1517 }