% Copyright (C) 2001-2023 Artifex Software, Inc.
% All Rights Reserved.
%
% This software is provided AS-IS with no warranty, either express or
% implied.
%
% This software is distributed under license and may not be copied,
% modified or distributed except as expressly authorized under the terms
% of the license contained in the file LICENSE in this distribution.
%
% Refer to licensing information at http://www.artifex.com or contact
% Artifex Software, Inc.,  39 Mesa Street, Suite 108A, San Francisco,
% CA 94129, USA, for further information.
%

% Initialization file for Level 2 resource machinery.
% When this is run, systemdict is still writable,
% but (almost) everything defined here goes into level2dict.

level2dict begin

(BEGIN RESOURCES) VMDEBUG

% We keep track of (global) instances with another entry in the resource
% dictionary, an .Instances dictionary.  For categories with implicit
% instances, the values in .Instances are the same as the keys;
% for other categories, the values are [instance status size].

% Note that the dictionary that defines a resource category is stored
% in global VM.  The PostScript manual says that each category must
% manage global and local instances separately.  However, objects in
% global VM other than systemdict can't reference objects in local VM.
% This means that the resource category dictionary, which would otherwise be
% the obvious place to keep track of the instances, can't be used to keep
% track of local instances.  Instead, we define a dictionary in local VM
% called localinstancedict, in which the key is the category name and
% the value is the analogue of .Instances for local instances.

% We don't currently implement automatic resource unloading.
% When and if we do, it should be hooked to the garbage collector.
% However, Ed Taft of Adobe says their interpreters don't implement this
% either, so we aren't going to worry about it for a while.

currentglobal //false setglobal
  systemdict /localinstancedict 5 dict
  .forceput	% localinstancedict is local, systemdict is global
//true setglobal
/.emptydict 0 dict readonly def
setglobal

% Resource category dictionaries have the following keys (those marked with
% * are optional):
%	Standard, defined in the Red Book:
%		Category (name)
%		*InstanceType (name)
%		DefineResource
%			<key> <instance> DefineResource <instance>
%		UndefineResource
%			<key> UndefineResource -
%		FindResource
%			<key> FindResource <instance>
%		ResourceStatus
%			<key> ResourceStatus <status> <size> true
%			<key> ResourceStatus false
%		ResourceForAll
%			<template> <proc> <scratch> ResourceForAll -
%		*ResourceFileName
%			<key> <scratch> ResourceFileName <filename>
%	Additional, specific to our implementation:
%		.Instances (dictionary)
%		.LocalInstances
%			- .LocalInstances <dict>
%		.GetInstance
%			<key> .GetInstance <instance> -true-
%			<key> .GetInstance -false-
%		.CheckResource
%			<key> <value> .CheckResource <key> <value> <ok>
%			  (or may give an error if not OK)
%		.DoLoadResource
%			<key> .DoLoadResource <key> (may give an error)
%		.LoadResource
%			<key> .LoadResource - (may give an error)
%		.ResourceFile
%			<key> .ResourceFile <file> -true-
%			<key> .ResourceFile <key> -false-
%		.ResourceFileStatus
%			<key> .ResourceFileStatus 2 <vmusage> -true-
%			<key> .ResourceFileStatus -false-
% All the above procedures expect that the top dictionary on the d-stack
% is the resource dictionary.

% Define enough of the Category category so we can define other categories.
% The dictionary we're about to create will become the Category
% category definition dictionary.

% .findcategory and .resourceexec are only called from within the
% implementation of the resource 'operators', so they don't have to worry
% about cleaning up the stack if they fail (the interpreter's stack
% protection machinery for pseudo-operators takes care of this).
% Note that all places that look up categories must use .findcategory
% so that the command in case of error will be correct rather than an
% internal invocation of findresource.
/.findcategory {	% <name> .findcategory -
                        %   (pushes the category on the dstack)
    /Category .findresource begin	% note: *not* findresource
} .internalbind def

% If an error occurs within the logic of a resource operator (after operand
% acquisition and checking), the Adobe interpreters report the operator name,
% not the operator object, as the command in $error.  For this reason, and
% this reason only, all resource operators must wrap their logic code in
%	/<opername> cvx { ...logic... } .errorexec

% The Category resource signals /undefined rather than /undefinedresource,
% both when referenced implicitly (to look up the category for a general
% resource operation) and when it is accessed directly (/Category /xxx
% findresource).  Because of this, all resource operators must use
% .undefinedresource rather than signalling undefinedresource directly.
/.undefinedresource {	% <command> .undefinedresource -
    /Category dup load eq { /undefined } { /undefinedresource } ifelse
    signaloperror
} .internalbind def

/.resourceexec {	% <key> /xxxResource .resourceexec -
                        %   (also pops the category from the dstack)
  load exec end
} .internalbind def

