Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

705 lines
21 KiB

  1. package SymMake;
  2. use lib $ENV{RAZZLETOOLPATH} . "\\sp";
  3. use lib $ENV{RAZZLETOOLPATH} . "\\PostBuildScripts";
  4. use lib $ENV{RAZZLETOOLPATH};
  5. use strict;
  6. use Carp;
  7. use IO::File;
  8. use Data::Dumper;
  9. use File::Basename;
  10. use File::Find;
  11. use Logmsg;
  12. # Data structure
  13. # pdbname.binext => [(var)pdbpath,size,$binext]
  14. # * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  15. #
  16. # Package SymMake
  17. # - create symbols.inf, symbols(n).ddf and symbols.cdf
  18. #
  19. # in this version, the symmake.pm creates full package's and update package's symbols.inf, symbols.ddf and symbols.cdf
  20. #
  21. # for doing this, the symmake.pm first reads the symbol list from arch, then reads another one from symbolscd.txt;
  22. # every reading, it store the record to $self->{'SYM'} and store the new file extension to $self->{'EXT'}
  23. #
  24. # then, we according $pkinfoptr to write relate information to symbols.inf, symbols(n).ddf and symbols.cdf
  25. #
  26. # [Data Relations]
  27. # $pkinfoptr and $self->{'SYM'} are the two mainly hash we operating with
  28. # $pkinfoptr - the package information includes the cab, ddf, inf's file names and the file handles
  29. # $self->{'SYM'} - the symbols records that are from archive or ntpostbld
  30. #
  31. # basically, we looping for each record in $self->{'SYM'},
  32. # according the $self->{'SYM'}->{"$symbol\.$installpath"}->[0] to get the kb term ('ARCH' or 'NTPB')
  33. # then, we use %revpktypes to get $pktype ('FULL' or 'UPDATE')
  34. #
  35. # or, we according $pktype ('FULL' or 'UPDATE') to get kb term from $pktypes
  36. # then, we can access the root of arch or ntpostbld ($self->{'KB'}->{$pktype})
  37. #
  38. # * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  39. #
  40. # $DDFHandle - the .ddf file handle for writing symbols(n).ddf
  41. # $CATHandle - the .cat file handle for writing content to .cdf for creating .cat(alog)
  42. # $INFHandle - the .inf file handle for writing symbols.inf
  43. #
  44. my ($DDFHandle, $CATHandle, $INFHandle);
  45. #
  46. # Package Types
  47. # FULL - from ARCH
  48. # UPDATE - from NTPOSTBLD
  49. #
  50. my %pktypes = (
  51. FULL => 'ARCH',
  52. UPDATE => 'NTPB'
  53. );
  54. #
  55. # %revpktypes = ( # reverse the key - value relation for %pktypes
  56. # 'ARCH' => 'FULL'
  57. # 'NTPB' => 'UPDATE'
  58. # )
  59. #
  60. my %revpktypes = reverse %pktypes;
  61. #
  62. # $obj = new SymMake $archpath, $ntpostbldpath
  63. # - object creator
  64. #
  65. # ( we assign the root and use the relation path in symbolcd.txt and archiver dump list )
  66. # return:
  67. # $obj->
  68. # 'KB' -> # Knowledge Base
  69. # 'ARCH' => \\arch\archive\....
  70. # 'NTPB' => %_NTPOSTBLD%
  71. # 'SYM' -> (empty) # The file lists of symbols, hash structure is listed in below:
  72. # # $self->{'SYM'}->
  73. # # $symbol\.$installpath -> # such as 'ntoskrnl.pdb.exe'
  74. # # [kbterm, symbol subpath, symbol filesize, $installpath] # such as ['ARCH', "\\symbols\\retail\\exe\\ntoskrnl.pdb", 4189184, 'exe']
  75. # 'EXT' -> (empty) # The file lists of symbols' file extension, hash structu is listed in below:
  76. # # $self->{'EXT'}->
  77. # # $pktype -> #such as 'FULL'
  78. # # $installpath -> 1 # such as 'EXE' -> 1
  79. # 'HANDLE' -> (empty) # The file handles
  80. # 'PKTYPE' -> undef # package type
  81. #
  82. sub new {
  83. my $class = shift;
  84. my $instance = {
  85. KB => {
  86. "$pktypes{'FULL'}" => $_[0],
  87. "$pktypes{'UPDATE'}" => $_[1]
  88. },
  89. SYM => {},
  90. EXT => {},
  91. HANDLE => {},
  92. PKTYPE => undef
  93. };
  94. return bless $instance, $class;
  95. }
  96. #
  97. # $obj->ReadSource($symbolcd)
  98. # - read the source file ($symbolcd) to $self->{'SYM'} and $self->{'EXT'}
  99. # IN: $symbolcd
  100. # REF: $self->{'PKTYPE'} : current package type
  101. #
  102. #
  103. #
  104. sub ReadSource
  105. {
  106. my ($self, $symbolcd) = @_;
  107. my ($fh, $kbterm, $mykey, @mylist);
  108. local $_;
  109. $kbterm = $pktypes{$self->{'PKTYPE'}};
  110. $symbolcd = "$self->{'KB'}->{$kbterm}\\symbolcd\\symbolcd.txt" if (!defined $symbolcd);
  111. $symbolcd = "$ENV{'TEMP'}\\symbolcd.txt" if (!-e $symbolcd);
  112. if ($self->{'PKTYPE'} =~ /FULL/i) {
  113. #
  114. # for full package, we look for $symbolcd exist
  115. # if exist, we load it
  116. #
  117. if (-e $symbolcd) {
  118. ($self->{'SYM'}, $self->{'EXT'}) = @{do $symbolcd}; # do command will load the script and evaluate (similar as 'require' command)
  119. } else {
  120. #
  121. # if not exist, we create one in run time from archive path ($self->{'KB'}->{$kbterm})
  122. #
  123. $self->HashArchServer($self->{'KB'}->{$kbterm});
  124. #
  125. # for reuse it next time, we store it to $ENV{'TEMP'}\\symbolcd.txt
  126. #
  127. # so, if we want to create one and store to archive server, we can do below:
  128. # [a.pl]
  129. # use SymMake;
  130. # ($the_archived_source_root, $my_dump_path_in_archive) = @ARGV;
  131. # $symmake = new SymMake $the_archived_source_root, $ENV{_NTPOSTBLD};
  132. # $symmake->ReadSource("$ENV{'TEMP'}\\symbolcd.txt");
  133. # sytem("copy \"$ENV{'TEMP'}\\symbolcd.txt\" $my_dump_path_in_archive
  134. # and call something similar as:
  135. # perl a.pl "\\\\arch\\archive\\ms\\windows\\windows_xp\\rtm\\2600\\$BuildType\\all\\$BuildArch\\pub" "\\\\arch\\archive\\ms\\windows\\windows_xp\\rtm\\2600\\$BuildType\\all\\$BuildArch\\pub\\symbolcd\\symbolcd.txt"
  136. #
  137. $Data::Dumper::Indent=1;
  138. $Data::Dumper::Terse=1;
  139. $fh = new IO::File $symbolcd, 'w';
  140. if (!defined $fh) {
  141. logmsg "Cannot open $symbolcd\.";
  142. } else {
  143. print $fh 'return [';
  144. print $fh Dumper($self->{'SYM'});
  145. print $fh ",\n";
  146. print $fh Dumper($self->{'EXT'});
  147. print $fh '];';
  148. $fh->close();
  149. }
  150. }
  151. } else {
  152. #
  153. # if is from update, we store $self->{'SYM'} and $self->{'EXT'} from symbolcd.txt
  154. #
  155. $self->HashSymbolCD($symbolcd);
  156. }
  157. return;
  158. #
  159. # $Data::Dumper::Indent=1;
  160. # $Data::T
  161. # print Dumper($self->{'SYM'}, qw(sym)
  162. }
  163. #
  164. # $obj->HashSymbolCD($file)
  165. # - store symbolcd.txt($file) to $self->{'SYM'} hash and $self->{'EXT'} hash
  166. #
  167. # IN: $file - the full filespec of the symbolcd.txt
  168. # OUT: none
  169. #
  170. sub HashSymbolCD
  171. {
  172. my ($self, $file) = @_;
  173. my ($fh, $bin, $symbol, $subpath, $installpath, $kbterm);
  174. local $_;
  175. $kbterm = $pktypes{$self->{'PKTYPE'}};
  176. $fh = new IO::File $file;
  177. if (!defined $fh) {
  178. logmsg "Cannot open symbolcd.txt ($file)";
  179. return;
  180. }
  181. while(<$fh>) {
  182. chomp;
  183. ($bin,$symbol,$subpath,$installpath)=split(/\,/,$_);
  184. $self->{'SYM'}->{lc"$symbol\.$installpath"} = [$kbterm, "\\" . $subpath, (-s $self->{'KB'}->{$kbterm} . '\\' . $subpath), lc$installpath];
  185. for (keys %pktypes) {
  186. $self->{'EXT'}->{$_}->{lc$installpath} = 1;
  187. }
  188. }
  189. $fh->close();
  190. }
  191. #
  192. # $obj->HashArchServer($path)
  193. # - store the list of symbols under $path to $self->{'SYM'} hash and $self->{'EXT'} hash
  194. #
  195. # IN: $path - the full path of the symbols (such as "\\\\arch\\archive\\ms\\windows\\windows_xp\\rtm\\2600\\$BuildType\\all\\$BuildArch\\pub")
  196. # OUT: none
  197. #
  198. sub HashArchServer
  199. {
  200. my ($self, $path) = @_;
  201. my ($fh, $bin, $symbol, $subpath, $installpath, $kbterm, $pdbsize);
  202. local $_;
  203. $kbterm = $pktypes{$self->{'PKTYPE'}};
  204. $fh = new IO::File "dir /s/b/a-d $path\\*.*|";
  205. if (!defined $fh) {
  206. logmsg "Cannot access to $path\.";
  207. }
  208. while (<$fh>) {
  209. chomp;
  210. $pdbsize = (-s);
  211. $_ = substr($_, length($path) + 1);
  212. /\\/;
  213. ($symbol, $subpath, $installpath) = ($',$_,$`);
  214. $self->{'SYM'}->{lc"$symbol\.$installpath"} = [$kbterm, '\\' . $subpath, $pdbsize, $installpath];
  215. $self->{'EXT'}->{$self->{'PKTYPE'}}->{$installpath} = 1;
  216. }
  217. $fh->close();
  218. }
  219. # * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  220. # * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  221. #
  222. # for Create_Symbols_CDF, and Create_Symbols_INF
  223. #
  224. # we create two writer, one is writing to update's and full package's files,
  225. # another is only writing to full package's file
  226. #
  227. # so, when we call &{$mywriter{'FULL'} - it only write to full package's file
  228. # when we call &{$mywriter{'UPDATE'} - it write to both files
  229. #
  230. # and, $mysepwriter is for writing separately
  231. # $mysepwriter{'FULL'} - write to full package
  232. # $mysepwriter{'UPDATE'} - write to update package
  233. #
  234. # we base on the writer function to loop our big symbols hash ($self->{'SYM'}) one time to
  235. # generate two documents
  236. #
  237. # for Create_Symbols_DDF
  238. #
  239. # we only need to write each record to one target file (that either in full package, or update
  240. # package to create symbols.cab). So, we don't use writer to write the DDF
  241. #
  242. # * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  243. # * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  244. #
  245. # Create_Symbols_CDF($pkinfoptr)
  246. # - Create symbols.CDF which is for creating the symbols.cat
  247. #
  248. # IN: $pkinfoptr-> # see RegisterPackage()
  249. # $pkname -> # such as 'FULL' or 'UPDATE'
  250. # 'CDFHANDLE' -> cdf file handle
  251. # 'CATNAME' -> the symbols catalog file name
  252. # 'INFNAME' -> the symbols inf file name
  253. #
  254. sub Create_Symbols_CDF
  255. {
  256. my ($self, $pkinfoptr) = @_;
  257. my ($mykbterm, $mypkname, $fhandle, $fullpdb, %mywriter);
  258. local $_;
  259. &Open_Private_Handle($pkinfoptr, 'CDF');
  260. for $mypkname (keys %{$pkinfoptr}) {
  261. # create the writer
  262. if ($mypkname ne 'FULL') {
  263. $mywriter{$mypkname} = &Writer($pkinfoptr->{$mypkname}->{'CDFHANDLE'}, $pkinfoptr->{'FULL'}->{'CDFHANDLE'});
  264. } else {
  265. $mywriter{$mypkname} = &Writer($pkinfoptr->{'FULL'}->{'CDFHANDLE'});
  266. }
  267. # write the head to each cdf file handle
  268. &Create_CDF_Head($pkinfoptr->{$mypkname}->{'CDFHANDLE'}, $pkinfoptr->{$mypkname}->{'CATNAME'}, $pkinfoptr->{$mypkname}->{'INFNAME'});
  269. }
  270. # write each record
  271. for (sort keys %{$self->{'SYM'}}) {
  272. $mykbterm = $self->{'SYM'}->{$_}->[0];
  273. $mypkname = $revpktypes{$mykbterm};
  274. $fullpdb = $self->{'KB'}->{$mykbterm} . $self->{'SYM'}->{$_}->[1];
  275. &{$mywriter{$mypkname}}("\<HASH\>" . $fullpdb . '=' . $fullpdb . "\n");
  276. }
  277. &Close_Private_Handle($pkinfoptr, 'CDF');
  278. }
  279. #
  280. # Create_Symbols_DDF($pkinfoptr)
  281. # - Create symbols.DDF which is for creating symbols.cab
  282. #
  283. # IN: $pkinfoptr-> # see RegisterPackage()
  284. # $pkname ->
  285. # 'CABNAME' =>
  286. # 'CABDEST' =>
  287. # 'CABSIZE' =>
  288. # 'DDFNAME' =>
  289. # 'CABCOUNT' =>
  290. # 'DDFLIST' => (return cab list)
  291. # 'DDFHANDLE' =>
  292. #
  293. sub Create_Symbols_DDF
  294. {
  295. my ($self, $pkinfoptr) = @_;
  296. my ($symkey, $symptr, $kbterm, $subpath, $pktype, $mypkinfoptr, $cabname, $ddfname, $cabcount, $DDFHandle, $myddfname, $mycabname);
  297. local $_;
  298. # initialization
  299. map({$_->{'CURSIZE'} = $_->{'CABSIZE'}} values %{$pkinfoptr});
  300. for (sort keys %{$self->{'SYM'}}) {
  301. $symkey = $_;
  302. $symptr = $self->{'SYM'}->{$_};
  303. # base on $self->{'SYM'}->{$symbol\.$installpath}->[0] to reference %revpktypes and get the package type ($pktype)
  304. ($kbterm, $subpath) = ($symptr->[0],$symptr->[1]);
  305. $pktype = $revpktypes{$kbterm};
  306. # don't generate something not specify
  307. next if (!exists $pkinfoptr->{$pktype});
  308. $mypkinfoptr = $pkinfoptr->{$pktype};
  309. #
  310. # According uncompressed files total size to seperate the cab
  311. # 'CURSIZE' - current size
  312. # 'CABSIZE' - is the approx. size
  313. #
  314. $mypkinfoptr->{'CURSIZE'}+=$symptr->[2];
  315. # if this cab list (ddf) is full
  316. if ($mypkinfoptr->{'CURSIZE'} >= $mypkinfoptr->{'CABSIZE'}) {
  317. # initial the current size to the current symbol's file size
  318. $mypkinfoptr->{'CURSIZE'} = $symptr->[2];
  319. ($cabname, $ddfname, $cabcount) = (
  320. $mypkinfoptr->{'CABNAME'},
  321. $mypkinfoptr->{'DDFNAME'},
  322. ++$mypkinfoptr->{'CABCOUNT'}
  323. );
  324. $myddfname = $ddfname . $cabcount . '.ddf';
  325. $mycabname = $cabname . $cabcount . '.cab';
  326. # create the new file and its DDF file head
  327. # the old file will automatically close by Perl
  328. $mypkinfoptr->{'DDFHANDLE'} = new IO::File $myddfname, 'w';
  329. if (!defined $mypkinfoptr->{'DDFHANDLE'}) {
  330. logmsg "Cannot open DDF file $myddfname\.";
  331. }
  332. &Create_DDF_Head($mypkinfoptr->{'DDFHANDLE'}, $mycabname);
  333. $mypkinfoptr->{'DDFLIST'}->{$myddfname} = $mycabname;
  334. }
  335. # write the record to the ddf file handle
  336. $DDFHandle = $mypkinfoptr->{'DDFHANDLE'};
  337. print $DDFHandle '"' . $self->{'KB'}->{$kbterm} . $subpath . '" "' . $symkey . "\"\n";
  338. }
  339. &Close_Private_Handle($pkinfoptr, 'DDF');
  340. }
  341. #
  342. # Create_Symbols_INF($pkinfoptr)
  343. # - Create symbols.inf
  344. #
  345. #
  346. # pkinfoptr-> # see RegisterPackage()
  347. # $pkname ->
  348. # INFNAME =>
  349. # CDFNAME =>
  350. # CABNAME =>
  351. # CATNAME =>
  352. # INFHANDLE =>
  353. #
  354. sub Create_Symbols_INF
  355. {
  356. my ($self, $pkinfoptr) = @_;
  357. my ($mypkname, $mypkinfoptr, $INFHandle, %mywriter, %mysepwriter, %h, %cabnames);
  358. local $_;
  359. &Open_Private_Handle($pkinfoptr, 'INF');
  360. for $mypkname (keys %{$pkinfoptr}) {
  361. ($mypkinfoptr, $INFHandle) = ($pkinfoptr->{$mypkname}, $pkinfoptr->{$mypkname}->{'INFHANDLE'});
  362. # create the writer
  363. if ($mypkname ne 'FULL') {
  364. $mywriter{$mypkname} = &Writer($INFHandle, $pkinfoptr->{'FULL'}->{'INFHANDLE'});
  365. } else {
  366. $mywriter{$mypkname} = &Writer($INFHandle);
  367. }
  368. $mysepwriter{$mypkname} = &Writer($INFHandle);
  369. &Create_INF_Version($INFHandle, $mypkinfoptr->{'CATNAME'});
  370. &Create_INF_Install($INFHandle, $self->{'EXT'}->{$mypkname});
  371. $cabnames{$mypkname} = (FileParse($mypkinfoptr->{'CABNAME'}))[0];
  372. }
  373. # the extension tag (ex. [FILES.EXE]) needs to write separately depends on update / full package has this extension's symbols or not
  374. # so, we need to use separately writer for this kind information
  375. &Create_INF_Files($self->{'SYM'}, \%mysepwriter, \%mywriter);
  376. &Create_INF_SourceDisks($self->{'SYM'}, \%cabnames, \%mysepwriter, \%mywriter);
  377. &Close_Private_Handle($pkinfoptr, 'INF');
  378. }
  379. # * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  380. #
  381. # Create_DDF_Head - create the .ddf's file head for symbols(n).ddf
  382. # Create_CDF_Head - create the .cdf's file head for symbols.cdf
  383. # Create_INF_Version - create the .inf's Version section
  384. # Create_INF_Install - create the .inf's [DefaultInstall], [DefaultInstall.Quiet]
  385. # [BeginPromptSection], [EndPromptSection], [RegVersion]
  386. # [SymCust], [CustDest], [CustDest.2], [DestinationDirs]
  387. #
  388. # Create_INF_Files - create the .inf's [Files.<extension>] sections
  389. # Create_INF_SourceDisks - create the [SourceDisksNames], [SourceDisksFiles]
  390. #
  391. # * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  392. sub Create_DDF_Head
  393. {
  394. my ($DDFHandle, $cabname) = @_;
  395. my ($mycabname, $mycabdest) = FileParse($cabname);
  396. print $DDFHandle <<DDFHEAD;
  397. .option explicit
  398. .Set DiskDirectoryTemplate=$mycabdest
  399. .Set RptFileName=nul
  400. .Set InfFileName=nul
  401. .Set CabinetNameTemplate=$mycabname\.cab
  402. .Set CompressionType=MSZIP
  403. .Set MaxDiskSize=CDROM
  404. .Set ReservePerCabinetSize=0
  405. .Set Compress=on
  406. .Set CompressionMemory=21
  407. .Set Cabinet=ON
  408. .Set MaxCabinetSize=999999999
  409. .Set FolderSizeThreshold=1000000
  410. DDFHEAD
  411. }
  412. sub Create_CDF_Head
  413. {
  414. my ($CDFHandle, $catname, $infname) = @_;
  415. $catname = (FileParse($catname))[0];
  416. print $CDFHandle <<CDFHEAD;
  417. [CatalogHeader]
  418. Name=$catname
  419. PublicVersion=0x00000001
  420. EncodingType=0x00010001
  421. CATATTR1=0x10010001:OSAttr:2:5.X
  422. [CatalogFiles]
  423. \<HASH\>$infname\.inf=$infname\.inf
  424. CDFHEAD
  425. }
  426. sub Create_INF_Version
  427. {
  428. my ($INFHandle, $catname) = @_;
  429. $catname = (FileParse($catname))[0];
  430. print $INFHandle <<INFVERSION;
  431. [Version]
  432. AdvancedInf= 2.5
  433. Signature= "\$CHICAGO\$"
  434. CatalogFile= $catname\.CAT
  435. INFVERSION
  436. }
  437. sub Create_INF_Install
  438. {
  439. my ($INFHandle, $exthptr) = @_;
  440. my $CopyFiles = 'Files.' . join(", Files\.", sort keys %{$exthptr});
  441. print $INFHandle <<INF_INSTALL;
  442. [DefaultInstall]
  443. CustomDestination= CustDest
  444. AddReg= RegVersion
  445. BeginPrompt= BeginPromptSection
  446. EndPrompt= EndPromptSection
  447. RequireEngine= Setupapi;
  448. CopyFiles= $CopyFiles
  449. [DefaultInstall.Quiet]
  450. CustomDestination=CustDest.2
  451. AddReg= RegVersion
  452. RequireEngine= Setupapi;
  453. CopyFiles= $CopyFiles
  454. [BeginPromptSection]
  455. Title= "Microsoft Windows Symbols"
  456. [EndPromptSection]
  457. Title= "Microsoft Windows Symbols"
  458. Prompt= "Installation is complete"
  459. [RegVersion]
  460. "HKLM","SOFTWARE\\Microsoft\\Symbols\\Directories","Symbol Dir",0,"\%49100\%"
  461. "HKCU","SOFTWARE\\Microsoft\\Symbols\\Directories","Symbol Dir",0,"\%49100\%"
  462. "HKCU","SOFTWARE\\Microsoft\\Symbols\\SymbolInstall","Symbol Install",,"1"
  463. [SymCust]
  464. "HKCU", "Software\\Microsoft\\Symbols\\Directories","Symbol Dir","Symbols install directory","\%25\%\\Symbols"
  465. [CustDest]
  466. 49100=SymCust,1
  467. [CustDest.2]
  468. 49100=SymCust,5
  469. [DestinationDirs]
  470. ;49100 is \%systemroot\%\\symbols
  471. Files.inf = 17
  472. Files.system32 = 11
  473. INF_INSTALL
  474. for (sort keys %{$exthptr}) {
  475. printf $INFHandle ("Files\.%-6s\t\t\= 49100,\"%s\"\n", $_, $_);
  476. }
  477. }
  478. sub Create_INF_Files
  479. {
  480. my ($symptr, $sepwriter, $popwriter) = @_;
  481. my ($mykbterm, $mypkname, %tags);
  482. local $_;
  483. for (sort {($symptr->{$a}->[3] cmp $symptr->{$b}->[3]) or ($a cmp $b)} keys %{$symptr}) {
  484. $mykbterm = $symptr->{$_}->[0];
  485. $mypkname = $revpktypes{$mykbterm};
  486. # if is a new tag name,
  487. if ($symptr->{$_}->[3] ne $tags{$mypkname}->[0]) {
  488. $tags{$mypkname} = [$symptr->{$_}->[3], - length($symptr->{$_}->[3]) -1];
  489. &{$sepwriter->{$mypkname}}("\n\[Files\.$tags{$mypkname}->[0]\]\n");
  490. }
  491. # if its from update list and different with the current full list's file extension
  492. # we need to create a new tag in full list
  493. if ($symptr->{$_}->[3] ne $tags{'FULL'}->[0]) {
  494. $tags{'FULL'} = [$symptr->{$_}->[3], - length($symptr->{$_}->[3]) -1];
  495. &{$sepwriter->{'FULL'}}("\n\[Files\.$tags{'FULL'}->[0]\]\n");
  496. }
  497. # $popwriter will write update ($mypkname) to both files and full to full package list
  498. &{$popwriter->{$mypkname}}(substr($_, 0, $tags{$mypkname}->[1]) . "\,$_\,\,4\n");
  499. }
  500. }
  501. sub Create_INF_SourceDisks
  502. {
  503. my ($symptr, $cabnameptr, $sepwriter, $popwriter) = @_; # $pkinfoptr) = @_;
  504. my ($INFHandle, $cabname, $mypkname);
  505. local $_;
  506. for (keys %{$cabnameptr}) {
  507. $cabname = $cabnameptr->{$_};
  508. &{$sepwriter->{$_}}(<<SOURCE_DISKS);
  509. [SourceDisksNames]
  510. 1="$cabname\.cab",$cabname\.cab,0
  511. [SourceDisksFiles]
  512. SOURCE_DISKS
  513. }
  514. for (sort keys %{$symptr}) {
  515. $mypkname = $revpktypes{$symptr->{$_}->[0]};
  516. &{$popwriter->{$mypkname}}($_ . "=1\n");
  517. }
  518. }
  519. # * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  520. #
  521. # Reusable subruntines
  522. #
  523. # * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  524. #
  525. # RegisterPackage($pkinfoptr, $pktype,$hptr)
  526. # - register $hptr to $pkinfoptr->{$pktype}
  527. # - registerpackage is the function to verify and store $pkinfoptr
  528. # - the cabname, ddfname, infname, cdfname, catname - are equal to 'SYMBOLS' normally
  529. # - cabsize is the total size for include files into one cab, we cannot compute the compressed
  530. # file size, so we compute with the uncompress file size
  531. #
  532. # - cabhandle, ddfhandle, infhandle - the file handles for .cab, .ddf and .inf; we create them
  533. # inside this module
  534. # - DDFLIST - the lists of the ddf files we plan to create
  535. #
  536. # $pkinfoptr->
  537. # $pktype ->
  538. # CABNAME
  539. # DDFNAME
  540. # INFNAME
  541. # CDFNAME
  542. # CATNAME
  543. # CABSIZE
  544. #
  545. # CABHANDLE - (reserved)
  546. # DDFHANDLE - (reserved)
  547. # INFHANDLE - (reserved)
  548. #
  549. # DDFLIST - (return)
  550. #
  551. sub RegisterPackage
  552. {
  553. my ($pkinfoptr, $pktype, $hptr) = @_;
  554. my ($mykey);
  555. my @chklists = qw(CABNAME DDFNAME INFNAME CDFNAME CATNAME CABSIZE);
  556. # register to $pkinfoptr
  557. $pkinfoptr->{$pktype} = $hptr;
  558. # check we have enough information
  559. for $mykey (@chklists) {
  560. die "$mykey not defined in $pktype" if (!exists $pkinfoptr->{$pktype}->{$mykey});
  561. }
  562. }
  563. #
  564. # $obj = Writer(@handles)
  565. # - the writer generator; generates a function to write one data to each @handles
  566. # keep @handles in parent program and $_[0] in sub {....} is the data we send to &{$obj}($data)
  567. #
  568. sub Writer {
  569. my (@handles) = @_;
  570. my ($hptr)=\@handles;
  571. return sub {
  572. my ($myhandle);
  573. for $myhandle (@{$hptr}) {
  574. print $myhandle $_[0];
  575. }
  576. };
  577. }
  578. #
  579. # Open_Private_Handle($pkinfoptr, $ftype)
  580. # - open each pkname of each $ftype name's file and store the handle to $pkinfoptr->{$pkname}->{$ftype . 'HANDLE'}
  581. # - for example, if we call Open_Private_Handle($pkinfoptr, 'DDF')
  582. # - it open $pkinfoptr->{'FULL'}->{'DDFNAME'} and $pkinfoptr->{'UPDATE'}->{'DDFNAME'}
  583. # - and store the file handle to $pkinfoptr->{'FULL'}->{'DDFHANDLE'} and $pkinfoptr->{'UPDATE'}->{'DDFHANDLE'}
  584. #
  585. sub Open_Private_Handle
  586. {
  587. my ($pkinfoptr, $ftype) = @_;
  588. my ($pkname);
  589. for $pkname (keys %{$pkinfoptr}) {
  590. $pkinfoptr->{$pkname}->{$ftype . 'HANDLE'} = new IO::File $pkinfoptr->{$pkname}->{$ftype . 'NAME'} . '.' . $ftype, 'w';
  591. if (!defined $pkinfoptr->{$pkname}->{$ftype . 'HANDLE'}) {
  592. logmsg "Cannot open " . $pkinfoptr->{$pkname}->{$ftype . 'NAME'} . '.' . $ftype . ".";
  593. }
  594. }
  595. }
  596. sub Close_Private_Handle
  597. {
  598. my ($pkinfoptr, $ftype) = @_;
  599. my ($pkname);
  600. for $pkname (keys %{$pkinfoptr}) {
  601. $pkinfoptr->{$pkname}->{$ftype . 'HANDLE'}->close() if (defined $pkinfoptr->{$pkname}->{$ftype . 'HANDLE'});
  602. delete $pkinfoptr->{$pkname}->{$ftype . 'HANDLE'};
  603. }
  604. }
  605. sub FileParse
  606. {
  607. my ($name, $path, $ext) = fileparse(shift, '\.[^\.]+$');
  608. $ext =~ s/^\.//;
  609. return $name, $path, $ext;
  610. }
  611. 1;