home *** CD-ROM | disk | FTP | other *** search
/ Freelog Special Freeware 31 / FreelogHS31.iso / PDF / Ghostscript / gs860w32.exe / gs8.60 / lib / gs_resmp.ps < prev    next >
Text File  |  2007-06-13  |  23KB  |  532 lines

  1. %    Copyright (C) 2000 Artifex Software, Inc.  All rights reserved.
  2. % This software is provided AS-IS with no warranty, either express or
  3. % implied.
  4. % This software is distributed under license and may not be copied,
  5. % modified or distributed except as expressly authorized under the terms
  6. % of the license contained in the file LICENSE in this distribution.
  7. % For more information about licensing, please refer to
  8. % http://www.ghostscript.com/licensing/. For information on
  9. % commercial licensing, go to http://www.artifex.com/licensing/ or
  10. % contact Artifex Software, Inc., 101 Lucas Valley Road #110,
  11. % San Rafael, CA  94903, U.S.A., +1(415)492-9861.
  12.  
  13. % $Id: gs_resmp.ps 8046 2007-06-12 20:55:18Z alexcher $
  14. % A procset to redefine a resource category with a resource map.
  15.  
  16. % Public entries :
  17.  
  18. % Redefine - a procedure for redefining a resource category with a map.
  19. %    Methods for interpreting the resource map to be provided by client 
  20. %    in the argument dictionary.
  21. %
  22. %    Note that the procedure Redefine is idempotential :
  23. %    consequtive calls to it will not replace the category methods,
  24. %    but will merge resource maps. If an interleaving redefinition
  25. %    needs to cancel the idempotentity, it must remove the entry
  26. %    /.IsRedefinedWithMap from the category dictionary.
  27.  
  28. % MakeResourceEnumerator - this procedure is useful for
  29. %    redefining any category. It provides a proper order of instances
  30. %    and proper stacks during resourceforall.
  31.  
  32. % BindWithCurrentdict - a procedure for generating temporary procedures 
  33. %    from templates, binding them with a local dictionary.
  34.  
  35. % execstack_lookup - a procedure for communicating through the execution stack.
  36. %    It allows for a callee to get an information from an indirect caller.
  37.  
  38. % The procedures are designed for exeution witout putting
  39. % the procset instance onto the dictionary stack.
  40.  
  41. languagelevel 2 .setlanguagelevel
  42. currentglobal true setglobal
  43.  
  44. /MappedCategoryRedefiner 10 dict begin % The procset.
  45.  
  46. currentpacking false setpacking
  47.  
  48. /InstanceEnumeratorPattern   %  - InstanceEnumeratorPattern ...
  49. {  
  50.   % This is a pattern for enumeration procedure to be built dynamically,
  51.   % applying BindWithCurrentdict with a temporary dictionary.
  52.   % The following names will be replaced with specific objects
  53.   % during BindWithCurrentdict :
  54.   % en_local_dict - a dictionary for storing the local integer variable 'status'.
  55.   % scr - the scratch string argument of resourceforall;
  56.   % proc - the procedure argument of resourceforall;
  57.   % InstancesStatus - a dictionary that maps resource instance names to their status value;
  58.   % Category - the category to be enumerated.
  59.  
  60.   % When this procedure is called from ResourceForAll, the category is the current dictionary.
  61.   % We remove it from the dictionary stack before performing the enumeration
  62.   % to provide the <proc> to write to the underlying dictionary,
  63.   % and put it back after the enumeration is completed.
  64.   end
  65.   { 
  66.     0 1 2 {
  67.       en_local_dict exch /status exch put
  68.       InstancesStatus {                                            
  69.         en_local_dict /status get eq {
  70.           scr cvs                           % ... (Font)
  71.           proc exec                         %
  72.         } {
  73.           pop
  74.         } ifelse                            % ...
  75.       } forall
  76.     } for                                   % ...
  77.   } stopped
  78.   Category begin
  79.   { stop } if
  80. } bind def
  81.  
  82. % An auxiliary proc for BindWithCurrentdict :
  83. /.BindAux    % <proc> BindAux <proc>
  84. { 0 exec
  85. } bind def
  86.  
  87. setpacking
  88.  
  89. /BindWithCurrentdict     % <proc> BindWithCurrentdict <proc>
  90. {  
  91.   % Make a copy of the given procedure, binding in the values of all names
  92.   % defined in currentdict.
  93.   % Caution1 : this code cannot handle procedures that were already
  94.   %            bound recursively.
  95.   % Caution2 : this code don't bind packedarrays. This was done
  96.   %            intentionally for a termination of the procedure tree.
  97.  
  98.   dup length array copy
  99.   dup length 1 sub -1 0 {                      
  100.     2 copy get                            % {precopy} i {elem}
  101.     dup dup type /arraytype eq exch xcheck and {
  102.                                           % {precopy} i {elem}
  103.       //.BindAux exec                     % {precopy} i {elem_copy}
  104.       2 index 3 1 roll put                % {precopy}
  105.     } {
  106.       dup dup type /nametype eq exch xcheck and {
  107.                                           % {precopy} i {elem}
  108.         currentdict exch .knownget {            
  109.           2 index 3 1 roll put            % {precopy}
  110.         } {                                            
  111.           pop
  112.         } ifelse
  113.       } {
  114.         pop pop
  115.       } ifelse
  116.     } ifelse                              % {precopy}
  117.   } for                                   % {copy}
  118.   cvx
  119. } bind def
  120.  
  121. //.BindAux 0 //BindWithCurrentdict put   % bind the recursive call in 'Bind'.
  122.  
  123. /MakeResourceEnumerator   % <proc> <scr> <InstancesStatus> MakeResourceEnumerator <Enumerator>
  124. {
  125.   % Build the enumeration procedure :
  126.  
  127.   % Since the resourceforall procedure may leave values on the operand stack,
  128.   % we cannot simply store the enumerator's local data on the stack.
  129.   % We also cannot use a static dictionary to store local variables,
  130.   % because of possible recursion in the resourceforall procedure.
  131.   % To work around this, we create a copy of the enumeration procedure and
  132.   % bind it dynamically with a temporary dictionary, which contains
  133.   % local variables for the currently executing instance of resourceforall.
  134.  
  135.   % Always place the enumerator in local VM,
  136.   % because its elements may be in local VM.
  137.  
  138.   currentglobal 4 1 roll
  139.   false setglobal
  140.   currentdict                    % Category
  141.   6 dict begin % the temporary dictionary
  142.     /Category exch def
  143.     /InstancesStatus exch def
  144.     /scr exch def
  145.     /proc exch def
  146.     /en_local_dict currentdict def
  147.     //InstanceEnumeratorPattern //BindWithCurrentdict exec     % Enumerator
  148.     /status 0 def % variable for the current status to enumerate - do not bind with it !
  149.   end
  150.   exch setglobal
  151. } bind def
  152.  
  153. /execstack_lookup     % <object> execstack_lookup <object1>
  154.                       % <object> execstack_lookup null
  155. { % Checks whether execution stack contains a procedure starting with <object>,
  156.   % and retrives the 2nd element of the procedure,
  157.   % or null if the procedure was not found.
  158.   %
  159.   % Since 'execstack' actually renders subarrays of procedures,
  160.   % the pattern for recognition must be like this :
  161.   %
  162.   %   { <object> <object1>
  163.   %     CallSomething
  164.   %   } loop
  165.   %
  166.   % The solution with 'loop' depends on how GS implements cycles,
  167.   % so it must not appear in documents, which are required to be interpreter independent.
  168.   % Any other type of cycles are also acceptable.
  169.   % If no repitition is really needed, just insert 'exit' into its body.
  170.   % If <object> <object1> are not needed for the caller, insert "pop pop" after them.
  171.   % If <object1> is really unuseful, the pattern may be simplified :
  172.   %
  173.   %   { <object> pop
  174.   %     CallSomething
  175.   %     exit
  176.   %   } loop
  177.   %
  178.   % It will retrieve 'pop' or 'null'.
  179.   %
  180.   % Note that 2 topmost execstack elements are the execstack_lookup procedure and its caller.
  181.   % We don't check them.
  182.  
  183.   currentglobal false setglobal                    % <object> bGlobal
  184.   countexecstack array execstack                   % <object> bGlobal [execstack]
  185.   dup null exch                                    % <object> bGlobal [execstack] null [execstack]
  186.   length 3 sub -1 0 {                              % <object> bGlobal [execstack] null i
  187.     2 index exch get                               % <object> bGlobal [execstack] null proc
  188.     dup type dup /packedarraytype eq exch /arraytype eq or {
  189.       dup rcheck {
  190.         dup length 1 gt {                          % <object> bGlobal [execstack] null proc
  191.           dup 0 get                                % <object> bGlobal [execstack] null proc elem0
  192.           5 index eq {                             % <object> bGlobal [execstack] null proc
  193.             1 get                                  % <object> bGlobal [execstack] null object1
  194.             exch pop exit                          % <object> bGlobal [execstack] object1
  195.           } {
  196.             pop
  197.           } ifelse
  198.         } {
  199.           pop                                      % <object> bGlobal [execstack] false
  200.         } ifelse
  201.       } {
  202.         pop                                        % <object> bGlobal [execstack] false
  203.       } ifelse
  204.     } {
  205.       pop                                          % <object> bGlobal [execstack] false
  206.     } ifelse
  207.   } for                                            % <object> bGlobal [execstack] bResult
  208.   exch pop exch setglobal exch pop                 % bResult
  209. } bind def
  210.  
  211. currentpacking false setpacking
  212. /MethodsToRedefine 5 dict begin
  213.  
  214.     % Procedures in this dictionary really are patterns for new category methods.
  215.     % The following names will be replaced with specific objects during BindWithCurrentdict :
  216.     %   .map - the map dictionary;
  217.     %   DefineResource, ResourceStatus, ResourceFileName, FindResource, ResourceForAll 
  218.     %        - procedures from the original resource category.
  219.  
  220.     /FindResource  % <Name> FindResource <dict>
  221.     { RESMPDEBUG { (resmp FindResource beg ) print dup = } if
  222.       dup ResourceStatus exec {
  223.         pop 2 lt
  224.       } {
  225.         false
  226.       } ifelse                             % bInVirtualMemory
  227.       { FindResource exec
  228.       } {
  229.         dup dup .map exch .knownget {      % /Name /Name <<record>>
  230.           dup dup /RecordVirtualMethods get /IsActive get exec {
  231.             1 index .getvminstance {       % /Name /Name <<record>> holder
  232.               1 get 1 eq
  233.             } {
  234.               true
  235.             } ifelse                       % /Name /Name <<record>> bStatusIs1
  236.             4 1 roll                       % bStatusIs1 /Name /Name <<record>>
  237.             dup /RecordVirtualMethods get /MakeInstance get exec
  238.                                            % bStatusIs1 /Name /Name Instance size
  239.             5 1 roll                       % size bStatusIs1 /Name /Name Instance
  240.             DefineResource exec            % size bStatusIs1 /Name Instance
  241.             % Make ResourceStatus to return correct values for this instance :
  242.             % Hack: we replace status values in the instance holder :
  243.             exch .getvminstance pop        % size bStatusIs1 Instance holder
  244.             dup 5 -1 roll 2 exch put       % bStatusIs1 Instance holder
  245.             3 2 roll {                     % Instance holder
  246.               1 1 put                      % Instance
  247.             } {
  248.               pop
  249.             } ifelse                       % Instance
  250.           } {                              % /Name /Name <<record>>
  251.             pop pop FindResource exec            
  252.           } ifelse
  253.         } {                                % /Name /Name
  254.           pop FindResource exec            
  255.         } ifelse
  256.       } ifelse
  257.       RESMPDEBUG { (resmp FindResource end) = } if
  258.     } bind def
  259.  
  260.     /ResourceStatus   % <Name> ResourceStatus <status> <size> true
  261.                       % <Name> ResourceStatus false
  262.     { RESMPDEBUG { (resmp ResourceStatus beg ) print dup == } if
  263.       dup ResourceStatus exec {            % /Name status size
  264.         1 index 2 lt {
  265.           % In VM - return with it.
  266.           3 2 roll pop true
  267.         } {
  268.           % Not in VM.
  269.           exch pop exch                    % size /Name
  270.           dup .map exch .knownget {        % size /Name <<record>>
  271.             dup dup /RecordVirtualMethods get /IsActive get exec {
  272.               3 2 roll pop                 % /Name <<record>>
  273.               dup /RecordVirtualMethods get /GetSize get exec 2 exch true
  274.             } {                            % size /Name <<record>>
  275.               pop pop 2 exch true
  276.             } ifelse
  277.           } {                              % size /Name
  278.             pop 2 exch true
  279.           } ifelse
  280.         } ifelse
  281.       } {                                  % /Name
  282.         dup .map exch .knownget {          % /Name <<record>>
  283.           dup dup /RecordVirtualMethods get /IsActive get exec {
  284.             dup /RecordVirtualMethods get /GetSize get exec 2 exch true
  285.           } {                              % /Name <<record>>
  286.             pop pop false
  287.           } ifelse
  288.         } {                                % /Name
  289.           pop false
  290.         } ifelse
  291.       } ifelse
  292.       RESMPDEBUG { (resmp ResourceStatus end) = } if
  293.     } bind def
  294.  
  295.     /ResourceFileName  % <Name> <scratch> ResourceFileName <string>
  296.     { RESMPDEBUG { (resmp ResourceFileName beg ) print 1 index = } if
  297.       exch                                                    % (scratch) /Name
  298.       .map 1 index .knownget {                                % (scratch) /Name <<record>>
  299.           RESMPDEBUG { (resmp ResourceFileName : have a map record.) = } if
  300.         dup dup /RecordVirtualMethods get /IsActive get exec {
  301.           RESMPDEBUG { (resmp ResourceFileName : record is active.) = } if
  302.           dup /RecordVirtualMethods get /GetFilePath get exec % (string)
  303.           RESMPDEBUG { (resmp ResourceFileName : retrieving ) print dup = } if
  304.         } {                                                   % (scratch) /Name <<record>>
  305.           RESMPDEBUG { (resmp ResourceFileName : record is NOT active.) = } if
  306.           pop exch ResourceFileName exec
  307.           RESMPDEBUG { (resmp ResourceFileName : retrieving ) print dup = } if
  308.         } ifelse
  309.       } { 
  310.         RESMPDEBUG { (resmp ResourceFileName : have NO map record.) = } if
  311.         exch ResourceFileName exec
  312.         RESMPDEBUG { (resmp ResourceFileName : retrieving ) print dup = } if
  313.       } ifelse
  314.       RESMPDEBUG { (resmp ResourceFileName end) = } if
  315.     } bind def
  316.  
  317.     /ResourceForAll  % <template> <proc> <scratch> ResourceForAll -
  318.     { RESMPDEBUG { (resmp ResourceForAll beg ) print CategoryName =string cvs print ( ) print 2 index = } if
  319.       % Create InstancesStatus dictionary :
  320.       20 dict % IS - Instances Status
  321.       4 1 roll                            % <<IS>> (templ) {proc} (sctarch)
  322.       % Check if we are under another ResourceForAll :
  323.       /.DisableResourceOrdering //execstack_lookup exec null eq 4 1 roll
  324.                                           % <<IS>> bOrder (templ) {proc} (sctarch)
  325.  
  326.       % Put underlying resources to the InstancesStatus dictionary :
  327.       currentdict % the category
  328.       begin % ResourceForAll removes it locally.
  329.       2 index
  330.       { cvn                               % <<IS>> bOrder (templ) {proc} (sctarch) /Name
  331.         4 index {
  332.           dup ResourceStatus exec {pop 6 index 3 1 roll put} {pop} ifelse
  333.         } {
  334.           5 index exch 2 put % Don't need the ordering, put '2' as a scratch.
  335.         } ifelse
  336.       }
  337.       2 index ResourceForAll exec         % <<IS>> bOrder (templ) {proc} (sctarch)
  338.       4 3 roll pop                        % <<IS>> (templ) {proc} (sctarch)
  339.       end
  340.  
  341.       % Put .map entries to the InstancesStatus dictionary :
  342.       4 -1 roll begin                     % (templ) {proc} (sctarch)
  343.       .map {                              % (templ) {proc} (sctarch) /Name record
  344.          dup dup /RecordVirtualMethods get /IsActive get exec {
  345.            pop                            % (templ) {proc} (sctarch) /Name
  346.            dup currentdict exch known {
  347.              pop
  348.            } {
  349.              dup 2 index cvs              % (templ) {proc} (sctarch) /Name (Name)
  350.              4 index .stringmatch {       % (templ) {proc} (sctarch) /Name
  351.                2 def % It is not in VM.
  352.              } {
  353.                pop
  354.              } ifelse
  355.            } ifelse
  356.         } {                               % (templ) {proc} (sctarch) /Name record
  357.           pop pop
  358.         } ifelse
  359.       } forall                            % (templ) {proc} (sctarch)
  360.  
  361.       % prepare stacks for the enumeration :
  362.       3 2 roll pop                        % {proc} (sctarch)
  363.       currentdict end                     % {proc} (scratch) <<IS>>
  364.  
  365.       % Make the enumerator and apply it :
  366.       //MakeResourceEnumerator exec exec
  367.       RESMPDEBUG { (resmp ResourceForAll end)= } if
  368.     } bind def
  369.  
  370.     /GetCIDSystemInfoFromMap   % <Name> GetCIDSystemInfoFromMap <Name>
  371.                                % <Name> GetCIDSystemInfoFromMap <dict>
  372.     { RESMPDEBUG { (resmp GetCIDSystemInfoFromMap beg ) print dup = } if
  373.       % This is a special function for communicating with GetCIDSystemInfo in gs_cidcm.ps .
  374.       dup .map exch .knownget {
  375.         RESMPDEBUG { (resmp GetCIDSystemInfoFromMap : have a map record.) = } if
  376.         dup /RecordVirtualMethods get /GetCSI get exec
  377.         dup null ne {
  378.           RESMPDEBUG { (resmp GetCIDSystemInfoFromMap : retrieving a dict.) = } if
  379.           exch
  380.         } if
  381.         pop
  382.       } if
  383.       RESMPDEBUG { (resmp GetCIDSystemInfoFromMap end) = } if
  384.     } bind def
  385.  
  386. currentdict end def
  387. setpacking
  388.  
  389. /Redefine     % <OptionsDict> Redefine -
  390. { % Before calling this proc, the OptionsDict must specify options for
  391.   % the catregory to be redefined :
  392.   % CategoryName - a name of category to redefine;
  393.   % MapFileName - a string for the resource map file name;
  394.   % VerifyMap - a procedure :
  395.   %   <raw_map> VerifyMap -
  396.   %   - checks the map for consistency
  397.   % PreprocessRecord  - a procedure :
  398.   %   <map> <Name> <raw_record> PreprocessRecord <map> <Name> <record> true
  399.   %   <map> <Name> <raw_record> PreprocessRecord <map> <Name> <raw_record> false
  400.   %   - converts a map record into a dictionary;
  401.   %   It must add RecordVirtualMethods dictionary to the record :
  402.   %     MakeInstance - a procedure :
  403.   %         <Name> <record> MakeInstance <Name> <Instance> <size>
  404.   %         - converts the record to resource instance;
  405.   %     GetFilePath - a procedure for ResourceFileName :
  406.   %         <scratch> <Name> <record> GetFilePath <filepath>
  407.   %     GetSize - a procedure for ResourceStatus :
  408.   %         <Name> <record> GetSize <size>
  409.   %     GetCSI - a procedure for obtaining CIDSystemInfo dictionary from the record :
  410.   %         <record> GetCSI <CSI>
  411.   %         <record> GetCSI null
  412.   %     IsActive - a procedure for skipping records depending on the current device :
  413.   %         <record> IsActive <bool>
  414.   %     Also it is allowed to contain additional entries for client's needs.
  415.   % The OptionsDict is also used for storing some local variables.
  416.  
  417.   % If a category is being redefined several times with this function,
  418.   % each redefinition must either use an unique map file,
  419.   % or the map file should be scanned by the last redefinition
  420.   % (and must be defined in the last one with /MapFileName).
  421.   % This happens so because we must accumulate all variants of
  422.   % methods before scanning the map. We would like to delay
  423.   % the scanning until all redefinitions are done, but it requires
  424.   % to implement a queue of "refinish" methods and execute it
  425.   % at very end of the prelude.
  426.  
  427.   begin % OptionsDict
  428.   CategoryName /Category findresource /OldCategory exch def
  429.   OldCategory /.IsRedefinedWithMap known {
  430.     % Already redefined with map - don't redefine, but enhance the map.
  431.     OldCategory /NewCategory exch def
  432.   } {
  433.     % Redefine with a new category instance.
  434.     OldCategory dup length dict 
  435.     dup /.PreprocessRecord 4 dict put
  436.     copy /NewCategory exch def
  437.   } ifelse
  438.  
  439.   % Provide the 'or' logic for PreprocessRecord,
  440.   % to allow different record types to be mixed in a single map file.
  441.   % We do this with building a dictionary of PreprocessRecord procedures,
  442.   % which come from different calls to Redefine :
  443.   NewCategory /.PreprocessRecord get dup length % <<pr>> l  
  444.   currentdict /PreprocessRecord get .growput
  445.  
  446.   currentdict /MapFileName known {
  447.     MapFileName .libfile {
  448.       1 dict begin
  449.       /; {} def
  450.       mark exch cvx exec .dicttomark           % <<map>>
  451.       end
  452.       dup VerifyMap                            % <<map>>
  453.     } {
  454.       QUIET not {
  455.         currentdict /IsMapFileOptional .knownget not { false } if not {
  456.           (Warning: the map file ) print dup =string cvs print ( was not found.) =
  457.         } if
  458.       } if
  459.       pop 0 dict                               % <<map>>
  460.     } ifelse
  461.   } {
  462.     currentdict /.map .knownget not { 
  463.       0 dict                                   % <<map>>
  464.     } if
  465.   } ifelse
  466.  
  467.   % Preprocess entries :
  468.   dup NewCategory /.PreprocessRecord get       % <<map>> <<map>> <<pr>>
  469.   3 1 roll {                                   % <<pr>> <<map>> /Name raw_record
  470.     false 3 1 roll                             % <<pr>> <<map>> false /Name raw_record 
  471.     4 index {                                  % <<pr>> <<map>> false /Name raw_record i {pr}
  472.       exch pop                                 % <<pr>> <<map>> false /Name raw_record {pr}
  473.       exec {                                   % <<pr>> <<map>> false /Name record
  474.         3 -1 roll pop true 3 1 roll            % <<pr>> <<map>> true /Name record
  475.         exit
  476.       } if                                     % <<pr>> <<map>> false /Name raw_record
  477.     } forall
  478.     3 2 roll {                                 % <<pr>> <<map>> /Name record
  479.       2 index 3 1 roll put                     % <<pr>> <<map>>
  480.     } {
  481.       exch                                     % <<pr>> <<map>> raw_record /Name
  482.       (Incorrect record ) print =string cvs print ( of the map file ) print MapFileName =string cvs print (.) =
  483.       end % Pops OptionsDict from dstack.
  484.       pop pop pop                              %
  485.       /Redefine cvx /undefinedresource signalerror
  486.     } ifelse
  487.   } forall                                     % <<pr>> <<map>>
  488.   exch pop                                     % <<map>>
  489.  
  490.  
  491.   % Add the map :
  492.   OldCategory /.IsRedefinedWithMap known {     % <<map>>
  493.     % Just add to the old map :
  494.     OldCategory /.map get copy pop             %
  495.   } {                                          % <<map>>
  496.     % Store the map to both the category and OptionsDict :
  497.     dup NewCategory exch /.map exch put
  498.     /.map exch def                             %
  499.   } ifelse
  500.   OldCategory /.IsRedefinedWithMap known not {
  501.     % Copy old methods to OptionsDict :
  502.     [ /DefineResource /ResourceStatus /ResourceFileName 
  503.       /FindResource /ResourceForAll
  504.     ] {
  505.       dup OldCategory exch get def
  506.     } forall
  507.     
  508.     % Build new methods :
  509.     //MethodsToRedefine {
  510.       //BindWithCurrentdict exec NewCategory 3 1 roll put  
  511.     } forall
  512.     CategoryName /CIDFont ne {
  513.       NewCategory /GetCIDSystemInfoFromMap undef
  514.       % This is some ugly, sorry.
  515.     } if
  516.     % Redefine the category :
  517.     NewCategory /.IsRedefinedWithMap true put
  518.     CategoryName NewCategory /Category defineresource pop
  519.   } if
  520.   end % OptionsDict
  521. } bind executeonly def
  522.  
  523. currentdict /PutPreprocessRecord .undef
  524.  
  525. currentdict end
  526. /ProcSet defineresource pop
  527.  
  528. setglobal .setlanguagelevel
  529.