% .getvminstance treats instances on disk as undefined.
/.getvminstance {	% <key> .getvminstance <instance> -true-
                        % <key> .getvminstance -false-
  .GetInstance {
    dup 1 get 2 ne { //true } { pop //false } ifelse
  } {
    //false
  } ifelse
} .internalbind def

20 dict begin

                % Standard entries

/Category /Category def
/InstanceType /dicttype def

/DefineResource {
        .CheckResource {
          dup /Category 3 index cvlit .growput
          dup [ exch 0 -1 ] exch
          .Instances 4 2 roll put
                % Make the Category dictionary read-only.  We will have to
                % use .forceput / .forceput later to replace the dummy,
                % empty .Instances dictionary with the real one later.
          readonly
        }{
          /defineresource cvx /typecheck signaloperror
        } ifelse
} .internalbind odef
/FindResource		% (redefined below)
        { .Instances exch get 0 get
        } .internalbind def

                % Additional entries

/.Instances 30 dict def
.Instances /Category [currentdict 0 -1] put

/.LocalInstances 0 dict def
/.GetInstance
        { .Instances exch .knownget
        } .internalbind def
/.CheckResource
        { dup gcheck currentglobal and
           { /DefineResource /FindResource /ResourceForAll /ResourceStatus
             /UndefineResource }
           { 2 index exch known and }
          forall
          not { /defineresource cvx /invalidaccess signaloperror } if
          //true
        } .internalbind def

.Instances end begin	% for the base case of findresource

(END CATEGORY) VMDEBUG

% Define the resource operators.  We use the "stack protection" feature of
% odef to make sure the stacks are restored properly on an error.
% This requires that the operators not pop anything from the stack until
% they have executed their logic successfully.  We can't make this
% work for resourceforall, because the procedure it executes mustn't see
% the operands of resourceforall on the stack, but we can make it work for
% the others.

% findresource is the only operator that needs to bind //Category.
% We define its contents as a separate procedure so that .findcategory
% can use it without entering another level of pseudo-operator.
/.findresource {		% <key> <category> findresource <instance>
        2 copy dup /Category eq
          { pop //Category 0 get begin } { //.findcategory exec } ifelse
        /FindResource //.resourceexec exec exch pop exch pop
} .internalbind
end		% .Instances of Category
def
/findresource {
    % See above re .errorexec.
    1 .argindex 	% also catch stackunderflow
    dup type /stringtype eq { cvn } if  % for CET 23-13-04
    3 1 roll exch pop
    dup type /nametype ne {
      /findresource .systemvar /typecheck signalerror
    } if
    /findresource cvx //.findresource .errorexec
} .internalbind odef

/defineresource {	% <key> <instance> <category> defineresource <instance>
    2 .argindex 2 index 2 index	% catch stackunderflow
    % See above re .errorexec.
    /defineresource cvx {
        //.findcategory exec
        currentdict /InstanceType known {
          dup type InstanceType ne {
            dup type /packedarraytype eq InstanceType /arraytype eq and
            not { /defineresource cvx /typecheck signaloperror } if
          } if
        } if
        /DefineResource //.resourceexec exec
        4 1 roll pop pop pop
    } .errorexec
} .internalbind odef
% We must prevent resourceforall from automatically restoring the stacks,
% because we don't want the stacks restored if proc causes an error or
% executes a 'stop'. On the other hand, resourceforall is defined in the
% PLRM as an operator, so it must have type /operatortype.  We hack this
% by taking advantage of the fact that the interpreter optimizes tail
% calls, so stack protection doesn't apply to the very last token of an
% operator procedure.
/resourceforall1 {	% <template> <proc> <scratch> <category> resourceforall1 -
        dup //.findcategory exec
        /ResourceForAll load
        % Stack: <template> <proc> <scratch> <category> proc
        exch pop		% pop the category
        exec end
} .forcebind def
/resourceforall {	% <template> <proc> <scratch> <category> resourceforall1 -
        //resourceforall1 exec		% see above
} .forcebind odef
/resourcestatus {	% <key> <category> resourcestatus <status> <size> true
                        % <key> <category> resourcestatus false
  {
    0 .argindex type /nametype ne {
      % CET 23-26 wants typecheck here, not undefineresource that happens
      % without the check.
      /resourcestatus cvx /typecheck signalerror
    } if
    2 copy //.findcategory exec /ResourceStatus //.resourceexec exec
    { 4 2 roll pop pop //true } { pop pop //false } ifelse
  } stopped {
    % Although resourcestatus is an operator, Adobe uses executable name
    % for error reporting. CET 23-26
    /resourcestatus cvx $error /errorname get signalerror
  } if
} .forcebind odef
/undefineresource {	% <key> <category> undefineresource -
  0 .argindex type /nametype ne {
    /undefinedresource cvx /typecheck signaloperror
  } if
  1 .argindex 1 index		% catch stackunderflow

  { //.findcategory exec /UndefineResource //.resourceexec exec pop pop
  } stopped {
    % Although undefineresource is an operator, Adobe uses executable name
    % here but uses operator for the errors above. CET 23-33
    /undefineresource cvx $error /errorname get signalerror
  } if
} .forcebind odef

% Define the system parameters used for the Generic implementation of
% ResourceFileName.
systemdict begin

%     - .default_resource_dir <string>
/.default_resource_dir {
  /LIBPATH .systemvar {
    dup .file_name_current eq {
      pop
    } {
      (Resource) rsearch {
        exch concatstrings
        exch pop
        .file_name_separator concatstrings exit
      } {
        pop
      } ifelse
    } ifelse
  } forall
} .internalbind def

%  <path> <name> <string> .resource_dir_name <path> <name> <string>
/.resource_dir_name
{  systemdict 2 index .knownget {
     exch pop
     systemdict 1 index undef
   } {
     dup () ne {
     .file_name_directory_separator concatstrings
    } if
    2 index exch //false
    .file_name_combine not {
      (Error: .default_resource_dir returned ) print exch print ( that can't combine with ) print =
      /.default_resource_dir cvx /configurationerror signalerror
    } if
  } ifelse
} .internalbind def

currentdict /pssystemparams known not {
  /pssystemparams 10 dict readonly def
} if
pssystemparams begin
  //.default_resource_dir exec
  /FontResourceDir (Font) //.resource_dir_name exec
     readonly currentdict 3 1 roll .forceput	% pssys'params is r-o
  /GenericResourceDir () //.resource_dir_name exec
     readonly currentdict 3 1 roll .forceput	% pssys'params is r-o
  pop % .default_resource_dir
  /GenericResourcePathSep
        .file_name_separator readonly currentdict 3 1 roll .forceput		% pssys'params is r-o
  currentdict (%diskFontResourceDir) cvn (/Resource/Font/) readonly .forceput	% pssys'params is r-o
  currentdict (%diskGenericResourceDir) cvn (/Resource/) readonly .forceput	% pssys'params is r-o
end
end

% Check if GenericResourceDir presents in LIBPATH.

% The value of GenericResourceDir must end with directory separator.
% We use .file_name_combine to check it.
% Comments use OpenVMS syntax, because it is the most complicated case.
(x) pssystemparams /GenericResourcePathSep get
(y) concatstrings concatstrings dup length              % (x]y) l1
pssystemparams /GenericResourceDir get dup length exch  % (x]y) l1 l2 (dir)
3 index //true .file_name_combine not {
  exch
  (File name ) print print ( cant combine with ) print =
  /GenericResourceDir cvx /configurationerror signaloperror
} if
dup length                                              % (x]y) l1 l2 (dir.x]y) l
4 2 roll add                                            % (x]y) (dir.x]y) l ll
ne {
  (GenericResourceDir value does not end with directory separator.\n) =
  /GenericResourceDir cvx /configurationerror signaloperror
} if
pop pop

