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