File Coverage

blib/lib/Win32/Exe/Manifest/Parser.pm
Criterion Covered Total %
statement 7 9 77.7
branch n/a
condition n/a
subroutine 3 3 100.0
pod n/a
total 10 12 83.3


line stmt bran cond sub pod time code
1             #########################################################################################
2             # Package Win32::Exe::Manifest::Parser
3             # Description: XML Parser for Manifests
4             # Created Wed Apr 21 07:54:51 2010
5             # SVN Id $Id: Parser.pm 2 2010-11-30 16:40:31Z mark.dootson $
6             # Copyright: Copyright (c) 2010 Mark Dootson
7             # Licence: This program is free software; you can redistribute it
8             # and/or modify it under the same terms as Perl itself
9             #########################################################################################
10              
11             package Win32::Exe::Manifest::Parser;
12              
13             #########################################################################################
14              
15 4     4   23 use strict;
  4         8  
  4         142  
16 4     4   21 use warnings;
  4         9  
  4         135  
17 4     4   3742 use XML::Simple 2.18;
  0            
  0            
18             use base qw( XML::Simple );
19             use Carp;
20              
21             our $VERSION = '0.15';
22              
23             =head1 NAME
24              
25             Win32::Exe::Manifest::Parser - MSWin Application and Assembly manifest handling
26              
27             =head1 VERSION
28              
29             This document describes version 0.15 of Win32::Exe::Manifest::Parser, released
30             November 30, 2010.
31              
32             =head1 DESCRIPTION
33              
34             This is an internal module from the Win32::Exe distribution supporting
35             parsing of application and assembly manifests.
36              
37             =cut
38              
39              
40             our $BASESCHEMA;
41              
42             $XML::Simple::PREFERRED_PARSER = 'XML::Parser';
43              
44             sub new {
45             my $class = shift;
46             my $self = $class->SUPER::new(@_);
47             return $self;
48             }
49              
50             sub get_current_schema { $_[0]->{_w32x_current_schema} || $BASESCHEMA; }
51             sub set_current_schema { $_[0]->{_w32x_current_schema} = $_[1]; }
52              
53             #---------------------------------------------------------------
54             # override XML Simple methods
55             #---------------------------------------------------------------
56              
57             sub sorted_keys {
58             my($self, $name, $hashref) = @_;
59             my @unsorted = (sort keys(%$hashref));
60             my $schema = $self->get_current_schema();
61             my @sorted = sort { _get_key_ordinal($name,$hashref,$a,$schema) <=> _get_key_ordinal($name,$hashref,$b,$schema) } @unsorted;
62            
63             # set indent
64             my ($namenamespace,$lookupname);
65             if($name =~ /:/) {
66             ($namenamespace,$lookupname) = split(/:/, $name, 2);
67             } else {
68             $lookupname = $name;
69             }
70             if($lookupname) {
71             $self->{opt}->{attrindent} = ( $lookupname =~ /^(assemblyIdentity)$/ )
72             ? 1 : 0;
73             } else {
74             $self->{opt}->{attrindent} = 0;
75             }
76             return ( @sorted );
77             }
78              
79             #--------------------------------------------------------------
80             # END XML::Simple overrides
81             #--------------------------------------------------------------
82              
83             sub _get_key_ordinal {
84             my($name,$hashref,$key, $schema) = @_;
85             # some defaults
86             return 1001 if $key eq 'xmlns';
87             return 10000 if $key =~ /^xmlns:.+$/;
88             my ($keynamespace,$lookupkey);
89             if($key =~ /:/) {
90             ($keynamespace,$lookupkey) = split(/:/, $key, 2);
91             } else {
92             $lookupkey = $key;
93             }
94             my ($namenamespace,$lookupname);
95             if($name =~ /:/) {
96             ($namenamespace,$lookupname) = split(/:/, $name, 2);
97             } else {
98             $lookupname = $name;
99             }
100            
101             carp qq(UNKNOWN NAMEKEY NAME $name : $lookupname KEY $key : $lookupkey\n) if (!$lookupname || !$lookupkey);
102            
103             if(ref($hashref->{$key})) {
104             return (exists($schema->{elementtypes}->{$lookupname}->{elements}->{$lookupkey}->{order}))
105             ? $schema->{elementtypes}->{$lookupname}->{elements}->{$lookupkey}->{order}
106             : 9999 ;
107             } else {
108             return (exists($schema->{elementtypes}->{$lookupname}->{attributes}->{$lookupkey}->{order}))
109             ? $schema->{elementtypes}->{$lookupname}->{attributes}->{$lookupkey}->{order}
110             : 9999 ;
111             }
112             }
113              
114             sub get_default_manifest {
115             my $self_or_class = shift;
116             my $defman = q(
117            
118            
119             Perl.Win32.Application
120            
121            
122            
123            
124            
125            
126            
127            
128             );
129             return $defman;
130             }
131              
132              
133             sub validate_manifest_version {
134             return ($_[1] eq '1.0') ? 1 : 0;
135             }
136              
137             sub validate_string {
138             my ($self, $val) = @_;
139             return 1;
140             }
141              
142             sub validate_class_name {
143             my($this, $name) = @_;
144             return ($name =~ /[^A-Za-z0-9\-_\.]/) ? 0 : 1;
145             }
146              
147             sub validate_type {
148             my($this, $type) = @_;
149             return ( $type eq 'win32'); # specification demands lower case
150             }
151              
152             sub validate_public_key {
153             my ($this, $key) = @_;
154             return 1;
155             }
156              
157             sub validate_language {
158             my ($self, $lang) = @_;
159             return 1;
160             }
161              
162             sub validate_architecture {
163             my ($this, $arch) = @_;
164             return 1 if $arch eq '*';
165             # many files seem to uppercase X86 so we'll accept case insensitive data
166             return 1 if $arch =~ /^(x86|msil|ia64|amd64)$/i;
167             return 0;
168             }
169              
170             sub validate_yesno {
171             my ($this, $val) = @_;
172             return ( $val =~ /^(yes|no)$/) ? 1 : 0;
173             }
174              
175             sub validate_truefalse {
176             my ($this, $val) = @_;
177             return ( $val =~ /^(true|false)$/) ? 1 : 0;
178             }
179              
180             sub validate_clsid {
181             my ($this, $clsid) = @_;
182             return ( $clsid =~ /^\{[A-Fa-f0-9]{8}-[A-Fa-f0-9]{4}-[A-Fa-f0-9]{4}-[A-Fa-f0-9]{4}-[A-Fa-f0-9]{12}\}$/ ) ? 1 : 0;
183             }
184              
185             sub validate_int4 {
186             my ($this, $int) = @_;
187             return ( $int =~ /^\d{1,4}$/) ? 1 : 0;
188             }
189              
190             sub validate_int8 {
191             my ($this, $int) = @_;
192             return ( $int =~ /^\d{1,8}$/) ? 1 : 0;
193             }
194              
195             sub validate_flags {
196             my ($this, $flags) = @_;
197             return ( $flags =~ /^(control|hidden|restricted|hasdiskimage)$/i ) ? 1 : 0;
198             }
199              
200             sub validate_level {
201             my ($this, $level) = @_;
202             return ( $level =~ /^(asInvoker|highestAvailable|requireAdministrator)$/ ) ? 1 : 0;
203             }
204              
205             sub validate_hashalg {
206             my ($this, $alg) = @_;
207             return ( $alg =~ /^(SHA1|SHA|MD5|MD4|MD2)$/i ) ? 1 : 0;
208             }
209              
210             sub validate_thread_model {
211             my ($this, $model) = @_;
212             return ( $model =~ /^(Apartment|Free|Both|Neutral)$/i ) ? 1 : 0;
213             }
214              
215             sub validate_hex {
216             my ($this, $hex) = @_;
217             return 1;
218             }
219              
220             sub validate_osid {
221             my ($this, $osid) = @_;
222             return 1 if $osid eq '{e2011457-1546-43c5-a5fe-008deee3d3f0}'; # Windows Vista Compatibility
223             return 1 if $osid eq '{35138b9a-5d96-4fbd-8e2d-a2440225f93a}'; # Windows 7 Compatibility
224             return 0;
225             }
226              
227             sub validate_miscstatus {
228             my ($this, $status) = @_;
229             my @vals = split(/\s*,\s*/, $status);
230             my @allowednames = qw(
231             recomposeonresize onlyiconic insertnotreplace static cantlinkinside canlinkbyole1
232             islinkobject insideout activatewhenvisible renderingisdeviceindependent
233             invisibleatruntime alwaysrun actslikebutton actslikelabel nouiactivate
234             alignable simpleframe setclientsitefirst imemode ignoreativatewhenvisible
235             wantstomenumerge supportsmultilevelundo
236             );
237             my %allowed;
238             @allowed{@allowednames} = ();
239             my $returnval = 1;
240             for (@vals) {
241             $returnval = (exists($allowed{$_})) ? 1 : 0;
242             last if !$returnval;
243             }
244             return $returnval;
245             }
246              
247             $BASESCHEMA = __PACKAGE__->get_default_schema();
248              
249             sub get_default_schema {
250             my $self_or_class = shift;
251             my $schema = {
252             namespace => {
253             'urn:schemas-microsoft-com:compatibility.v1' => 'cmpv1',
254             'urn:schemas-microsoft-com:asm.v1' => 'asmv1',
255             'urn:schemas-microsoft-com:asm.v2' => 'asmv2',
256             'urn:schemas-microsoft-com:asm.v3' => 'asmv3',
257             },
258             nstranslation => {
259             cmpv1 => 'cmpv1',
260             asmv1 => 'asmv1',
261             asmv2 => 'asmv2',
262             asmv3 => 'asmv3',
263             },
264             namespacelookup => {
265             cmpv1 => 'urn:schemas-microsoft-com:compatibility.v1',
266             asmv1 => 'urn:schemas-microsoft-com:asm.v1',
267             asmv2 => 'urn:schemas-microsoft-com:asm.v2',
268             asmv3 => 'urn:schemas-microsoft-com:asm.v3',
269             },
270             attributes => {
271             manifestVersion => 'validate_manifest_version',
272             name => 'validate_class_name',
273             type => 'validate_type',
274             publicKeyToken => 'validate_public_key',
275             language => 'validate_language',
276             processorArchitecture => 'validate_architecture',
277             version => 'validate_string',
278             optional => 'validate_yesno',
279             clsid => 'validate_clsid',
280             description => 'validate_string',
281             threadingModel => 'validate_thread_model',
282             tlbid => 'validate_clsid',
283             progid => 'validate_string',
284             helpdir => 'validate_string',
285             iid => 'validate_clsid',
286             numMethods => 'validate_int4',
287             resourceid => 'validate_string',
288             flags => 'validate_flags',
289             hashalg => 'validate_hashalg',
290             hash => 'validate_hex',
291             proxyStubClsid32 => 'validate_string',
292             baseInterface => 'validate_clsid',
293             versioned => 'validate_yesno',
294             oldVersion => 'validate_string',
295             newVersion => 'validate_string',
296             size => 'validate_int8',
297             runtimeVersion => 'validate_string',
298             Id => 'validate_osid',
299             xmlns => 'validate_string',
300             level => 'validate_level',
301             uiAccess => 'validate_truefalse',
302             miscStatus => 'validate_miscstatus',
303             miscStatusIcon => 'validate_miscstatus',
304             miscStatusContent => 'validate_miscstatus',
305             miscStatusDocprint => 'validate_miscstatus',
306             miscStatusThumbnail => 'validate_miscstatus',
307             },
308             elementtypes => {
309             assembly => {
310             exclusive => 'none',
311             content => { elements => 1, attributes => 1, value => 0 },
312             value_validator => undef,
313             attributes => {
314             xmlns => {
315             required => 1,
316             default => 'urn:schemas-microsoft-com:asm.v1',
317             },
318             manifestVersion => {
319             required => 1,
320             default => '1.0',
321             order => 1002,
322             },
323             },
324             elements => {
325             # files, even from Microsoft, sometimes don't have an assemblyIdentity
326             assemblyIdentity => { min => 0, max => 1, order => 10, },
327             compatibility => { min => 0, max => 1, order => 64, },
328             application => { min => 0, max => 1, order => 66, },
329             description => { min => 0, max => 1, order => 20, },
330             noInherit => { min => 0, max => 1, order => 30, },
331             noInheritable => { min => 0, max => 1, order => 40, },
332             comInterfaceExternalProxyStub => { min => 0, max => 0, order => 50, },
333             dependency => { min => 0, max => 0, order => 60, },
334             file => { min => 0, max => 0, order => 70, },
335             clrClass => { min => 0, max => 0, order => 80, },
336             clrSurrogate => { min => 0, max => 0, order => 90, },
337             trustInfo => { min => 0, max => 1, order => 62, },
338             windowClass => { min => 0, max => 1, order => 150, },
339             },
340             },
341             trustInfo => {
342             exclusive => 'none',
343             content => { elements => 1, attributes => 1, value => 0 },
344             value_validator => undef,
345             attributes => {
346             xmlns => {
347             required => 1,
348             default => 'urn:schemas-microsoft-com:asm.v3',
349             },
350             },
351             elements => {
352             security => { min => 1, max => 1, order => 10 },
353             },
354             },
355             security => {
356             exclusive => 'none',
357             content => { elements => 1, attributes => 0, value => 0 },
358             value_validator => undef,
359             attributes => {
360             },
361             elements => {
362             requestedPrivileges => { min => 1, max => 1, order => 10, },
363             },
364             },
365             requestedPrivileges => {
366             exclusive => 'none',
367             content => { elements => 1, attributes => 0, value => 0 },
368             value_validator => undef,
369             attributes => {
370             },
371             elements => {
372             requestedExecutionLevel => { min => 1, max => 1 , order => 10, },
373             },
374             },
375             requestedExecutionLevel => {
376             exclusive => 'none',
377             content => { elements => 0, attributes => 1, value => 0 },
378             value_validator => undef,
379             attributes => {
380             level => {
381             required => 1,
382             default => 'asInvoker',
383             order => 1002,
384             },
385             uiAccess => {
386             required => 0,
387             default => 'false',
388             order => 1003,
389             },
390             },
391             elements => {
392             },
393             },
394             compatibility => {
395             exclusive => 'application',
396             content => { elements => 1, attributes => 1, value => 0 },
397             value_validator => undef,
398             attributes => {
399             xmlns => {
400             required => 1,
401             default => 'urn:schemas-microsoft-com:compatibility.v1',
402             },
403             },
404             elements => {
405             application => { min => 1, max => 1, order => 10, },
406             },
407             },
408             application => {
409             exclusive => 'none',
410             content => { elements => 1, attributes => 1, value => 0 },
411             value_validator => undef,
412             attributes => {
413             xmlns => {
414             required => 0,
415             default => 'urn:schemas-microsoft-com:asm.v3',
416             },
417             },
418             elements => {
419             supportedOS => { min => 0, max => 0, order => 10 },
420             windowsSettings => { min => 0, max => 0, order => 10 },
421             },
422             },
423             supportedOS => {
424             exclusive => 'none',
425             content => { elements => 0, attributes => 1, value => 0 },
426             value_validator => undef,
427             attributes => {
428             Id => {
429             required => 1,
430             # Windows Vista Compatibility Key
431             default => '{e2011457-1546-43c5-a5fe-008deee3d3f0}',
432             order => 1002,
433             },
434             },
435             elements => {
436             },
437             },
438             clrClass => {
439             exclusive => 'assembly',
440             content => { elements => 1, attributes => 0, value => 0 },
441             value_validator => undef,
442             attributes => {
443             name => {
444             required => 1,
445             default => undef,
446             order => 1002,
447             },
448             clsid => {
449             required => 1,
450             default => undef,
451             order => 1003,
452             },
453             progid => {
454             required => 0,
455             default => undef,
456             order => 1004,
457             },
458             tlbid => {
459             required => 0,
460             default => undef,
461             order => 1005,
462             },
463             description => {
464             required => 0,
465             default => undef,
466             order => 1006,
467             },
468             runtimeVersion => {
469             required => 0,
470             default => undef,
471             order => 1007,
472             },
473             threadingModel => {
474             required => 0,
475             default => undef,
476             order => 1008,
477             },
478             },
479             elements => {
480             progid => { min => 0, max => 0, order => 10 },
481             },
482             },
483             clrSurrogate => {
484             exclusive => 'assembly',
485             content => { elements => 0, attributes => 1, value => 0 },
486             value_validator => undef,
487             attributes => {
488             name => {
489             required => 1,
490             default => undef,
491             order => 1002,
492             },
493             clsid => {
494             required => 1,
495             default => undef,
496             order => 1003,
497             },
498             runtimeVersion => {
499             required => 0,
500             default => undef,
501             order => 1004,
502             },
503             },
504             elements => {
505             },
506             },
507             assemblyIdentity => {
508             exclusive => 'none',
509             content => { elements => 0, attributes => 1, value => 0 },
510             value_validator => undef,
511             attributes => {
512             name => {
513             required => 1,
514             default => undef,
515             order => 1003,
516             },
517             version => {
518             required => 0,
519             default => '0.0.0.0',
520             order => 1004,
521             },
522             type => {
523             required => 0,
524             default => 'win32',
525             order => 1002,
526             },
527             processorArchitecture => {
528             required => 0,
529             default => '*',
530             order => 1006,
531             },
532             publicKeyToken => {
533             required => 0,
534             default => undef,
535             order => 1007,
536             },
537             language => {
538             required => 0,
539             default => undef,
540             order => 1005,
541             },
542             },
543             elements => {
544             },
545             },
546             comInterfaceProxyStub => {
547             exclusive => 'assembly',
548             content => { elements => 0, attributes => 1, value => 0 },
549             value_validator => undef,
550             attributes => {
551             name => {
552             required => 1,
553             default => undef,
554             order => 1003,
555             },
556             iid => {
557             required => 1,
558             default => undef,
559             order => 1002,
560             },
561             tblid => {
562             required => 0,
563             default => undef,
564             order => 1004,
565             },
566             numMethods => {
567             required => 0,
568             default => undef,
569             order => 1006,
570             },
571             proxyStubClsid32 => {
572             required => 0,
573             default => undef,
574             order => 1007,
575             },
576             baseInterface => {
577             required => 0,
578             default => undef,
579             order => 1005,
580             },
581             threadingModel => {
582             required => 0,
583             default => undef,
584             order => 1008,
585             },
586             },
587             elements => {
588             },
589             },
590             description => {
591             exclusive => 'none',
592             content => { elements => 0, attributes => 0, value => 1 },
593             value_validator => 'validate_string',
594             attributes => {
595             },
596             elements => {
597             },
598             },
599             dependency => {
600             exclusive => 'none',
601             content => { elements => 1, attributes => 1, value => 0 },
602             value_validator => undef,
603             attributes => {
604             optional => {
605             required => 0,
606             default => 'no',
607             order => 1002,
608             },
609             },
610             elements => {
611             dependentAssembly => { min => 0, max => 1, order => 10 },
612             }
613             },
614             dependentAssembly => {
615             exclusive => 'none',
616             content => { elements => 1, attributes => 0, value => 0 },
617             value_validator => undef,
618             attributes => {
619             },
620             elements => {
621             assemblyIdentity => { min => 1, max => 1, order => 10 },
622             bindingRedirect => { min => 0, max => 0, order => 20 },
623             },
624             },
625             bindingRedirect => {
626             exclusive => 'application',
627             content => { elements => 0, attributes => 1, value => 0 },
628             value_validator => undef,
629             attributes => {
630             oldVersion => {
631             required => 1,
632             default => undef,
633             order => 1002,
634             },
635             newVersion => {
636             required => 1,
637             default => undef,
638             order => 1003,
639             },
640             },
641             elements => {
642             },
643             },
644             file => {
645             exclusive => 'none',
646             content => { elements => 1, attributes => 1, value => 0 },
647             value_validator => undef,
648             attributes => {
649             name => {
650             required => 1,
651             default => undef,
652             order => 1002,
653             },
654             hash => {
655             required => 0,
656             default => undef,
657             order => 1004,
658             },
659             hashalg => {
660             required => 0,
661             default => undef,
662             order => 1003,
663             },
664             size => {
665             required => 0,
666             default => undef,
667             order => 1005,
668             },
669             },
670             elements => {
671             comClass => { min => 0, max => 0, order => 10, },
672             comInterfaceProxyStub => { min => 0, max => 0, order => 20, },
673             typelib => { min => 0, max => 0, order => 30, },
674             windowClass => { min => 0, max => 0, order => 40, },
675             },
676             },
677             comClass => {
678             exclusive => 'assembly',
679             content => { elements => 1, attributes => 1, value => 0 },
680             value_validator => undef,
681             attributes => {
682             clsid => {
683             required => 1,
684             default => undef,
685             order => 1003,
686             },
687             threadingModel => {
688             required => 0,
689             default => undef,
690             order => 1004,
691             },
692             progid => {
693             required => 0,
694             default => undef,
695             order => 1003,
696             },
697             tlbid => {
698             required => 0,
699             default => undef,
700             order => 1005,
701             },
702             description => {
703             required => 0,
704             default => undef,
705             order => 1002,
706             },
707             miscStatus => {
708             required => 0,
709             default => undef,
710             order => 1006,
711             },
712             miscStatusIcon => {
713             required => 0,
714             default => undef,
715             order => 1007,
716             },
717             miscStatusDocprint => {
718             required => 0,
719             default => undef,
720             order => 1008,
721             },
722             miscStatusContent => {
723             required => 0,
724             default => undef,
725             order => 1009,
726             },
727             musStatusThumbnail => {
728             required => 0,
729             default => undef,
730             order => 1010,
731             },
732             },
733             elements => {
734             progid => { min => 0, max => 0, order => 10, },
735             },
736             },
737             comInterfaceExternalProxyStub => {
738             exclusive => 'assembly',
739             content => { elements => 0, attributes => 1, value => 0 },
740             value_validator => undef,
741             attributes => {
742             name => {
743             required => 1,
744             default => undef,
745             order => 1005,
746             },
747             iid => {
748             required => 1,
749             default => undef,
750             order => 1002,
751             },
752             tblid => {
753             required => 0,
754             default => undef,
755             order => 1006,
756             },
757             numMethods => {
758             required => 0,
759             default => undef,
760             order => 1004,
761             },
762             proxyStubClsid32 => {
763             required => 0,
764             default => undef,
765             order => 1007,
766             },
767             baseInterface => {
768             required => 0,
769             default => undef,
770             order => 1003,
771             },
772             },
773             elements => {
774             },
775             },
776             typelib => {
777             exclusive => 'assembly',
778             content => { elements => 0, attributes => 1, value => 0 },
779             value_validator => undef,
780             attributes => {
781             tblid => {
782             required => 1,
783             default => undef,
784             order => 1002,
785             },
786             version => {
787             required => 1,
788             default => undef,
789             order => 1003,
790             },
791             helpdir => {
792             required => 1,
793             default => '',
794             order => 1004,
795             },
796             resourceid => {
797             required => 0,
798             default => undef,
799             order => 1006,
800             },
801             flags => {
802             required => 0,
803             default => undef,
804             order => 1005,
805             },
806             },
807             elements => {
808             },
809             },
810             windowClass => {
811             exclusive => 'assembly',
812             content => { elements => 0, attributes => 1, value => 1 },
813             value_validator => 'validate_class_name',
814             attributes => {
815             versioned => {
816             required => 1,
817             default => 'yes',
818             order => 1002,
819             },
820             },
821             elements => {
822             },
823             },
824             noInherit => {
825             exclusive => 'application',
826             content => { elements => 0, attributes => 0, value => 0 },
827             value_validator => undef,
828             attributes => {
829             },
830             elements => {
831             },
832             },
833             noInheritable => {
834             exclusive => 'assembly',
835             content => { elements => 0, attributes => 0, value => 0 },
836             value_validator => undef,
837             attributes => {
838             },
839             elements => {
840             },
841             },
842             progid => {
843             exclusive => 'assembly',
844             content => { elements => 0, attributes => 0, value => 1 },
845             value_validator => 'validate_class_name',
846             attributes => {
847             },
848             elements => {
849             },
850             },
851             windowsSettings => {
852             exclusive => 'none',
853             content => { elements => 1, attributes => 1, value => 0 },
854             value_validator => undef,
855             attributes => {
856             xmlns => {
857             required => 1,
858             default => 'http://schemas.microsoft.com/SMI/2005/WindowsSettings',
859             },
860             },
861             elements => {
862             dpiAware => { min => 0, max => 1, order => 10 },
863             },
864             },
865             dpiAware => {
866             exclusive => 'none',
867             content => { elements => 0, attributes => 0, value => 1 },
868             value_validator => 'validate_truefalse',
869             attributes => {
870             },
871             elements => {
872             },
873             },
874             },
875             };
876             return $schema;
877             }
878              
879             1;
880              
881             __END__