pssystemparams dup /GenericResourceDir get exch /GenericResourcePathSep get
(Init) exch (gs_init.ps) concatstrings concatstrings concatstrings
status {
  pop pop pop pop
} {
  (\n*** Warning: GenericResourceDir doesn't point to a valid resource directory.) =
  (               the -sGenericResourceDir=... option can be used to set this.\n) =
  flush
} ifelse

% Define the generic algorithm for computing resource file names.
/.rfnstring 8192 string def
/.genericrfn		% <key> <scratch> <prefix> .genericrfn <filename>
 { 3 -1 roll //.rfnstring cvs concatstrings exch copy
 } .internalbind def

% Define the Generic category.

/Generic mark

                % Standard entries

% We're still running in Level 1 mode, so dictionaries won't expand.
% Leave room for the /Category entry.
/Category //null

% Implement the body of Generic resourceforall for local, global, and
% external cases.  'args' is [template proc scratch resdict].
/.enumerateresource {	% <key> [- <proc> <scratch>] .enumerateresource -
  1 index type dup /stringtype eq exch /nametype eq or {
    exch 1 index 2 get cvs exch
  } if
        % Use .setstackprotect to prevent the stacks from being restored if
        % an error occurs during execution of proc.
  1 get //false .setstackprotect exec //true .setstackprotect
} .internalbind def
/.localresourceforall {		% <key> <value> <args> .localr'forall -
  exch pop
  2 copy 0 get .stringmatch { //.enumerateresource exec } { pop pop } ifelse
} .internalbind def
/.globalresourceforall {	% <key> <value> <args> .globalr'forall -
  exch pop
  2 copy 0 get .stringmatch {
    dup 3 get begin .LocalInstances end 2 index known not {
      //.enumerateresource exec
    } {
      pop pop
    } ifelse
  } {
    pop pop
  } ifelse
} .internalbind def
/.externalresourceforall {	% <filename> <len> <args> .externalr'forall -
  3 1 roll 1 index length 1 index sub getinterval exch
  dup 3 get begin .Instances .LocalInstances end
                % Stack: key args insts localinsts
  3 index known {
    pop pop pop
  } {
    2 index known { pop pop } { //.enumerateresource exec } ifelse
  } ifelse
} .internalbind def

/DefineResource dup {
        .CheckResource
           { dup [ exch 0 -1 ]
                        % Stack: key value instance
             currentglobal
              { //false setglobal 2 index UndefineResource	% remove local def if any
                //true setglobal
                .Instances dup //.emptydict eq {
                  pop 3 dict
                        % As noted above, Category dictionaries are read-only,
                        % so we have to use .forceput here.
                  currentdict /.Instances 2 index .forceput	% Category dict is read-only
                } executeonly if
              } executeonly
              { .LocalInstances dup //.emptydict eq
                 { pop 3 dict localinstancedict Category 2 index put
                 }
                if
              }
             ifelse
                        % Stack: key value instance instancedict
             3 index 2 index .growput
                        % Now make the resource value read-only.
             0 2 copy get { readonly } //.internalstopped exec pop
             dup 4 1 roll put exch pop exch pop
           } executeonly
           { /defineresource cvx /typecheck signaloperror
           }
        ifelse
} .forcebind .makeoperator		% executeonly to prevent access to .forceput
/UndefineResource
        {  { dup 2 index .knownget
              { dup 1 get 1 ge
                 { dup 0 //null put 1 2 put pop pop }
                 { pop exch .undef }
                ifelse
              }
              { pop pop
              }
             ifelse
           }
          currentglobal
           { 2 copy .Instances exch exec
           }
          if .LocalInstances exch exec
        } .forcebind
% Because of some badly designed code in Adobe's CID font downloader that
% makes findresource and resourcestatus deliberately inconsistent with each
% other, the default FindResource must not call ResourceStatus if there is
% an instance of the desired name already defined in VM.
/FindResource {
        dup //null eq {
          % CET 13-06 wants /typecheck for "null findencoding" but
          % .knownget doesn't fail on null
          /findresource cvx /typecheck signaloperror
        } if
        dup //.getvminstance exec {
          exch pop 0 get
        } {
          dup ResourceStatus {
            pop 1 gt {
              .DoLoadResource //.getvminstance exec not {
                /findresource cvx //.undefinedresource exec
              } if 0 get
            } {
              .GetInstance pop 0 get
            } ifelse
          } {
           /findresource cvx //.undefinedresource exec
          } ifelse
        } ifelse
} .forcebind
% Because of some badly designed code in Adobe's CID font downloader, the
% definition of ResourceStatus for Generic and Font must be the same (!).
% We patch around this by using an intermediate .ResourceFileStatus procedure.
/ResourceStatus {
        dup .GetInstance {
          exch pop dup 1 get exch 2 get //true
        } {
          .ResourceFileStatus
        } ifelse
} .forcebind
/.ResourceFileStatus {
        .ResourceFile { closefile 2 -1 //true } { pop //false } ifelse
} .internalbind
/ResourceForAll {
                % Construct a new procedure to hold the arguments.
                % All objects constructed here must be in local VM to avoid
                % a possible invalidaccess.
        currentdict 4 .localvmpackedarray	% [template proc scratch resdict]
                % We must pop the resource dictionary off the dict stack
                % when doing the actual iteration, and restore it afterwards.
        .currentglobal not {
          .LocalInstances length 0 ne {
                % We must do local instances, and do them first.
            //.localresourceforall {exec} 0 get 3 .localvmpackedarray cvx
            .LocalInstances exch {forall} 0 get 1 index 0 get
            currentdict end 3 .execn begin
          } if
        } if
                % Do global instances next.
        //.globalresourceforall {exec} 0 get 3 .localvmpackedarray cvx
        .Instances exch cvx {forall} 0 get 1 index 0 get
        currentdict end 3 .execn begin
        mark                                             % args [
        Category .namestring .file_name_separator concatstrings
        2 index 0 get                                    % args [ (c/) (t)
        1 index length 3 1 roll                          % args [ l (c/) (t)
        concatstrings                                    % args [ l (c/t)
        [
          //true /LIBPATH .systemvar 3 index
          .generate_dir_list_templates_with_length       % args (t) [ l [(pt) Lp ...]
            % also add on the Resources as specified by the GenericResourceDir
          //true [ currentsystemparams /GenericResourceDir get]
          counttomark 1 add index .generate_dir_list_templates_with_length
          ] exch pop
        dup length 1 sub 0 exch 2 exch {                 % args [ l [] i
          2 copy get                                     % args [ l [] i (pt)
          exch 2 index exch 1 add get                    % args [ l [] (pt) Lp
          3 index add
          exch                                           % args [ l [] Lp (pt)

          {                                              % args [ l [] Lp (pf)
            dup length                                   % args [ l [] Lp (pf) Lpf
            2 index sub                                  % args [ l [] Lp (pf) Lf
            2 index exch                                 % args [ l [] Lp (pf) Lp Lf
            getinterval cvn dup                          % args [ l [] Lp /n /n
            5 2 roll                                     % args [ /n /n l [] Lp
          } //.rfnstring filenameforall
          pop                                            % args [ /n1 /n1 ... /nN /nN l []
        } for                                            % args [ /n1 /n1 ... /nN /nN l []
        pop pop
        .dicttomark % An easy way to exclude duplicates. % args <</n/n>>
          % {
          { pop } 0 get
          2 index 2 get { cvs 0 } aload pop 5 index
          //.externalresourceforall {exec} 0 get
          % }
        7 .localvmpackedarray cvx
        3 2 roll pop % args
        { forall } 0 get
        currentdict end 2 .execn begin
} .forcebind

/ResourceFileName  {                          % /in (scr) --> (p/c/n)
  exch //.rfnstring cvs                       % (scr) (n)
  /GenericResourcePathSep getsystemparam exch % (scr) (/) (n)
  Category .namestring                        % (scr) (/) (n) (c)
  3 1 roll                                    % (scr) (c) (/) (n)
  concatstrings concatstrings                 % (scr) (c/n)
  /GenericResourceDir getsystemparam 1 index  % (scr) (c/n) (p/) (c/n)
  concatstrings                               % (scr) (c/n) (p/c/n)
  dup status {
    pop pop pop pop exch pop                  % (scr) (p/c/n)
  } {
    exch
    .libfile
    {//true}
    {
      pop dup .libfile
      {//true}
      {//false}
      ifelse
    } ifelse

    {
      dup .filename pop
      exch closefile
      exch pop
    }
    {pop}
    ifelse
  } ifelse
  exch copy                                   % (p/c/n)
} .forcebind

                % Additional entries

% Unfortunately, we can't create the real .Instances dictionary now,
% because if someone copies the Generic category (which pp. 95-96 of the
% 2nd Edition Red Book says is legitimate), they'll wind up sharing
% the .Instances.  Instead, we have to create .Instances on demand,
% just like the entry in localinstancedict.
% We also have to prevent anyone from creating instances of Generic itself.
/.Instances //.emptydict

/.LocalInstances
        { localinstancedict Category .knownget not { //.emptydict } if
        } .internalbind
/.GetInstance
        { currentglobal
           { .Instances exch .knownget }
           { .LocalInstances 1 index .knownget
              { exch pop //true }
              { .Instances exch .knownget }
             ifelse
           }
          ifelse
        } .internalbind
/.CheckResource
        { //true
        } .internalbind
/.vmused {
                % - .vmused <usedvalue>
                % usedvalue = vmstatus in global + vmstatus in local.
  0 2 {
    .currentglobal not .setglobal
    vmstatus pop exch pop add
  } repeat
} .internalbind odef
/.DoLoadResource {
                % .LoadResource may push entries on the operand stack.
                % It is an undocumented feature of Adobe implementations,
                % which we must match for the sake of some badly written
                % font downloading code, that such entries are popped
                % automatically.
        count 1 index cvlit //.vmused
                % Stack: key count litkey memused
        {.LoadResource} 4 1 roll 4 .execn
                % Stack: ... count key memused
        //.vmused exch sub
        1 index //.getvminstance exec not {
          pop dup //.undefinedresource exec	% didn't load
        } if
        dup 1 1 put
        2 3 -1 roll put
                % Stack: ... count key
        exch count 1 sub exch sub {exch pop} repeat
} .internalbind
/.LoadResource
        { dup .ResourceFile
           { exch pop currentglobal
              { //.runresource exec }
              { //true setglobal { //.runresource exec } stopped //false setglobal { stop } if }
             ifelse
           }
           { dup //.undefinedresource exec
           }
         ifelse
        } .internalbind
/.ResourceFile
        {
          Category //.rfnstring cvs length                      % key l
          dup //.rfnstring dup length 2 index sub               % key l l (buf) L-l
          3 2 roll exch getinterval                             % key l ()
          .file_name_directory_separator exch copy length add   % key l1
          dup //.rfnstring dup length 2 index sub               % key l1 l1 (buf) L-l
          3 2 roll exch getinterval                             % key l1 ()
          2 index exch cvs length add                           % key l2
          //.rfnstring exch 0 exch getinterval                  % key (relative_path)
          .libfile {
            exch pop //true
          } {
            pop
            currentdict /ResourceFileName known {
              mark 1 index //.rfnstring { ResourceFileName } //.internalstopped exec {
                cleartomark //false
              } {
                (r) { file } //.internalstopped exec {
                  cleartomark //false
                } {
                  exch pop exch pop //true
                } ifelse
              } ifelse
             } {
               pop //false
             } ifelse
          } ifelse
        } .internalbind

.dicttomark
/Category defineresource pop

% Fill in the rest of the Category category.
/Category /Category findresource dup
/Generic /Category findresource begin {
  /FindResource /ResourceForAll /ResourceStatus /.ResourceFileStatus
  /UndefineResource /ResourceFileName
  /.ResourceFile /.LoadResource /.DoLoadResource
} { dup load put dup } forall
pop readonly pop end

(END GENERIC) VMDEBUG

% Define the fixed categories.

mark
        % Non-Type categories with existing entries.
 /ColorSpaceFamily
   { }	% These must be deferred, because optional features may add some.
 /Emulator
   mark EMULATORS { <00> search { exch pop cvn exch }{ cvn exit } ifelse } .forcebind loop //.packtomark exec
 /Filter
   { }	% These must be deferred, because optional features may add some.
 /IODevice
        % Loop until the .getiodevice gets a rangecheck.
   errordict /rangecheck 2 copy get
   errordict /rangecheck { pop stop } put	% pop the command
   mark 0 { {
    dup .getiodevice dup //null eq { pop } { exch } ifelse 1 add
   } loop} //.internalstopped exec
   pop pop pop //.packtomark exec
   4 1 roll put
   //.clearerror exec
        % Type categories listed in the Red Book.
 /ColorRenderingType
   { }	% These must be deferred, because optional features may add some.
 /FMapType
   { }	% These must be deferred, because optional features may add some.
 /FontType
   { }	% These must be deferred, because optional features may add some.
 /FormType
   { }	% These must be deferred, because optional features may add some.
 /HalftoneType
   { }	% These must be deferred, because optional features may add some.
 /ImageType
   { }	% Deferred, optional features may add some.
 /PatternType
   { }  % Deferred, optional features may add some.
        % Type categories added since the Red Book.
 /setsmoothness where {
   pop /ShadingType { }	% Deferred, optional features may add some.
 } if
counttomark 2 idiv
 { mark

                % Standard entries

                % We'd like to prohibit defineresource,
                % but because optional features may add entries, we can't.
                % We can at least require that the key and value match.
   /DefineResource
        { currentglobal not
           { /defineresource cvx /invalidaccess signaloperror }
           { 2 copy ne
              { /defineresource cvx /rangecheck signaloperror }
              { dup .Instances 4 -2 roll .growput }
             ifelse
           }
          ifelse
        } .internalbind
   /UndefineResource
        { /undefineresource cvx /invalidaccess signaloperror } .internalbind
   /FindResource
        { .Instances 1 index .knownget
           { exch pop }
           { /findresource cvx //.undefinedresource exec }
          ifelse
        } .internalbind
   /ResourceStatus
        { .Instances exch known { 0 0 //true } { //false } ifelse } .internalbind
   /ResourceForAll
        /Generic //.findcategory exec /ResourceForAll load end

                % Additional entries

   counttomark 2 add -1 roll
   dup length dict dup begin exch { dup def } forall end
                % We'd like to make the .Instances readonly here,
                % but because optional features may add entries, we can't.
   /.Instances exch
   /.LocalInstances	% used by ResourceForAll
        0 dict def

   .dicttomark /Category defineresource pop
 } repeat pop

(END FIXED) VMDEBUG

% Define the other built-in categories.

/.definecategory	% <name> -mark- <key1> ... <valuen> .definecategory -
 { counttomark 2 idiv 2 add		% .Instances, Category
   /Generic /Category findresource dup maxlength 3 -1 roll add
   dict .copydict begin
   counttomark 2 idiv { def } repeat pop	% pop the mark
   currentdict end /Category defineresource pop
 } .internalbind def

/ColorRendering mark /InstanceType /dicttype .definecategory
% ColorSpace is defined below
% Encoding is defined below
% Font is defined below
/Form mark /InstanceType /dicttype .definecategory
/Halftone mark /InstanceType /dicttype .definecategory
/Pattern mark /InstanceType /dicttype .definecategory
/ProcSet mark /InstanceType /dicttype .definecategory
% Added since the Red Book:
/ControlLanguage mark /InstanceType /dicttype .definecategory
/HWOptions mark /InstanceType /dicttype .definecategory
/Localization mark /InstanceType /dicttype .definecategory
/PDL mark /InstanceType /dicttype .definecategory
% CIDFont, CIDMap, and CMap are defined in gs_cidfn.ps
% FontSet is defined in gs_cff.ps
% IdiomSet is defined in gs_ll3.ps
% InkParams and TrapParams are defined in gs_trap.ps

(END MISC) VMDEBUG

% Define the OutputDevice category.
/OutputDevice mark
/InstanceType /dicttype
/.Instances mark
%% devicedict is not created yet so here we employ a technique similar to
%% that used to create it, in order to get the device names. We run a loop
%% executing .getdevice with incremental numbers until we get an error.
%% The devicedict creation only stops on a rangecheck, we stop on any error.
%% We need to use .internalstopped, not stopped or we get an invalidacces
%% later in this file. Instances of /OutputDevice are dictionaries, and the
%% only required key is a /PageSize. The array of 4 numbers are minimum to
%% maximum and are matches for the Adobe Acrobat Distiller values.
0
{
  {dup .getdevice .devicename cvn 1 dict dup /PageSize [1 1 14400 14400] put [exch readonly 0 -1] 3 -1 roll 1 add} loop
} //.internalstopped exec pop
%% Remove the count, and the duplicate, from the stack
pop pop
.dicttomark
.definecategory

% Define the ColorSpace category.

/.defaultcsnames mark
  /DefaultGray 0
  /DefaultRGB 1
  /DefaultCMYK 2
.dicttomark readonly def

% The "hooks" are no-ops here, redefined in LL3.
/.definedefaultcs {	% <index> <value> .definedefaultcs -
  pop pop
} .internalbind def
/.undefinedefaultcs {	% <index> .undefinedefaultcs -
  pop
} .internalbind def

/ColorSpace mark

/InstanceType /arraytype

% We keep track of whether there are any local definitions for any of
% the Default keys.  This information must get saved and restored in
% parallel with the local instance dictionary, so it must be stored in
% local VM.
userdict /.localcsdefaults //false put

/DefineResource {
  2 copy /Generic /Category findresource /DefineResource get exec
  exch pop
  exch //.defaultcsnames exch .knownget {
    1 index //.definedefaultcs exec
    currentglobal not { .userdict /.localcsdefaults //true put } if
  } if
} .internalbind

/UndefineResource {
  dup /Generic /Category findresource /UndefineResource get exec
  //.defaultcsnames 1 index .knownget {
        % Stack: resname index
    currentglobal {
      //.undefinedefaultcs exec pop
    } {
        % We removed the local definition, but there might be a global one.
      exch .GetInstance {
        0 get //.definedefaultcs exec
      } {
        //.undefinedefaultcs exec
      } ifelse
        % Recompute .localcsdefaults by scanning.  This is rarely needed.
      .userdict /.localcsdefaults //false //.defaultcsnames {
        pop .LocalInstances exch known { pop //true exit } if
      } forall put
    } ifelse
  } {
    pop
  } ifelse
} .internalbind

.definecategory			% ColorSpace

% Define the Encoding category.

/Encoding mark

/InstanceType /arraytype

% Handle already-registered encodings, including lazily loaded encodings
% that aren't loaded yet.

/.Instances mark
  EncodingDirectory
   {dup length 256 eq { [ exch readonly 0 -1 ] } { pop [//null 2 -1] } ifelse
   } forall
.dicttomark

/.ResourceFileDict mark
  EncodingDirectory
   { dup length 256 eq { pop pop } { 0 get } ifelse
   } forall
.dicttomark

/ResourceFileName
 { .ResourceFileDict 2 index .knownget
    { exch copy exch pop }
    { /Generic /Category findresource /ResourceFileName get exec }
   ifelse
 } .internalbind

.definecategory			% Encoding

% Make placeholders in level2dict for the redefined Encoding operators,
% so that they will be swapped properly when we switch language levels.

/.findencoding /.findencoding load def
/findencoding /findencoding load def
/.defineencoding /.defineencoding load def

(END ENCODING) VMDEBUG

% Define the Font category.

/.fontstatusaux {		% <fontname> .fontstatusaux <fontname> <found>
  {		% Create a loop context just so we can exit it early.
                % Check Fontmap.
    Fontmap 1 index .knownget
    { //true }
    { .nativeFontmap 1 index .knownget } ifelse

    {
      {
        dup type /nametype eq {
          .fontstatus { pop //null exit } if
        } {
          dup type /dicttype eq {/Path .knownget pop} if
          dup type /stringtype eq {
            findlibfile { closefile pop //null exit } if pop
          } {
                % Procedure, assume success.
            pop //null exit
          } ifelse
        } ifelse
      } forall dup //null eq { pop //true exit } if
    } if


    dup / eq { //false exit } if  % / throws an error from findlibfile
                % Convert names to strings; give up on other types.
    dup type /nametype eq { .namestring } if
    dup type /stringtype ne { //false exit } if
                % Check the resource directory.
    dup //.fonttempstring /FontResourceDir getsystemparam .genericrfn
    status {
      pop pop pop pop //true exit
    } if
                % Check for a file on the search path with the same name
                % as the font.
    findlibfile { closefile //true exit } if
                % Scan a FONTPATH directory and try again.
    //.scannextfontdir exec not { //false exit } if
  } loop
} .internalbind def

/.fontstatus {		% <fontname> .fontstatus <fontname> <found>
  //.fontstatusaux exec
  { //true }
  {
    .buildnativefontmap
    { //.fontstatusaux exec }
    { //false } ifelse
  } ifelse
} .internalbind def
currentdict /.fontstatusaux .undef

/Font mark

/InstanceType /dicttype

/DefineResource
        { 2 copy //definefont exch pop
          /Generic /Category findresource /DefineResource get exec
        } .internalbind
/UndefineResource
        { dup //undefinefont
          /Generic /Category findresource /UndefineResource get exec
        } .internalbind
/FindResource {
        dup //.getvminstance exec {
          exch pop 0 get
        } {
          dup ResourceStatus {
            pop 1 gt { .loadfontresource } { .GetInstance pop 0 get } ifelse
          } {
            .loadfontresource
          } ifelse
        } ifelse
} .internalbind
/ResourceForAll {
        { //.scannextfontdir exec not { exit } if } loop
        /Generic /Category findresource /ResourceForAll get exec
} .forcebind
/.ResourceFileStatus {
        .fontstatus { pop 2 -1 //true } { pop //false } ifelse
} .internalbind

/.loadfontresource {
        dup //.vmused exch
                % Hack: rebind .currentresourcefile so that all calls of
                % definefont will know these are built-in fonts.
        currentfile {pop //findfont exec} .execasresource  % (findfont is a procedure)
        exch //.vmused exch sub
                % stack: name font vmused
                % findfont has the prerogative of not calling definefont
                % in certain obscure cases of font substitution.
        2 index //.getvminstance exec {
          dup 1 1 put
          2 3 -1 roll put
        } {
          pop
        } ifelse exch pop
} systemdict /CETMODE .knownget not {//false} if {.bind}{.internalbind}ifelse

/.Instances FontDirectory length 2 mul dict

.definecategory			% Font

% Redefine font "operators".
/.definefontmap
 { /Font /Category findresource /.Instances get
   dup 3 index known
    { pop
    }
    { 2 index
                % Make sure we create the array in global VM.
      .currentglobal //true .setglobal
      [//null 2 -1] exch .setglobal
      .growput
    }
   ifelse
   //.definefontmap exec
 } .internalbind def

/definefont {
  { /Font defineresource } stopped {
      /definefont cvx $error /errorname get signalerror
  } if
} .internalbind odef
/undefinefont {
  /Font undefineresource
} .internalbind odef
% The Red Book requires that findfont be a procedure, not an operator,
% but it still needs to restore the stacks reliably if it fails.
/.findfontop {
  { /Font findresource } stopped {
    pop /findfont cvx $error /errorname get signalerror
  } if
} .internalbind odef
/findfont {
  .findfontop
} .internalbind def	% Must be a procedure, not an operator

% Remove initialization utilities.
currentdict /.definecategory .undef
currentdict /.emptydict .undef

end				% level2dict

% Convert deferred resources after we finally switch to Level 2.

/.fixresources {
        % Encoding resources
  EncodingDirectory
   { dup length 256 eq
      { /Encoding defineresource pop }
      { pop pop }
     ifelse
   } forall
  /.findencoding {
    { /Encoding findresource } stopped {
      pop /findencoding cvx $error /errorname get signalerror
    } if
  } .internalbind def
  /findencoding /.findencoding load def		% must be a procedure
  /.defineencoding { /Encoding defineresource pop } .internalbind def
        % ColorRendering resources and ProcSet
  systemdict /ColorRendering .knownget {
    /ColorRendering exch /ProcSet defineresource pop
    systemdict /ColorRendering undef
    /DefaultColorRendering currentcolorrendering /ColorRendering defineresource pop
  } if
        % ColorSpace resources
  systemdict /CIEsRGB .knownget {
    /sRGB exch /ColorSpace defineresource pop
    systemdict /CIEsRGB undef
  } if
  systemdict /CIEsRGBICC .knownget {
    /sRGBICC exch /ColorSpace defineresource pop
    systemdict /CIEsRGBICC undef
  } if
  systemdict /CIEsGRAYICC .knownget {
    /sGrayICC exch /ColorSpace defineresource pop
    systemdict /CIEsGRAYICC undef
  } if
  systemdict /CIEesRGBICC .knownget {
    /esRGBICC exch /ColorSpace defineresource pop
    systemdict /CIEesRGBICC undef
  } if
  systemdict /CIErommRGBICC .knownget {
    /rommRGBICC exch /ColorSpace defineresource pop
    systemdict /CIErommRGBICC undef
  } if
  % ColorSpaceFamily resources
  colorspacedict { pop dup /ColorSpaceFamily defineresource pop } forall
        % Filter resources
  filterdict { pop dup /Filter defineresource pop } forall
        % FontType and FMapType resources
  buildfontdict { pop dup /FontType defineresource pop } forall
  mark
    buildfontdict 0 known { 2 3 4 5 6 7 8 } if
    buildfontdict 9 known { 9 } if
  counttomark { dup /FMapType defineresource pop } repeat pop
        % FormType resources
  .formtypes { pop dup /FormType defineresource pop } forall
        % HalftoneType resources
  .halftonetypes { pop dup /HalftoneType defineresource pop } forall
        % ColorRenderingType resources
  .colorrenderingtypes {pop dup /ColorRenderingType defineresource pop} forall
        % ImageType resources
  .imagetypes { pop dup /ImageType defineresource pop } forall
        % PatternType resources
  .patterntypes { pop dup /PatternType defineresource pop } forall
        % Make the fixed resource categories immutable.
  /.shadingtypes where {
    pop .shadingtypes { pop dup /ShadingType defineresource pop } forall
  } if
  [ /ColorSpaceFamily /Emulator /Filter /IODevice /ColorRenderingType
    /FMapType /FontType /FormType /HalftoneType /ImageType /PatternType
    /.shadingtypes where { pop /ShadingType } if
  ] {
    /Category findresource
    dup /.Instances get readonly pop
    .LocalInstances readonly pop
    readonly pop
  } forall
        % clean up
  systemdict /.fixresources undef
} .internalbind def

%% Replace 1 (gs_resmp.ps)
(gs_resmp.ps)  dup runlibfile VMDEBUG

[
    /.default_resource_dir
    /.resource_dir_name
    /.fonttempstring /.scannextfontdir % from gs_fonts.ps
] systemdict .undefinternalnames

[
    /.definedefaultcs
    /.undefinedefaultcs
    /.defaultcsnames
    /.enumerateresource
    /.externalresourceforall
    /.getvminstance
    /.globalresourceforall
    /.localresourceforall
    /resourceforall1
    /.resourceexec
    /.undefinedresource
    /.vmused
] dup level2dict .undefinternalnames
systemdict .undefinternalnames
