|
|
% 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 defsetglobal
% 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} .internalbindend % .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} ifpssystemparams 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
endend
% 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} ifdup 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} ifpop pop
pssystemparams dup /GenericResourceDir get exch /GenericResourcePathSep get(Init) exch (gs_init.ps) concatstrings concatstrings concatstringsstatus { 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 } forallpop 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.
} ifcounttomark 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 defcurrentdict /.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 .undefcurrentdict /.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 .undefinternalnamessystemdict .undefinternalnames
|