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