dcp: ignore prefixes in XML nodes
[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
252     /* Look for PKLs path */
253     if ( (_p_asset_list == NULL) ||  (_p_asset_list->size() == 0) ) {
254         msg_Err( p_demux, "Asset list empty" );
255         this->CloseXml();
256         return -1;
257     }
258
259     for (AssetList::iterator iter = _p_asset_list->begin();
260             iter != _p_asset_list->end() ; ++iter) {
261         string s_filepath;
262         s_filepath = (*iter)->getPath();
263         if (s_filepath.empty()) {
264             msg_Err( p_demux, "No path element for asset" );
265             continue;
266         }
267         /* set an absolute file path */
268         s_filepath = p_dcp->path + s_filepath;
269
270         /* case of packing list */
271         if ((*iter)->isPackingList()) {
272             pklfiles.push_back( s_filepath );
273         }
274     }
275
276     /* TODO: case of only on PKL managed.
277      * Future work needed for managing severals
278      * the PKL vector will be used to select the required PKL  */
279     if( (pklfiles.size() == 0)  || (pklfiles[0].empty()) )
280     {
281         msg_Err( p_demux, "Could not find PKL file in ASSETMAP" );
282         this->CloseXml();
283         return -1;
284     }
285
286     /* Create the first PKL */
287     pkl = new (nothrow) PKL(p_demux, pklfiles[0], _p_asset_list, p_dcp->path);
288     if ( unlikely(pkl == NULL) ) {
289         this->CloseXml();
290         return -1;
291         }
292     if (pkl->Parse()) {
293         delete pkl;
294         this->CloseXml();
295         return -1;
296         }
297     p_dcp->pkls.push_back( pkl );
298
299     /* Now, CPL */
300     if ( pkl->FindCPLs() <= 0 ) {
301         msg_Err(p_demux, " No CPL found");
302         this->CloseXml();
303         return -1;
304     }
305     /* TODO: Only one CPL managed.
306      * Future work needed for managing severals
307      */
308
309     cpl = pkl->getCPL(0);
310     if( cpl == NULL ) {
311         msg_Err(p_demux, " No CPL found");
312         this->CloseXml();
313         return -1;
314     }
315     if ( cpl->Parse() ) {
316         this->CloseXml();
317         return -1;
318     }
319
320     /* KDM, if needed */
321     for( AssetList::iterator iter = _p_asset_list->begin(); iter != _p_asset_list->end(); ++iter )
322         if( ! (*iter)->getKeyId().empty() )
323         {
324             msg_Dbg( p_demux, "DCP is encrypted, searching KDM file...");
325             psz_kdm_path = var_InheritString( p_demux, "kdm" );
326             if( !psz_kdm_path || !*psz_kdm_path )
327             {
328                 msg_Err( p_demux, "cryptographic key IDs found in CPL and no path to KDM given");
329                 free( psz_kdm_path );
330                 this->CloseXml();
331                 return VLC_EGENERIC;
332             }
333             KDM p_kdm( p_demux, psz_kdm_path, p_dcp );
334             free( psz_kdm_path );
335             if( ( retval = p_kdm.Parse() ) )
336             {
337                 this->CloseXml();
338                 return retval;
339             }
340             break;
341         }
342
343     reel_nbr = cpl->getReelList().size();
344     for(index = 0; index != reel_nbr; ++index)
345     {
346         reel = cpl->getReel(index);
347
348         Asset *asset;
349         struct info_reel video;
350         struct info_reel audio;
351
352         /* Get picture */
353         asset = reel->getTrack(TRACK_PICTURE);
354         if (asset != NULL)
355         {
356             sum_duration_vid += asset->getDuration();
357             video.filename = p_dcp->path + asset->getPath();
358             video.i_entrypoint = asset->getEntryPoint();
359             video.i_duration = asset->getDuration();
360             video.i_correction = video.i_entrypoint - sum_duration_vid + video.i_duration;
361             video.i_absolute_end = sum_duration_vid;
362             video.p_key = asset->getAESKeyById( p_dcp->p_key_list, asset->getKeyId() );
363             p_dcp->video_reels.push_back(video);
364             msg_Dbg( this->p_demux, "Video Track: %s",asset->getPath().c_str());
365             msg_Dbg( this->p_demux, "Entry point: %i",asset->getEntryPoint());
366         }
367         /* Get audio */
368         asset = reel->getTrack(TRACK_SOUND);
369         if (asset != NULL)
370         {
371             /*if (!p_dcp->audio_reels.empty())
372             {
373                 sum_duration_aud = 0;
374                 for (int i = 0; i != p_dcp->audio_reels.size(); ++i)
375                 {
376                     sum_duration_aud += p_dcp->audio_reels(i).i_duration;
377                 }
378             }*/
379             sum_duration_aud += asset->getDuration();
380             audio.filename = p_dcp->path + asset->getPath();
381             audio.i_entrypoint = asset->getEntryPoint();
382             audio.i_duration = asset->getDuration();
383             audio.i_correction = audio.i_entrypoint - sum_duration_aud + audio.i_duration;
384             audio.i_absolute_end = sum_duration_aud;
385             audio.p_key = asset->getAESKeyById( p_dcp->p_key_list, asset->getKeyId() );
386             p_dcp->audio_reels.push_back(audio);
387             msg_Dbg( this->p_demux, "Audio Track: %s",asset->getPath().c_str());
388             msg_Dbg( this->p_demux, "Entry point: %i",asset->getEntryPoint());
389         }
390     }
391     /* free memory */
392     this->CloseXml();
393     return VLC_SUCCESS;
394 }
395
396
397
398 /*
399  * Asset Class
400  */
401 Asset::~Asset() {}
402
403 int Asset::Parse( xml_reader_t *p_xmlReader, string p_node, int p_type)
404 {
405     string node;
406     int type;
407     string s_value;
408     const string s_root_node = "Asset";
409
410     if (p_type != XML_READER_STARTELEM)
411         return -1;
412     if( p_node != s_root_node)
413         return -1;
414     /* loop on Assets Node */
415     while( ( type = XmlFile::ReadNextNode( this->p_demux, p_xmlReader, node ) ) > 0 ) {
416         switch (type) {
417             case XML_READER_STARTELEM:
418                 {
419                     AssetTag_t _tag = ASSET_UNKNOWN;
420                     for(AssetTag_t i = ASSET_ID; i <= ASSET_ORIGINAL_FILENAME; i = AssetTag_t(i+1)) {
421                         if( node == g_asset_names[i-1]) {
422                             _tag = i;
423                             switch(_tag) {
424                                 /* Case of complex nodes */
425                                 case ASSET_PACKING_LIST:
426                                     /* case of <PackinkList/> tag, bur not compliant with SMPTE-429-9 2007*/
427                                     if (xml_ReaderIsEmptyElement( p_xmlReader))
428                                         this->b_is_packing_list = true;
429                                     else if ( XmlFile::ReadEndNode( this->p_demux, p_xmlReader, node, type, s_value ) )
430                                         return -1;
431                                     if ( s_value == "true" )
432                                         this->b_is_packing_list = true;
433                                     break;
434                                 case ASSET_CHUNK_LIST:
435                                     if ( this->parseChunkList(p_xmlReader, node, type ) )
436                                         return -1;
437                                     this->s_path = this->chunk_vec[0].getPath();
438                                     break;
439                                 case ASSET_ID:
440                                     if ( XmlFile::ReadEndNode( this->p_demux, p_xmlReader, node, type, s_value ) )
441                                         return -1;
442                                     this->s_id = s_value;
443                                     break;
444                                 case ASSET_ANNOTATION_TEXT:
445                                     if ( XmlFile::ReadEndNode( this->p_demux, p_xmlReader, node, type, s_value ) )
446                                         return -1;
447                                     this->s_annotation = s_value;
448                                     break;
449                                 case ASSET_ORIGINAL_FILENAME:
450                                 case ASSET_HASH:
451                                 case ASSET_TYPE:
452                                 case ASSET_SIZE:
453                                     /* Asset tags not in AssetMap */
454                                     break;
455                                 default:
456                                     msg_Warn(this->p_demux, "Unknow ASSET_TAG: %i", _tag );
457                                     break;
458                             }
459                             /* break the for loop as a tag is found*/
460                             break;
461                         }
462                     }
463                     if( _tag == ASSET_UNKNOWN )
464                         return -1;
465                     break;
466                 }
467             case XML_READER_TEXT:
468                 return -1;
469             case XML_READER_ENDELEM:
470                 if ( node != s_root_node) {
471                     msg_Err(this->p_demux,
472                             "Something goes wrong in Asset parsing on Assetmap (node %s)", node.c_str());
473                     return -1;
474                 } else {
475                     /*Check Presence of Id and Chunklist */
476                     if ( this->s_id.empty() ) {
477                         msg_Err(this->p_demux, " No Id element found in Asset");
478                         return -1;
479                     }
480                     if ( this->s_path.empty() ) {
481                         msg_Err(this->p_demux, " No path element found in Asset");
482                         return -1;
483                     }
484                     return 0;
485                 }
486                 break;
487         }
488     }
489     return -1;
490 }
491
492
493
494 int Asset::ParsePKL( xml_reader_t *p_xmlReader)
495 {
496     string node;
497     int type;
498     string s_value;
499     const string s_root_node = "Asset";
500
501     while( ( type = XmlFile::ReadNextNode( this->p_demux, p_xmlReader, node ) ) > 0 ) {
502         switch (type) {
503             case XML_READER_STARTELEM:
504                 {
505                     AssetTag_t _tag = ASSET_UNKNOWN;
506                     for(AssetTag_t i = ASSET_ID; i <= ASSET_ORIGINAL_FILENAME; i = AssetTag_t(i+1)) {
507                         if( node == g_asset_names[i-1]) {
508                             _tag = i;
509                             switch(_tag) {
510                                 case ASSET_ANNOTATION_TEXT:
511                                     if ( XmlFile::ReadEndNode( this->p_demux, p_xmlReader, node, type, s_value ) )
512                                         return -1;
513                                     if ( this->s_annotation.empty() )
514                                         this->s_annotation = s_value;
515                                     else
516                                         this->s_annotation = this->s_annotation + "--" + s_value;
517                                     break;
518                                 case ASSET_HASH:
519                                     if ( XmlFile::ReadEndNode( this->p_demux, p_xmlReader, node, type, s_value ) )
520                                         return -1;
521                                     this->s_hash = s_value;
522                                     break;
523                                 case ASSET_SIZE:
524                                     if ( XmlFile::ReadEndNode( this->p_demux, p_xmlReader, node, type, s_value ) )
525                                         return -1;
526                                     this->ui_size = atol(s_value.c_str());
527                                     break;
528                                 case ASSET_TYPE:
529                                     if ( XmlFile::ReadEndNode( this->p_demux, p_xmlReader, node, type, s_value ) )
530                                         return -1;
531                                     this->s_type = s_value;
532                                     break;
533                                 case ASSET_ORIGINAL_FILENAME:
534                                     if ( XmlFile::ReadEndNode( this->p_demux, p_xmlReader, node, type, s_value ) )
535                                         return -1;
536                                     this->s_original_filename = s_value;
537                                     break;
538                                 case ASSET_ID: /* already verified */
539                                 case ASSET_PACKING_LIST:
540                                 case ASSET_CHUNK_LIST:
541                                     /* Asset tags not in PKL */
542                                     break;
543                                 default:
544                                     msg_Warn(this->p_demux, "Unknow ASSET_TAG: %i", _tag );
545                                     break;
546                             }
547                             /* break the for loop as a tag is found*/
548                             break;
549                         }
550                     }
551                     if( _tag == ASSET_UNKNOWN )
552                         return -1;
553                 break;
554             }
555             case XML_READER_TEXT:
556                 return -1;
557             case XML_READER_ENDELEM:
558                 if ( node != s_root_node) {
559                     msg_Err(this->p_demux,
560                             "Something goes wrong in Asset parsing on PKL (node %s)", node.c_str());
561                     return -1;
562                 } else {
563                     /* Verify that mandatory attributes are filled */
564                     if (this->s_hash.empty()) {
565                         msg_Err(this->p_demux,"Asset Hash tag invalid");
566                         return -1;
567                     }
568                     if (this->ui_size == 0) {
569                         msg_Err(this->p_demux,"Asset Size tag invalid");
570                         return -1;
571                     }
572                     if (this->s_type.empty()) {
573                         msg_Err(this->p_demux,"Asset Type tag invalid");
574                         return -1;
575                     }
576                     return 0;
577                 }
578                 break;
579         }
580
581     }
582
583     return -1;
584 }
585
586 void Asset::Dump()
587 {
588     msg_Dbg(this->p_demux,"Id              = %s", this->s_id.c_str());
589     msg_Dbg(this->p_demux,"Path            = %s", this->s_path.c_str());
590     msg_Dbg(this->p_demux,"Is PKL          = %s", this->b_is_packing_list ? "True" : "False");
591     msg_Dbg(this->p_demux,"Hash            = %s", this->s_hash.c_str());
592     msg_Dbg(this->p_demux,"Size            = %i", this->ui_size);
593     msg_Dbg(this->p_demux,"Type            = %s", this->s_type.c_str());
594     msg_Dbg(this->p_demux,"OrignalFileName = %s", this->s_original_filename.c_str());
595     msg_Dbg(this->p_demux,"AnnotationText  = %s", this->s_annotation.c_str());
596 }
597
598 int Asset::parseChunkList( xml_reader_t *p_xmlReader, string p_node, int p_type)
599 {
600     string node;
601     int type;
602     string s_value;
603     std::vector<Chunk> chunk_vec;
604
605     if (p_type != XML_READER_STARTELEM)
606         return -1;
607     if( p_node != "ChunkList" )
608         return -1;
609     /* loop on Assets Node */
610     while( ( type = XmlFile::ReadNextNode( this->p_demux, p_xmlReader, node ) ) > 0 ) {
611          switch (type) {
612             case XML_READER_STARTELEM:
613                 {
614                     Chunk chunk(this->p_demux);
615                     if (node != "Chunk" )
616                         return -1;
617                     if ( chunk.Parse(p_xmlReader, node, type) )
618                         return -1;
619                     chunk_vec.push_back(chunk);
620                     break;
621                 }
622             case XML_READER_ENDELEM:
623                 if ( node == p_node) {
624                     if (chunk_vec.size() != 1 ) {
625                         msg_Err(this->p_demux, "chunklist of size greater than one not supported");
626                         return -1;
627                         }
628                     this->chunk_vec = chunk_vec;
629                     return 0;
630                 }
631                 break;
632         }
633     }
634     return -1;
635 }
636
637 AESKey * Asset::getAESKeyById( AESKeyList* p_key_list, const string s_id )
638 {
639     /* return NULL if DCP is not encrypted */
640     if( !p_key_list || s_id.empty() )
641         return NULL;
642
643     for( AESKeyList::iterator index = p_key_list->begin(); index != p_key_list->end(); ++index )
644         if( (*index)->getKeyId() == s_id )
645             return *index;
646
647     return NULL;
648 }
649
650
651 int AssetMap::ParseAssetList (xml_reader_t *p_xmlReader, const string p_node, int p_type)
652 {
653     string node;
654     int type;
655     Asset *asset;
656
657     if (p_type != XML_READER_STARTELEM)
658         return -1;
659     if( p_node != "AssetList" )
660         return -1;
661     /* loop on AssetList nodes */
662     while( ( type = XmlFile::ReadNextNode( this->p_demux, p_xmlReader, node ) ) > 0 ) {
663         switch (type) {
664             case XML_READER_STARTELEM:
665                 if (node != "Asset" )
666                     return -1;
667                 asset = new (nothrow) Asset(this->p_demux);
668                 if ( unlikely(asset == NULL) )
669                     return -1;
670                 if (asset->Parse(p_xmlReader, node, type)){
671                     delete asset;
672                     return -1;
673                 }
674                 p_dcp->p_asset_list->push_back(asset);
675                 break;
676
677             case XML_READER_ENDELEM:
678                 if (node == p_node )
679                     return 0;
680                 break;
681             default:
682             case XML_READER_TEXT:
683                 msg_Err(this->p_demux, "Error parsing AssetList in AssetMap");
684                 return -1;
685         }
686     }
687     return -1;
688 }
689
690 Asset * AssetMap::getAssetById(AssetList *asset_list, const string p_id)
691 {
692     AssetList::iterator index = asset_list->begin() ;
693     for (index = asset_list->begin(); index != asset_list->end(); ++index)
694         if ((*index)->getId() == p_id )
695             return *index;
696     return NULL;
697 }
698
699 /*
700  * XmlFile Class
701  */
702 XmlFile::~XmlFile() {}
703
704 int XmlFile::OpenXml()
705 {
706     char *psz_uri;
707
708     this->p_xml = xml_Create( this->p_demux );
709     if (! this->p_xml) {
710         return -1;
711     }
712     psz_uri = vlc_path2uri( this->s_path.c_str(), "file" );
713     this->p_stream = stream_UrlNew(this->p_demux, psz_uri );
714     free(psz_uri);
715     if( ! this->p_stream ) {
716         xml_Delete(this->p_xml );
717         return -1;
718     }
719
720     this->p_xmlReader = xml_ReaderCreate( this->p_xml, this->p_stream);
721     if( ! this->p_xmlReader ) {
722         stream_Delete( this->p_stream );
723         xml_Delete(this->p_xml );
724         return -1;
725     }
726     return 0;
727 }
728
729 int XmlFile::ReadNextNode( demux_t *p_demux, xml_reader_t *p_xmlReader, string& p_node )
730 {
731     string s_node;
732     const char * c_node;
733     int i;
734     size_t ui_pos;
735
736     i = xml_ReaderNextNode( p_xmlReader, &c_node );
737
738     /* remove namespaces, if there are any */
739     s_node = c_node;
740     ui_pos = s_node.find( ":" );
741     if( ( i == XML_READER_STARTELEM || i == XML_READER_ENDELEM ) && ( ui_pos != string::npos ) )
742     {
743         try
744         {
745             p_node = s_node.substr( ui_pos + 1 );
746         }
747         catch( ... )
748         {
749             msg_Err( p_demux, "error while handling string" );
750             return -1;
751         }
752     }
753     else
754         p_node = s_node;
755
756     return i;
757 }
758
759 int XmlFile::ReadEndNode( demux_t *p_demux, xml_reader_t *p_xmlReader, string p_node, int p_type, string &s_value)
760 {
761     string node;
762
763     if ( xml_ReaderIsEmptyElement( p_xmlReader) )
764             return 0;
765
766     if (p_type != XML_READER_STARTELEM)
767         return -1;
768
769     if( XmlFile::ReadNextNode( p_demux, p_xmlReader, node ) == XML_READER_TEXT )
770     {
771         s_value = node;
772         if( ( XmlFile::ReadNextNode( p_demux, p_xmlReader, node ) == XML_READER_ENDELEM ) &&
773                 node == p_node)
774             return 0;
775     }
776     return -1;
777 }
778 /*
779  * Reads first node in XML and returns
780  * 1 if XML is CPL,
781  * 0 if not
782  * -1 on error
783  */
784 int XmlFile::isCPL()
785 {
786     string node;
787     int type, ret = 0;
788
789     if( this->OpenXml() )
790     {
791         msg_Err( this->p_demux, "Failed to open CPL XML file" );
792         return -1;
793     }
794
795     /* read 1st node  and verify that is a CPL */
796     type = XmlFile::ReadNextNode( this->p_demux, p_xmlReader, node );
797     if( type == -1 ) /* error */
798         ret = -1;
799     if( type == XML_READER_STARTELEM &&  node == "CompositionPlaylist" )
800         ret = 1;
801
802     /* close xml */
803     this->CloseXml();
804     return ret;
805 }
806
807 void XmlFile::CloseXml() {
808     if( this->p_stream )
809         stream_Delete( this->p_stream );
810     if( this->p_xmlReader )
811         xml_ReaderDelete( this->p_xmlReader );
812     if( this->p_xml )
813         xml_Delete( this->p_xml );
814
815 }
816
817 /*
818  * PKL Class
819  */
820
821 PKL::~PKL() {
822     vlc_delete_all(vec_cpl);
823 }
824
825 int PKL::Parse()
826 {
827     string node;
828     int type;
829     string s_value;
830     const string s_root_node = "PackingList";
831
832     static const string names[] = {
833         "Id",
834         "IssueDate",
835         "Issuer",
836         "Creator",
837         "AssetList",
838         "AnnotationText",
839         "IconId",
840         "GroupId",
841         "Signer",
842         "Signature"
843     };
844
845     if (this->OpenXml())
846         return -1;
847
848     /* read 1st node  and verify that is a PKL*/
849     if ( ! ( ( XML_READER_STARTELEM == XmlFile::ReadNextNode( this->p_demux, this->p_xmlReader, node ) ) &&
850                 (node == s_root_node) ) ) {
851         msg_Err( this->p_demux, "Not a valid XML Packing List");
852         goto error;
853     }
854     while( ( type = XmlFile::ReadNextNode( this->p_demux, this->p_xmlReader, node ) ) ) {
855         switch (type) {
856             case XML_READER_STARTELEM: {
857                 PKLTag_t _tag = PKL_UNKNOWN;
858                 for(PKLTag_t i = PKL_ID; i <= PKL_SIGNATURE; i = PKLTag_t(i+1)) {
859                     if( node == names[i-1]) {
860                         _tag = i;
861                         switch (_tag) {
862                             /* case for parsing non terminal nodes */
863                             case PKL_ASSET_LIST:
864                                 if ( this->ParseAssetList(node, type) )
865                                     goto error;
866                                 break;
867                             case PKL_SIGNER:
868                                 if ( this->ParseSigner(node, type) )
869                                     goto error;
870                                 break;
871                             case PKL_SIGNATURE:
872                                 if ( this->ParseSignature(node, type) )
873                                     goto error;
874                                 break;
875                             /* Parse simple/end nodes */
876                             case PKL_ID:
877                                 if ( XmlFile::ReadEndNode( this->p_demux, p_xmlReader, node, type, s_value ) )
878                                     goto error;
879                                 this->s_id = s_value;
880                                 break;
881                             case PKL_ISSUE_DATE:
882                                 if ( XmlFile::ReadEndNode( this->p_demux, p_xmlReader, node, type, s_value ) )
883                                     goto error;
884                                 this->s_issue_date = s_value;
885                                 break;
886                             case PKL_ISSUER:
887                                 if ( XmlFile::ReadEndNode( this->p_demux, p_xmlReader, node, type, s_value ) )
888                                     goto error;
889                                 this->s_issuer = s_value;
890                                 break;
891                             case PKL_CREATOR:
892                                 if ( XmlFile::ReadEndNode( this->p_demux, p_xmlReader, node, type, s_value ) )
893                                     goto error;
894                                 this->s_creator = s_value;
895                                 break;
896                             case PKL_ANNOTATION_TEXT:
897                                 if ( XmlFile::ReadEndNode( this->p_demux, p_xmlReader, node, type, s_value ) )
898                                     goto error;
899                                 this->s_annotation = s_value;
900                                 break;
901                             case PKL_ICON_ID:
902                                 if ( XmlFile::ReadEndNode( this->p_demux, p_xmlReader, node, type, s_value ) )
903                                     goto error;
904                                 this->s_icon_id = s_value;
905                                 break;
906                             case PKL_GROUP_ID:
907                                 if ( XmlFile::ReadEndNode( this->p_demux, p_xmlReader, node, type, s_value ) )
908                                     goto error;
909                                 this->s_group_id = s_value;
910                                 break;
911                             default:
912                                 msg_Warn(this->p_demux, "Unknow PKG_TAG: %i", _tag );
913                                 break;
914                         }
915                         /* break the for loop as a tag is found*/
916                         break;
917                     }
918                 }
919                 if( _tag == PKL_UNKNOWN )
920                     goto error;
921                 break;
922             }
923             case XML_READER_TEXT:
924             case -1:
925                 goto error;
926             case XML_READER_ENDELEM:
927                 if ( node != s_root_node) {
928                     msg_Err(this->p_demux,
929                         "Something goes wrong in PKL parsing (node %s)", node.c_str());
930                     goto error;
931                 }
932                 break;
933         }
934     }
935     /* TODO verify presence of mandatory fields*/
936
937     /* Close PKL XML*/
938     this->CloseXml();
939     return 0;
940 error:
941     msg_Err( this->p_demux, "PKL parsing failed");
942     this->CloseXml();
943     return -1;
944 }
945
946 int PKL::FindCPLs()
947 {
948     if ( this->vec_cpl.size() != 0 ) {
949         msg_Err(this->p_demux, "CPLs already checked");
950         return -1;
951     }
952
953     for (AssetList::iterator index = this->asset_list->begin();
954             index != this->asset_list->end(); ++index) {
955         Asset *asset = *index;
956         if ( asset->getType().find("text/xml") == string::npos) {
957             /* not an xml file */
958             continue;
959         }
960
961         CPL *cpl = new (nothrow) CPL(this->p_demux,
962                       this->s_dcp_path + asset->getPath(),
963                       this->asset_list);
964         if ( unlikely(cpl == NULL) )
965                     return -1;
966         switch( cpl->isCPL() )
967         {
968             case 1:
969                 /* CPL Found */
970                 this->vec_cpl.push_back(cpl);
971                 break;
972             case -1:
973                 /* error */
974                 return -1;
975             case 0:
976             default:
977                 delete cpl;
978                 break;
979         }
980     }
981     return this->vec_cpl.size();
982 }
983
984
985 int PKL::ParseAssetList(string p_node, int p_type) {
986     string node;
987     int type;
988
989     if (p_type != XML_READER_STARTELEM)
990         return -1;
991     if( p_node != "AssetList")
992         return -1;
993     while( ( type = XmlFile::ReadNextNode( this->p_demux, this->p_xmlReader, node ) ) ) {
994         switch (type) {
995             case XML_READER_STARTELEM:
996                 if( node =="Asset") {
997                     if ( this->ParseAsset(node, type) )
998                         return -1;
999                 } else
1000                     return -1;
1001                 break;
1002             case XML_READER_ENDELEM:
1003                 if ( node == p_node) {
1004                     /* parse of chunklist finished */
1005                     goto end;
1006                 }
1007                 break;
1008             case -1:
1009                 /* error */
1010                 return -1;
1011         }
1012     }
1013 end:
1014     return 0;
1015 }
1016
1017 int PKL::ParseAsset(string p_node, int p_type) {
1018     string node;
1019     int type;
1020     string s_value;
1021     Asset *asset = NULL;
1022
1023     if (p_type != XML_READER_STARTELEM)
1024         return -1;
1025     if( p_node != "Asset")
1026         return -1;
1027
1028     /* 1st node shall be Id" */
1029     if( ( type = XmlFile::ReadNextNode( this->p_demux, this->p_xmlReader, node ) ) )
1030         if ( ! ( ( type == XML_READER_STARTELEM ) && ( node == "Id" ) ) || type == -1 )
1031             return -1;
1032     if( ( type = XmlFile::ReadNextNode( this->p_demux, this->p_xmlReader, node ) ) != -1 )
1033     {
1034         if( type == XML_READER_TEXT )
1035         {
1036             s_value = node;
1037             if (unlikely(node.empty()))
1038                 return -1;
1039         }
1040     }
1041     else
1042         return -1;
1043
1044     if( ( type = XmlFile::ReadNextNode( this->p_demux, this->p_xmlReader, node ) ) != -1 )
1045     {
1046         if( type == XML_READER_ENDELEM )
1047         {
1048             asset = AssetMap::getAssetById(this->asset_list, s_value);
1049             if (asset  == NULL)
1050                 return -1;
1051         }
1052     }
1053     else
1054         return -1;
1055
1056      if (asset == NULL)
1057         return -1;
1058      if ( asset->ParsePKL(this->p_xmlReader) )
1059         return -1;
1060     return 0;
1061 }
1062
1063 int PKL::ParseSigner(string p_node, int p_type)
1064 {
1065     string node;
1066     int type;
1067
1068     if (p_type != XML_READER_STARTELEM)
1069         return -1;
1070     if( p_node != "Signer")
1071         return -1;
1072
1073     while( ( type = XmlFile::ReadNextNode( this->p_demux, this->p_xmlReader, node ) ) > 0 ) {
1074         /* TODO not implemented. Just parse until end of Signer node */
1075             if ((node == p_node) && (type = XML_READER_ENDELEM))
1076                 return 0;
1077     }
1078
1079     msg_Err(this->p_demux, "Parse of Signer finished bad");
1080     return -1;
1081 }
1082
1083 int PKL::ParseSignature(string p_node, int p_type)
1084 {
1085     string node;
1086     int type;
1087
1088     if (p_type != XML_READER_STARTELEM)
1089         return -1;
1090     if( p_node != "Signature")
1091         return -1;
1092
1093     while( ( type = XmlFile::ReadNextNode( this->p_demux, this->p_xmlReader, node ) ) > 0 ) {
1094         /* TODO not implemented. Just parse until end of Signature node */
1095             if ((node == p_node) && (type = XML_READER_ENDELEM))
1096                 return 0;
1097     }
1098     msg_Err(this->p_demux, "Parse of Signature finished bad");
1099     return -1;
1100 }
1101
1102 /*
1103  * Reel Class
1104  */
1105 int Reel::Parse(string p_node, int p_type) {
1106     string node;
1107     int type;
1108     string s_value;
1109
1110     if (p_type != XML_READER_STARTELEM)
1111         return -1;
1112     if( p_node != "Reel")
1113         return -1;
1114
1115     while( ( type = XmlFile::ReadNextNode( this->p_demux, this->p_xmlReader, node ) ) > 0 ) {
1116         switch (type) {
1117             case XML_READER_STARTELEM:
1118                 if (node =="Id") {
1119                     if ( XmlFile::ReadEndNode( this->p_demux, this->p_xmlReader, node, type, s_value ) )
1120                         return -1;
1121                     this->s_id = s_value;
1122                 } else if (node == "AnnotationText") {
1123                     if ( XmlFile::ReadEndNode( this->p_demux, this->p_xmlReader, node, type, s_value ) )
1124                         return -1;
1125                     this->s_annotation = s_value;
1126                 } else if ( node =="AssetList" ) {
1127                     if (this->ParseAssetList(node, type))
1128                         return -1;
1129                 } else {
1130                     /* unknown tag */
1131                     msg_Err(this->p_demux, "Reel::Parse, unknown tag:%s", node.c_str());
1132                     return -1;
1133                 }
1134                 break;
1135             case XML_READER_TEXT:
1136                 /* Error */
1137                 msg_Err(this->p_demux, "Reel parsing error");
1138                 return -1;
1139             case XML_READER_ENDELEM:
1140                 /* verify correctness of end node */
1141                 if ( node == p_node) {
1142                     /* TODO : verify Reel id */
1143                     return 0;
1144                 }
1145                 break;
1146         }
1147     }
1148     return -1;
1149 }
1150
1151
1152 Asset * Reel::getTrack(TrackType_t e_track)
1153 {
1154     switch (e_track) {
1155         case TRACK_PICTURE:
1156             return this->p_picture_track;
1157         case TRACK_SOUND:
1158             return this->p_sound_track;
1159         case TRACK_SUBTITLE:
1160             return this->p_subtitle_track;
1161         case TRACK_UNKNOWN:
1162         default:
1163             break;
1164     }
1165     return NULL;
1166 }
1167
1168 int Reel::ParseAssetList(string p_node, int p_type) {
1169     string node;
1170     int type;
1171     string s_value;
1172
1173     if (p_type != XML_READER_STARTELEM)
1174         return -1;
1175     if( p_node != "AssetList")
1176         return -1;
1177
1178     while( ( type = XmlFile::ReadNextNode( this->p_demux, this->p_xmlReader, node ) ) > 0 )  {
1179         switch (type) {
1180             case XML_READER_STARTELEM:
1181                 if (node =="MainPicture") {
1182                     if ( this->ParseAsset(node, type, TRACK_PICTURE) )
1183                         return -1;
1184                 } else if (node =="MainSound") {
1185                     if ( this->ParseAsset(node, type, TRACK_SOUND) )
1186                         return -1;
1187                 } else if (node =="MainSubtitle") {
1188                     if ( this->ParseAsset(node, type, TRACK_SUBTITLE) )
1189                         return -1;
1190                 } else {
1191                     /* unknown tag */
1192                     msg_Err(this->p_demux, "Reel::ParseAssetList, unknown tag:%s", node.c_str());
1193                     return -1;
1194                 }
1195                 break;
1196             case XML_READER_TEXT:
1197                 /* Parsing error */
1198                 msg_Err(this->p_demux, "AssetList parsing error");
1199                 return -1;
1200             case XML_READER_ENDELEM:
1201                 /* verify correctness of end node */
1202                 if ( node == p_node) {
1203                     /* TODO : verify id */
1204                     return 0;
1205                 }
1206                 break;
1207         }
1208     }
1209     return -1;
1210 }
1211
1212 int Reel::ParseAsset(string p_node, int p_type, TrackType_t e_track) {
1213     string node;
1214     int type;
1215     string s_value;
1216     bool b_stop_parse = false;
1217     Asset *asset = NULL;
1218
1219     if (p_type != XML_READER_STARTELEM)
1220         return -1;
1221
1222     /* 1st node shall be Id */
1223     if( ( type = XmlFile::ReadNextNode( this->p_demux, this->p_xmlReader, node ) ) )
1224         if( ! ( ( type == XML_READER_STARTELEM ) && ( node == "Id" ) ) || type == -1 )
1225             return -1;
1226
1227     if ( XmlFile::ReadEndNode( this->p_demux, this->p_xmlReader, node, type, s_value ) )
1228         return -1;
1229
1230     asset = AssetMap::getAssetById(this->p_asset_list, s_value);
1231     if (asset  == NULL)
1232         return -1;
1233
1234     while(  (! b_stop_parse) &&
1235             ( type = XmlFile::ReadNextNode( this->p_demux, this->p_xmlReader, node ) ) ) {
1236         switch (type) {
1237             case XML_READER_STARTELEM:
1238                 if (node =="EditRate") {
1239                     if ( XmlFile::ReadEndNode( this->p_demux, this->p_xmlReader, node, type, s_value ) )
1240                         return -1;
1241                 } else if (node == "AnnotationText") {
1242                     if ( XmlFile::ReadEndNode( this->p_demux, this->p_xmlReader, node, type, s_value ) )
1243                         return -1;
1244                         asset->setAnnotation(s_value);
1245                 } else if (node == "IntrinsicDuration") {
1246                     if ( XmlFile::ReadEndNode( this->p_demux, this->p_xmlReader, node, type, s_value ) )
1247                         return -1;
1248                         asset->setIntrinsicDuration(atoi(s_value.c_str()));
1249                 } else if (node == "EntryPoint") {
1250                     if ( XmlFile::ReadEndNode( this->p_demux, this->p_xmlReader, node, type, s_value ) )
1251                         return -1;
1252                         asset->setEntryPoint(atoi(s_value.c_str()));
1253                 } else if (node == "Duration") {
1254                     if ( XmlFile::ReadEndNode( this->p_demux, this->p_xmlReader, node, type, s_value ) )
1255                         return -1;
1256                         asset->setDuration(atoi(s_value.c_str()));
1257                 } else if (node == "KeyId") {
1258                     if ( XmlFile::ReadEndNode( this->p_demux, this->p_xmlReader, node, type, s_value ) )
1259                         return -1;
1260                     asset->setKeyId( s_value );
1261                 } else if (node == "Hash") {
1262                     if ( XmlFile::ReadEndNode( this->p_demux, this->p_xmlReader, node, type, s_value ) )
1263                         return -1;
1264                 } else if (node == "FrameRate") {
1265                     if ( XmlFile::ReadEndNode( this->p_demux, this->p_xmlReader, node, type, s_value ) )
1266                         return -1;
1267                 } else if (node == "ScreenAspectRatio") {
1268                     if ( XmlFile::ReadEndNode( this->p_demux, this->p_xmlReader, node, type, s_value ) )
1269                         return -1;
1270                 } else if (node == "Language") {
1271                     if ( XmlFile::ReadEndNode( this->p_demux, this->p_xmlReader, node, type, s_value ) )
1272                         return -1;
1273                 } else {
1274                     /* unknown tag */
1275                     msg_Err(this->p_demux, "Reel::ParseAsset unknown tag:%s", node.c_str());
1276                     return -1;
1277                 }
1278                 break;
1279             case XML_READER_TEXT:
1280             case -1:
1281                 /* error */
1282                 return -1;
1283                 break;
1284             case XML_READER_ENDELEM:
1285                 /* verify correctness of end node */
1286                 if ( node == p_node) {
1287                     /* TODO : verify id */
1288                     b_stop_parse = true;
1289                 }
1290         }
1291     }
1292     /* store by track */
1293     switch (e_track) {
1294         case TRACK_PICTURE:
1295             this->p_picture_track = asset;
1296             break;
1297         case TRACK_SOUND:
1298             this->p_sound_track = asset;
1299             break;
1300         case TRACK_SUBTITLE:
1301             this->p_subtitle_track = asset;
1302             break;
1303         case TRACK_UNKNOWN:
1304         default:
1305             break;
1306     }
1307     return 0;
1308 }
1309
1310 /*
1311  * CPL Class
1312  */
1313
1314 CPL::~CPL() {
1315     vlc_delete_all(vec_reel);
1316 }
1317
1318 int CPL::Parse()
1319 {
1320     string node;
1321     int type;
1322     string s_value;
1323     const string s_root_node = "CompositionPlaylist";
1324
1325     static const string names[] = {
1326         "Id",
1327         "AnnotationText",
1328         "IconId",
1329         "IssueDate",
1330         "Issuer",
1331         "Creator",
1332         "ContentTitleText",
1333         "ContentKind",
1334         "ContentVersion",
1335         "RatingList",
1336         "ReelList",
1337         "Signer",
1338         "Signature"
1339     };
1340
1341     if (this->OpenXml())
1342         return -1;
1343
1344     /* read 1st node  and verify that is a CPL*/
1345     if( ! ( ( XML_READER_STARTELEM == XmlFile::ReadNextNode( this->p_demux, this->p_xmlReader, node ) ) &&
1346                 (node == s_root_node) ) ) {
1347         msg_Err( this->p_demux, "Not a valid XML Packing List");
1348         goto error;
1349     }
1350
1351     while( ( type = XmlFile::ReadNextNode( this->p_demux, this->p_xmlReader, node ) ) ) {
1352         switch (type) {
1353             case XML_READER_STARTELEM: {
1354                 CPLTag_t _tag = CPL_UNKNOWN;
1355                 for(CPLTag_t i = CPL_ID; i <= CPL_SIGNATURE; i = CPLTag_t(i+1)) {
1356                     if( node == names[i-1]) {
1357                         _tag = i;
1358                         switch (_tag) {
1359                             /* case for parsing non terminal nodes */
1360                             case CPL_REEL_LIST:
1361                                 if ( this->ParseReelList(node, type) )
1362                                     goto error;
1363                                 break;
1364                             case CPL_CONTENT_VERSION:
1365                             case CPL_SIGNER:
1366                             case CPL_SIGNATURE:
1367                             case CPL_RATING_LIST:
1368                                 if ( this->DummyParse(node,type) )
1369                                     goto error;
1370                                 break;
1371                                 /* Parse simple/end nodes */
1372                             case CPL_ID:
1373                                 if ( XmlFile::ReadEndNode( this->p_demux, p_xmlReader, node, type, s_value ) )
1374                                     goto error;
1375                                 this->s_id = s_value;
1376                                 break;
1377                             case CPL_ANNOTATION_TEXT:
1378                                 if ( XmlFile::ReadEndNode( this->p_demux, p_xmlReader, node, type, s_value ) )
1379                                     goto error;
1380                                 this->s_annotation = s_value;
1381                                 break;
1382                             case CPL_ICON_ID:
1383                                 if ( XmlFile::ReadEndNode( this->p_demux, p_xmlReader, node, type, s_value ) )
1384                                     goto error;
1385                                 this->s_icon_id = s_value;
1386                                 break;
1387                             case CPL_ISSUE_DATE:
1388                                 if ( XmlFile::ReadEndNode( this->p_demux, p_xmlReader, node, type, s_value ) )
1389                                     goto error;
1390                                 this->s_issue_date= s_value;
1391                                 break;
1392                             case CPL_ISSUER:
1393                                 if ( XmlFile::ReadEndNode( this->p_demux, p_xmlReader, node, type, s_value ) )
1394                                     goto error;
1395                                 this->s_issuer = s_value;
1396                                 break;
1397                             case CPL_CREATOR:
1398                                 if ( XmlFile::ReadEndNode( this->p_demux, p_xmlReader, node, type, s_value ) )
1399                                     goto error;
1400                                 this->s_creator = s_value;
1401                                 break;
1402                             case CPL_CONTENT_TITLE:
1403                                 if ( XmlFile::ReadEndNode( this->p_demux, p_xmlReader, node, type, s_value ) )
1404                                     goto error;
1405                                 this->s_content_title = s_value;
1406                                 break;
1407                             case CPL_CONTENT_KIND:
1408                                 if ( XmlFile::ReadEndNode( this->p_demux, p_xmlReader, node, type, s_value ) )
1409                                     goto error;
1410                                 this->s_content_kind = s_value;
1411                                 break;
1412                             default:
1413                                 msg_Warn(this->p_demux, "Unknow CPL_TAG: %i", _tag );
1414                                 break;
1415                         }
1416
1417                         /* break the for loop as a tag is found*/
1418                         break;
1419                     }
1420                 }
1421                 if( _tag == CPL_UNKNOWN )
1422                     goto error;
1423                 break;
1424             }
1425             case XML_READER_TEXT:
1426             case -1:
1427                goto error;
1428             case XML_READER_ENDELEM:
1429                if ( node != s_root_node) {
1430                    msg_Err(this->p_demux,
1431                            "Something goes wrong in CKL parsing (node %s)", node.c_str());
1432                    goto error;
1433                }
1434                break;
1435         }
1436     }
1437
1438     /* TODO verify presence of mandatory fields*/
1439
1440     /* Close CPL XML*/
1441     this->CloseXml();
1442     return 0;
1443 error:
1444     this->CloseXml();
1445     return -1;
1446 }
1447
1448 int CPL::ParseReelList(string p_node, int p_type) {
1449     string node;
1450     int type;
1451
1452     if (p_type != XML_READER_STARTELEM)
1453         return -1;
1454     if( p_node != "ReelList")
1455         return -1;
1456     while( ( type = XmlFile::ReadNextNode( this->p_demux, this->p_xmlReader, node ) ) > 0 ) {
1457         switch (type) {
1458             case XML_READER_STARTELEM: {
1459                 Reel *p_reel = new (nothrow) Reel( this->p_demux, this->asset_list, this->p_xmlReader);
1460                 if ( unlikely(p_reel == NULL) )
1461                     return -1;
1462                 if( node =="Reel") {
1463                     if ( p_reel->Parse(node, type) ) {
1464                         delete p_reel;
1465                         return -1;
1466                     }
1467                 } else {
1468                     delete p_reel;
1469                     return -1;
1470                 }
1471                 this->vec_reel.push_back(p_reel);
1472
1473                 break;
1474             }
1475             case XML_READER_TEXT:
1476                 /* impossible */
1477                 break;
1478             case XML_READER_ENDELEM:
1479                 if ( node == p_node)
1480                     return 0;
1481                 break;
1482             }
1483     }
1484     return -1;
1485 }
1486
1487
1488 int CPL::DummyParse(string p_node, int p_type)
1489 {
1490     string node;
1491     int type;
1492
1493     if (p_type != XML_READER_STARTELEM)
1494         return -1;
1495
1496     if (xml_ReaderIsEmptyElement( this->p_xmlReader))
1497         return 0;
1498
1499     while( ( type = XmlFile::ReadNextNode( this->p_demux, this->p_xmlReader, node ) ) > 0 ) {
1500         /* TODO not implemented. Just pase until end of input node */
1501         if ((node == p_node) && (type = XML_READER_ENDELEM))
1502             return 0;
1503     }
1504
1505     return -1;
1506 }