anastigmatix.net

This document has a standard, validated CSS2 stylesheet, which your browser does not seem to display properly. In a browser supporting web standards, this table of contents would be fixed at the side of the page for easy reference.

anastigmatix home
  • Packaging for PostScript
  • Deploying PostScript code
  • What is a resource?
  • Deploying the resource file
  • Direct inclusion
  • Download to initial VM
  • File available to interpreter
  • Document manager
  • Resource as staged program
  • Form of Anastigmatix resource
  • Packaging tools
  • Specific issues and techniques
  • Private definitions
  • Resource dependencies
  • Local and global VM
  • Write protection
  • Things Adobe did not define clearly
  • Resource names
  • DSC resource syntax
  • VMusage
  • Interpreter resource location
  • Ghostscript
  • Adobe's Distiller
  • Former build/packaging system
  • Resource unpack script
  • Resource packaging for the PostScript® language

    When Adobe Systems unveiled Level 2 of the PostScript language in 1990, they included a very flexible named resource facility as well as other features that simplify development and deployment of libraries of reusable PostScript resources. Judging by PostScript code and tutorials available on the web, few PostScript programmers are yet taking advantage of what these language features can offer for the packaging of their code.

    This page describes how those features of PostScript can be effectively used in one approach—not the only one possible, but the one used for resources on this site—to packaging PostScript code that can be reusable and widely deployed. These guidelines and tools, with a few resources offered here as working examples, may persuade you that it would not be too hard to put the finishing touches on your own code.

    Deploying PostScript code

    So you've got a great library of PostScript procedures that the world shouldn't be without. If it is like a lot of those available on the web, it comes in a big file of PostScript, with instructions that say to paste it in at the front of a program that uses it or, for people using ghostscript or Distiller, save it in some handy spot on disk and add the file name with a run command at the top of a program that uses it.

    The user of your library might have some questions. When I run this file, what does it do? Does it push a new dictionary on the lookup stack, or does it add definitions to userdict? Does it define only the names I am expected to see in using the library, or will there be a lot of other names it only uses internally? Will some collide with names I use in my own code? Does its dictionary need to be on my lookup stack for its procedures to work right? If my program needs your library and another one from somewhere else, will they trip over each other's definitions, or stomp on each other's assumptions?

    Does running the file have other effects besides creating some definitions? Will it leave something on a stack, or change the graphics state, impose a new coordinate system or move the current point? Will it leave some interpreter setting in a different state than before?

    Without packaging guidelines, there are a lot of questions to ask before using somebody else's PostScript code. If the code is packaged as a resource, Adobe's guidelines for a well-behaved resource guarantee that the answers to most of those questions will be no.

    What is a resource?

    If your code is packaged as a resource, the first thing we know about it is it has a name and a category. There are several standard categories, and the most likely one is ProcSet, a set of procedure definitions conceptually belonging in the prolog of a file. Now, if the name of your resource is com.example.helloworld, your users will get access to it by putting this command in the setup section of a program:

    /com.example.helloworld /ProcSet findresource
    

    The findresource will succeed if the PostScript interpreter has been supplied with your resource file or knows where to get it, which can happen at least four different ways, covering a lot of practical scenarios. The program doesn't need to know which method was used. When findresource succeeds, it returns one object. In the ProcSet category, the object will be a dictionary. Because your resource is well-behaved, that object is the only manifestation of your resource there is (besides the memory it takes up, which could be noticed with vmstatus, but there's really nothing you can do about that). Making your resource available did not have any other effect: no graphics state updates, nothing left around in other dictionaries or on the stacks. It only created one dictionary the user can get with findresource. And nothing else will happen, until the user, either by get or begin, starts using procedures from your dictionary.

    What are the implications for writing your resource file? It should be a PostScript program that ultimately produces one dictionary (or one object of the expected type, for a category other than ProcSet) and passes it to defineresource. It can do anything reasonable in the process, allocating objects, creating other intermediate dictionaries, and so on, even calling findresource on other resources you rely on, as long as everything is left as it was found by the end. If your code currently has some effect at the moment it is loaded, like setting up a page size or graphics state, those effects should be moved to an “init” procedure in your dictionary, so they will not happen until the user's request.

    Deploying the resource file

    I hinted above that findresource will succeed if the PostScript interpreter has been supplied with the resource file or knows where to get it. Here are four ways to make findresource succeed.

    Method Pro Con
    Direct inclusion Not much to go wrong. The file with all needed resources included is self-contained and will print anywhere. Storage space if lots of files have copies of the same resources pasted in. Bandwidth when files sent to printer.
    Simply paste the resource file into any program that uses it, in the prolog section (before the findresource command, which belongs in the setup section). This is much like the way you might be deploying now, except by making the file a well-behaved resource, you assure the user the only effect of pasting it there is to make its dictionary available to findresource and there will be no other effect until some procedure from that dictionary is executed.
    Download to initial VM Works in any printer with enough memory. Easy and fast. Resource occupies printer memory until next power cycle, even for jobs that do not use it. Must be sent again after a power cycle. No luck if printer startjob password has been set and you don't know what it is.
    Download one copy of the resource file to the printer, with the line
    true () startjob
    added at the top, where () should match the printer's startjob password. If the passwords match (or the printer had no password set, in which case any password “matches”), the resource is loaded in virtual memory that persists between print jobs. No need to paste resource in other files; findresource will just work.
    File available to interpreter Works in any printer with a disk or flash file system, and also for host-based interpreters like ghostscript. Brought into memory only when requested, transparently; findresource just works. Lasts across power cycles. Printers with disks are very handy but not common at the low end.
    Query the category dictionary in the printer (or other interpreter, such as ghostscript) for the resource category and name, to find the full file name the interpreter would use to look for the resource. Save the resource file under exactly that name on the printer's disk (or the computer where you're running ghostscript). No need to paste resource in other files; findresource just works. More details in an appendix.
    File available to document manager Convenient if files are always sent through document manager and contain correct DSC comments. Flexible. Requires document manager software that does resource management; I've read all about it in Adobe manuals, but never met anyone with experience using such software. I am not aware of any freely available software that does this (CUPS didn't seem to, last I checked), even though that surprises me.
    Document-manager software looks at files queued for printing and can preprocess them in various ways. Resource management looks at the DocumentNeededResources, DocumentSuppliedResources, BeginResource, EndResource, and IncludeResource document-structure convention (DSC) comments, and can transparently replace an IncludeResource comment with the appropriate resource if it believes the printer doesn't have that resource; can also do the reverse, if it believes the printer does have the resource already; can accumulate its own copies of often-used resources by snarfing them out of files that way; and may decide on its own to download certain resources to printer's initial VM or disk based on frequency of use, and then snarf them out of files to save bandwidth.

    The upshot is there are several ways your users can choose to make your resource available to their programs, depending on their own circumstances, and as a resource developer you'd just like to make sure the full range of choices will work. Two things fall out:

    Resource as staged program

    It is possible to look at the life of a resource as a matter of staged programming, where a program in one stage generates a related program to be used in the next.

    What is the ultimate form of your resource? It is an object obtained from findresource, plus any procedures and other objects in it, which will be used by the program importing it. Those procedures and objects should be in a form for efficient execution and reasonable use of interpreter memory.

    One stage earlier, your resource file contains a PostScript program that generates that object. The file should be in a form that is compact for disk storage and communication bandwidth, comfortable for users who have it pasted into files they have to look at, and tolerably efficient for something that will be executed one time and thrown away after building the resource dictionary. The file should also have reliable DSC comments.

    Another stage back, and your source file may be a program that generates the resource file, including the DSC comments, which are part unchanging boilerplate and part details that redundantly appear in several places and are madness to keep in sync by hand. The best form for this file is what supports easy comprehension and maintenance: readable names, liberal whitespace and systematic indentation, and lots and lots of comments.

    The staging view relaxes a tension often seen in PostScript programming, where programmers try to strike some precarious compromise between readability, compactness, and efficiency all at once, and wind up with something that is terse, filled with made-up names like mt where they meant moveto, and not as readable, compact, or efficient as it could be. It is easier and more effective to get a compact resource file by an automatic conversion from the source, and then the source does not need to make any compromises on readability. As long as the conversion is well tested and known to work, it does not really complicate development and testing of your resource: you keep the source file open in a text editor, and after saving a change, just run the conversion before reloading the resource file in your PostScript interpreter.

    For the most part, what I have called “staging” here—generation of resource file from source, and resource from resource file—can be done in simple PostScript. In some cases, the job can be simplified further by turning PostScript into an explicitly staged programming language, as the ProcSet resource net.anastigmatix.MetaPre does.

    Form of an Anastigmatix resource file

    An example of an Anastigmatix resource file shows a number of required Document Structuring Convention comments, possibly a few ordinary comments briefly explaining what the resource is for, and a compact block of goo. The goo has no secretive or proprietary purpose; there is even a snippet of PostScript at the end of this page you can use to unpack it (the original source with indentation and comments is easier to read). It is just a form that answers well the several considerations above for the form of a resource file. It is compact for storage and transmission, and uses only encodings built into every Level 2 or later PostScript interpreter, which can very efficiently unpack it. It uses only seven-bit ASCII characters, so it can be shipped over all sorts of communication channels, and does not make a mess in a text editor for someone doing direct PostScript programming with the resource pasted into the file. Being a block of goo, it looks nothing like what the user is writing, so one can quite mindlessly scroll down to where the good stuff begins. The name of the resource, repeated occasionally in whitespace banner letters through the goo, helps to avoid disorientation in a large file that may have several different resources pasted in—when they all look like ordinary PostScript code, it can be hard to tell one from another without scrolling up to find where it started.

    The goo transformation is straightforward. The source program is read using PostScript's token operator, with the natural effect of stripping all white space and comments, and the tokens are written in “binary token” form. This is supported by every Level 2 and later PostScript interpreter, and requires no special arrangement: a PostScript scanner can read binary and ordinary ASCII tokens interleaved in any mixture. That means the binary token encoder doesn't need to be complete; some tokens can be written in the ordinary ASCII form, if the binary form wouldn't be shorter, or just out of laziness. Benefits of the binary token form include:

    The binary token form by itself would not be suitable for pasting into text files, so all of that output is written through the ASCII85Encode filter, with an overall expansion of 25%, five bytes from every four. The corresponding ASCII85Decode filter is again present in every Level 2 or later interpreter, and it ignores all whitespace, so the banner text merged into the resource file is transparent to it. Effectively, system names are encoded in 2.5 bytes, and integers in 1.25, 2.5, or 5, depending on their sizes.

    A final benefit of the goo transformation could be a discipline it imposes on the resource developer. While code is in development, it is very easy to leave various configuration settings to be made by tweaking the code itself. But by the time it is distributed as a resource, it isn't pretty to expect the user to edit the resource code to make settings; it undermines the very idea of a shared resource that can be pulled from storage by findresource for any job that needs it. The distributed version should have arguments, or configuration commands, or a parameter dictionary, for the anticipated settings, and a resource file in goo form is a strong reminder that settings are not made with code tweaks. (For debugging emergencies if the source isn't handy, it is possible to unpack the file given only a PostScript interpreter, and edit and use the unpacked version, but that should be rare.)

    It is possible to insert the FlateEncode filter between the binary tokens and ASCII85Encode to shrink the file still more with the compression method of gzip. I do not do this for most resources because FlateDecode is only certain to be present in Level 3 interpreters, and most resources are tolerably small without it. I do it for net.anastigmatix.hyphenpattern resources, though, to get Level 3 versions substantially smaller than the Flate-free versions usable on Level 2. Smaller for storage and transmission, that is; of course they are just the same size once loaded into interpreter VM.

    Packaging tools

    To use the resources on this site, you need nothing besides any Level 2 or later PostScript interpreter. For hacking on them, or your own resources, you need a Level 2 or later PostScript interpreter with access to a filesystem, such as ghostscript or Distiller running on a computer, or even a PostScript printer with a disk. The tools for packaging resources in this form are in the pure PostScript net.anastigmatix.Packager resource.

    Some resources on this site have not yet been rebuilt with Packager and use an older build system that relied on a collection of tools most easily assembled on Unix and further described in an appendix. Those resources will be converted to Packager style as time permits, or when they need editing.

    Specific issues and techniques

    Private definitions

    The definitions in your final resource dictionary should be the ones you expect to be used by programs importing your resource. In those procedures, you might refer to other definitions that belong only to your implementation. For instance, in everyday PostScript programming, you might have a procedure defined this way:

    /foo { 42 add internalfoo } bind def
    

    With this design, the name internalfoo is looked up every time foo is executed. As a speed issue, that is surprisingly unimportant: PostScript name lookups are optimized and cached, and extremely fast. But if foo is exported in a resource, it won't work unless the interpreter is able to look up internalfoo at the time of use. It will work if you include internalfoo in your resource dictionary and you require the calling program to keep your resource dictionary on the lookup stack—but both would be better avoided, to control the risk of name conflicts with other code in the calling program.

    A simple solution that covers most cases is to use immediately evaluated names:

    /foo { 42 add //internalfoo exec } bind def
    

    foo no longer contains the name internalfoo at all, just a direct reference to the procedure. Notice that the pre-resolved form of “internalfoo” is not simply “//internalfoo” but “//internalfoo exec”—and, as one of PostScript's less consistent corners, that is only true when internalfoo names an array or packed array that is executable (a procedure); if the value is not executable, or has any other type whether executable or not, then you do not add exec. Thank the next-to-last paragraph of PLRM section 3.5.3.

    Now you are able to leave internalfoo out of your final resource dictionary, and let the dictionary contain only the definitions you mean to export. Even better, foo will work whether the program using your resource adds your dictionary to the lookup stack or simply uses /foo get exec on your dictionary directly. Some users of your resource might prefer that, if they use, or other resources they import use, definitions that might conflict with yours.

    Immediately-evaluated names do not allow forward reference; you must order definitions so internalfoo has been defined before foo refers to it. One way to put it all together is to begin with a private dictionary:

    2 dict begin
    /internalfoo { 42 sub (Your number was:) = = } bind def
    /foo { 42 add //internalfoo exec } bind def
    

    and then copy only the exported definitions into a new dictionary and complete defining the resource:

    /foo dup load end 1 dict begin def
    /MyResource currentdict end /ProcSet defineresource pop
    

    If you have imported MetaPre, there is a handy export that handles creating the final dictionary and discarding the original one, just given a list of the names that should be exported—though of course something so simple would not be a reason to import MetaPre if you were not using it for anything else:

    /MyResource { /foo } export /ProcSet defineresource pop
    

    If you have procedures with a mutual dependency, or even just a single recursive procedure so some forward reference can't be avoided, sometimes messy tricks are used. You can leave a hole in a procedure and use put to fill the hole after what goes there is defined. Another option is to keep your original dictionary around, with all the internal and exported definitions, as a private dictionary:

    2 dict begin
    /internalfoo { -|[currentdict]|- begin 84 lt { foo } if end } metabind def
    /foo { 42 add //internalfoo exec } bind def
    /MyResource { /foo } export /ProcSet defineresource pop
    

    Here I have used MetaPre notation for splicing the current value of currentdict into internalfoo. But to keep the whole private dictionary around and do lots of internal begins and ends is a fairly heavy solution, unless you have a lot of mutual references to be dealt with. If you use this technique, and your design involves callback procedures supplied by user code, don't forget to end the private dictionary before calling them and reinstate it after.

    A less messy trick for recursion can be to use fix, which is also supplied by MetaPre.

    Resource dependencies

    If your resource relies on some other resource MegaQuux, you can start with a findresource to import it. If you know it doesn't have any names that conflict with yours, go ahead and put it on the lookup stack with begin. Just remember an extra end when you are done so it is not left on the stack: if the program importing you also uses MegaQuux, it'll have its own findresource for it, and not rely on your implementation dependencies.

    /MegaQuux /ProcSet findresource begin
    2 dict begin
    /internalfoo ... def
    /foo ... def
    ... defineresource pop
    end % MegaQuux
    

    How you use the imported resource depends on how well it is packaged. If it, like your own resource, is packaged with resolved references so it will work without its dictionary on the lookup stack, you are in luck; just refer to its procedures the same way you refer to your own:

    /internalfoo { currentpoint //triplequux exec } bind def
    

    The calling program will not need to do anything special or be aware of the other resource you are using internally. (Of course, the DSC comments in your resource file will include
    %%DocumentNeededResources: procset MegaQuux 0.0 0
    and the calling program will have DocumentNeededResources referring to you, so any document manager will know what files it needs to supply.)

    If MegaQuux is not so nicely packaged, and needs its own dictionary on the lookup stack or its procedures don't work, things get more complicated. You can stage your own procedures with begin and end of the MegaQuux dictionary surrounding calls into it. You can provide an init procedure for your resource that does a begin of the MegaQuux dictionary once and for all, though by doing that you may be causing name conflicts for the calling program. That isn't such a problem in the situation where MegaQuux is a resource that any program using your resource would obviously also be using. In that case, you can also do nothing about MegaQuux yourself, and rely on the calling program having imported it. You can also send a note to the MegaQuux maintainers with a link to this page.

    Local and global VM

    Depending on the method used to supply your resource file to the interpreter, your resource may be loaded into global VM. That means any data structures created at the time your resource is loaded will not allow stores of local data passed in later by the calling program. This can be an issue if you have default settings the program can change, or preallocated dictionaries for local variables in procedures.

    A good solution can be to stage things so that structures that might have to hold program input are created later, say in the setup section. The resource can have an init procedure that does that; it might even have only an init procedure in the dictionary returned by findresource, and init returns a new locally-allocated dictionary with the rest of the goods. There can even be an init that takes a parameter dictionary as an argument, specifying various settings, and returns a new dictionary with procedures specialized to those settings.

    Write protection

    Although defineresource makes the dictionary (or other object) representing your resource read-only, nothing does that automatically for other objects contained in it. If your dictionary contains composite objects that are writable, client code will be able to alter them. That is also true of objects appearing within procedures. For example, if your resource contains the procedure

    /foo { (myfile) (r) file } bind readonly def

    then even though the procedure is read-only, client code could use (w) //foo 1 get copy to change the behavior of your resource. Note that bind alone does not make the procedure it is applied to read-only, though it does make any procedure references within it read-only. Packed arrays, of course, are read-only with no special attention.

    Coding techniques that can help include:

    Things Adobe did not define clearly

    Resource names

    The Document Structuring Conventions briefly mention (Tech Note 5001, p. 35) that names of ProcSet resources should contain company and application names with an eye to reducing naming conflicts, but does not suggest any single convention. The example I used at the top of this document, com.example.helloworld, is an idea borrowed from Java, which recommends basing package names on inverted domain names. It is a reasonable idea, and perhaps Adobe might have suggested it too if the web had taken off a few years earlier, or they had defined the structure conventions a few years later.

    It is possible not only to define resources within existing categories, but to create new dedicated categories; an example is net.anastigmatix.hyphenpattern, where every resource in the category is a hyphenation pattern set for some language. Obviously, when a dedicated category is created, it is the category name that needs to be fully qualified to avoid conflicts; resources within a dedicated category can have simple names. The exception would be if the category is likely to attract contributed resources from many sources; then some sensible naming scheme for resources in the category might be proposed by the category's creator.

    DSC resource syntax for new categories

    While the set of resource categories is unmistakably designed and documented to be extensible (PLRM 3.9.3), the DSC authors seem not to have noticed, and specified a fixed set of keywords for six categories (TN 5001, p. 36)—not even the full set the language already defines. Also, the keywords do not match the spelling of the corresponding category names in the PostScript interpreter: the existing category names are mixed case, but the DSC keywords are lowercase, leaving unspecified what should be used as the DSC keyword for a category not listed. It seems unwise to allow non-listed category keywords to differ in spelling from the category names, because a document manager would have no built-in knowledge to associate the two. If new category names are based on domain names (which are case-insensitive by definition), then it is perhaps reasonable to follow the Java convention and spell them in lowercase consistently; then the names and keywords will be spelled the same and the keywords will be lowercase.

    A deeper problem is that distinct syntax rules are given in the DSC for <filename>, <fontname>, <formname>, <patternname>, <procname>, and <vectorname>, leaving unspecified what the syntax should even be for expressing in DSC the name of a resource in an unlisted category. Four of the given nonterminals reduce to <text>, but <fontname> and <procname> have more structure. I have been using the syntax of <procname> for newly-created categories because I think version numbers are valuable, but that may have to be revisited based on reports from people who actually use document manager software, on what gives it the least indigestion.

    VMusage

    The rule for measuring VM usage for the %%VMusage comment requires disabling garbage collection (TN 5001, p. 66). The first number is the difference in available VM after downloading the resource file once; the second is the new difference after downloading it, redundantly, again. Both numbers, because GC is disabled, reflect not only the final size of the resource but the total size of everything that might have been allocated and thrown away in running the resource file to create it. The numbers might be of interest to someone writing for a pre-Level 2 interpreter, which had no garbage collection, but that someone wouldn't be using named resources and categories, binary tokens or filters, all Level 2 features, or reading this page, either—even if that someone used the web, which is younger than Level 2 PostScript. I have made a habit of including another comment—not an official DSC comment, obviously, just a comment—giving the size after loading the resource and running a GC, because that's the number that really counts.

    The rule also says to “make sure there are no dependencies on other resources or conditions”—a bit impractical if there are other resources your resource deliberately does depend on. The real rule, of course, should be that you load the prerequisite resources first, run a GC, disable GC, then take the baseline measurement and measure the size of your resource against that.

    Appendix: interpreter location of resources

    For the deployment technique of file available to interpreter, you need to know where to put the resource files so that the interpreter will find them. In the general case, say for a printer with a hard disk, you can find out by asking the interpreter. For example, if you want to save a ProcSet resource named com.example.foo on the printer's disk, send the printer a query like this:

    /ProcSet /Category findresource begin
    /com.example.foo 128 string ResourceFileName end =

    The returned string is the name of the file the interpreter would seek if presented with /com.example.foo /ProcSet findresource. If you save the resource on the printer's disk under exactly that name, findresource will just work.

    Ghostscript

    The technique above can also be used with Ghostscript to find the default location where it will look for resource files. The result will involve a directory named Resource located where Ghostscript was installed, unless it was installed with a different default. However, Ghostscript (in current versions) can in fact look for resources along a path of directories; this can be helpful if you do not have write access to the main resource directory for your Ghostscript installation, as you can create a personal resource directory and add it to an environment variable or on the gs command line. The details are in the Ghostscript documentation. Beyond placing the resource files in the right directories, nothing needs to be done. If the file is present under the proper name, Ghostscript will find it.

    Adobe's Distiller

    This description applies to Adobe Distiller as available for Unix systems (and so, presumably, on Mac OS X). I do not know if the rules change significantly for Windows, but I will add that information if I find out.

    Like Ghostscript, Adobe's Distiller will search a path of directories for resource files. The path is given in the environment variable PSRESOURCEPATH, as a list of directories separated by colons, to be searched in order. Two consecutive colons indicate where Distiller's customary default location should fall in the search order.

    So far, so good, but it is not enough simply to point PSRESOURCEPATH at a directory that contains resource files. When Distiller searches the resource path, it does not look for resource files themselves, but for resource database files, which are simply text files with the extension .upr that list the resource categories and files available. So, if you have chosen a directory Resource and downloaded the Anastigmatix resources into its subdirectories ProcSet, Category, net.anastigmatix.encoding and so on—just as they are organized here—then the Resource directory should also contain the file net.anastigmatix.upr. Distiller will then find the resources as long as the Resource directory is on the PSRESOURCEPATH. Comments in the database file further describe its format, if you are curious.

    Appendix: former build/packaging system

    The pure PostScript net.anastigmatix.Packager resource was preceded by a build/packaging system that calls for a fairly complete Unix-like environment: ghostscript, the Korn shell (as far as I know, they work under pdksh also, but there are differences, and AT&T has now released ksh under CPL so nobody is really stuck with pdksh), and typical Unix command-line tools. The system requires a Unix-derived OS where /dev/fd/n really shares file descriptors; that includes the BSDs—and therefore Mac OS X—but not Linux, which brilliantly emulates /dev/fd/n in a way that makes the descriptors unshared.

    [There may be a workaround for Linux: if you go to the AT&T Research download page (where you would go to get ksh anyway), and download not the minimal ast-ksh package but the full ast-open distribution, you get a bunch of other utilities, some of which are really cool. One of them, 3d, is intended to emulate a union file system by shared-library interposition when the OS does not have union mounts; it just happens to emulate a working /dev/fd/n also, and I successfully used it once to make something work on Linux that needed that.]

    The easiest way to hack on a resource that still relies on the old build system is probably to edit it to use net.anastigmatix.Packager instead, and then hack it.

    Appendix: script to unpack resource file

    %!PS
    % $Id: resource.html,v 1.18 2009/12/05 02:24:26 chap Exp $
    
    % Copyright Chapman Flack, www.anastigmatix.net. May be freely used and
    % distributed provided this notice remains intact. Provided in the hope
    % that it will be useful but AS-IS WITHOUT ANY EXPRESS OR IMPLIED WARRANTY
    % AND WITHOUT REPRESENTATION AS TO ITS SUITABILITY FOR ANY PURPOSE. 
    
    % A .gs and not a .ps file - depends on ==only which is a ghostscript extra.
    %
    % Prepend to any Level2 file created by anastigmatix-binwrite.gs and feed to
    % ghostscript to see the contents of the file.  For example, could say:
    %  cat anastigmatix-bindump.ps somefile.ps | gsnd -q -
    %
    % Some files may have additional layers of encoding, such as for compression.
    % In that case, what you will see unpacked is probably a short string for
    % setting up a decode filter, followed by gibberish and/or an error. If so:
    % 1. Count the number of times the word 'exec' appears in the unpacked string.
    % 2. Repeat the command above, but add -sExtraExecs=n after 'gsnd', where n is
    %    the number of execs you counted.
    % 3. Repeat as needed (adding to the value of ExtraExecs) until you see the main
    %    layer unpacked.
    
    /buf ( ) def
    /1st //true def
    /decode {
      1st { /1st //false store buf } { inf buf readstring pop } ifelse
    } bind def
    
    /readit { % toktyp *readit* token
      buf 0 3 -1 roll put /1st //true store //decode 0 () /SubFileDecode filter
      token pop
    } bind def
    
    /ptypes <<
      /booleantype { { (//true) } { (//false) } ifelse print } bind
    >> def
    
    /printit {
      ptypes 1 index type 2 copy known { get exec } { pop pop ==only } ifelse
    } bind def
    
    {
      << /exec
         { % file
           cvlit /inf exch def
           /ouf (%stdout) (w) file def
           {
    	 inf read not { exit } if
    	 dup 128 ge 1 index 160 lt and {
               ( ) print dup readit printit ( % ) print =
    	 } {
               ouf exch write
    	 } ifelse
           } loop inf closefile ouf flushfile end
         }
         /findresource
         {
           {findresource cleardictstack} aload pop
           countdictstack array dictstack dup length 3 sub 3 exch getinterval
           cleardictstack
           {begin}
           {forall} 0 get
           5 array astore cvx executeonly exec
         }
      >> begin
      /ExtraExecs dup where { exch get cvi } { pop 0 } ifelse
      [ << /exec { end exec } >> {begin} 0 get ] cvx repeat
    } bind % this bind is sort of crucial :)
    exec
    

    Valid XHTML 1.0! Valid CSS! $Id: resource.html,v 1.18 2009/12/05 02:24:26 chap Exp $