Harlequin RIP SDK

The Harlequin device interface is a abstract file system API for reading, writing and manipulating streams of data and named objects, and parameter abstractions for reading, writing, and manipulating structured data. More...

Files

file  swdevice.h
 Header file defining the DEVICE interface.
 

Data Structures

struct  _pdf_filespec
 PDF_FILESPEC - a pointer to PDF_FILESPEC will be passed as the arg to DEVICELIST_IOCTL when the opcode is DeviceIOCtl_PDFFilenameToPS. More...
 
struct  _os_filespec
 A pointer to OS_FILESPEC will be passed as the arg to DEVICELIST_IOCTL routine when opcode is DeviceIOCtl_OSDeviceName. More...
 
struct  DEVICEPARAM
 A structure describing the parameter to set and its value. More...
 
struct  FILEENTRY
 Calls to DEVICELIST_NEXT must pass a FILEENTRY structure which the routine will fill in. More...
 
struct  STAT
 Calls to DEVICELIST_STATUS_FILE must pass a STAT structure to the routine which it will fill in. More...
 
struct  devicelist
 PostScript device instances. More...
 
struct  DeviceType
 This is the structure used to represent a device type (class) implementation in the Harlequin RIP core. More...
 

Macros

#define OS_DEVICE_TYPE   0
 The OS file system device type. More...
 
#define NULL_DEVICE_TYPE   1
 Data source/sink device type. More...
 
#define ABS_DEVICE_TYPE   10
 Absolute mapping device type. More...
 
#define RELATIVE_DEVICE_TYPE   17
 Relative mapping device type. More...
 
#define PREBOOT_DEVICE_TYPE   18
 Device to support alternate %os% mounting methods. More...
 
#define PREFIX_DEVICE_TYPE   19
 Device type to add Prefix support to relative devices. More...
 
#define COMPRESS_DEVICE_TYPE   23
 Device type to perform compression on raster band data. More...
 
#define UNION_DEVICE_TYPE   40
 Unified view of multiple devices. More...
 
#define MONEVENT_DEVICE_TYPE   52
 Device type used for sending textual output from %stdout, %stderr and %monitor. More...
 
#define FONT_ND_CRYPT_DEVICE_TYPE   128
 Device type for encrypting or decrypting OEM encrypted fonts. More...
 
#define MINPOSSIBLESTRATEGY   1
 
#define MAXPOSSIBLESTRATEGY   128
 
#define LONGESTDEVICENAME   50
 
#define DeviceIOCtl_ShortRead   0
 Opcode for DEVICELIST_IOCTL. More...
 
#define DeviceIOCtl_PDFFilenameToPS   1
 Opcode for DEVICELIST_IOCTL to convert PDF filenames specified for a particular platform to PostScript filenames. Argument is a pointer to a PDF_FILESPEC.
 
#define DeviceIOCtl_OSDeviceName   2
 Opcode for DEVICELIST_IOCTL. Arg is a pointer to an OS_FILESPEC. More...
 
#define VOIDPTR_TO_DEVICE_FILEDESCRIPTOR(d)   ((DEVICE_FILEDESCRIPTOR)((uintptr_t)(d) >> 1))
 Convert a (void*) to a device file descriptor. More...
 
#define DEVICE_FILEDESCRIPTOR_TO_VOIDPTR(d)   ((void *)((uintptr_t)(d) << 1))
 Convert a device file descriptor which was converted from a (void*) via the macro VOIDPTR_TO_DEVICE_FILEDESCRIPTOR() back to its original value.
 
#define setDevParamTypeAndName(_dp, _type, _name, _nameLength)
 Utility macro to set the type and name of a DEVICEPARAM.
 
#define setDevParamTypeAndCName(_dp, _type, _name)    setDevParamTypeAndName((_dp), (_type), (uint8 *)(_name), CSTRING_LENGTH(_name))
 Utility macro to set the type and name of a DEVICEPARAM, using a constant C string for the name. More...
 
#define SW_DEVICE_NAME_PROGRESS   "progress"
 

Typedefs

typedef HqnResult DEVICE_result
 Type for return value from DEVICELIST_LAST_ERROR functions. More...
 
typedef HqnFileDescriptor DEVICE_FILEDESCRIPTOR
 Type of a file descriptor for devices.
 
typedef struct _pdf_filespec PDF_FILESPEC
 PDF_FILESPEC - a pointer to PDF_FILESPEC will be passed as the arg to DEVICELIST_IOCTL when the opcode is DeviceIOCtl_PDFFilenameToPS. More...
 
typedef struct _os_filespec OS_FILESPEC
 A pointer to OS_FILESPEC will be passed as the arg to DEVICELIST_IOCTL routine when opcode is DeviceIOCtl_OSDeviceName. More...
 
typedef struct DEVICEPARAM DEVICEPARAM
 A structure describing the parameter to set and its value.
 
typedef struct FILEENTRY FILEENTRY
 Calls to DEVICELIST_NEXT must pass a FILEENTRY structure which the routine will fill in.
 
typedef struct STAT STAT
 Calls to DEVICELIST_STATUS_FILE must pass a STAT structure to the routine which it will fill in.
 
typedef struct devicelist DEVICELIST
 PostScript device instances. More...
 
typedef int32(* DEVICELIST_TICKLE) (struct DeviceType *dev, int32 recursion)
 The tickle feature is obsolete. This function type will not be called.
 
typedef DEVICE_result(* DEVICELIST_LAST_ERROR) (DEVICELIST *dev)
 Device type method to return last error for a device instance. More...
 
typedef int32(* DEVICELIST_INIT) (DEVICELIST *dev)
 Device type method to initialise a device instance. More...
 
typedef DEVICE_FILEDESCRIPTOR(* DEVICELIST_OPEN) (DEVICELIST *dev, uint8 *filename, int32 openflags)
 Device type method to open a file on a device instance. More...
 
typedef int32(* DEVICELIST_READ) (DEVICELIST *dev, DEVICE_FILEDESCRIPTOR descriptor, uint8 *buff, int32 len)
 Device type method to read data from an open file on a device instance. More...
 
typedef int32(* DEVICELIST_WRITE) (DEVICELIST *dev, DEVICE_FILEDESCRIPTOR descriptor, uint8 *buff, int32 len)
 Device type method to write data to an open file on a device instance. More...
 
typedef int32(* DEVICELIST_CLOSE) (DEVICELIST *dev, DEVICE_FILEDESCRIPTOR descriptor)
 Device type method to close an open file on a device instance. More...
 
typedef int32(* DEVICELIST_ABORT) (DEVICELIST *dev, DEVICE_FILEDESCRIPTOR descriptor)
 Device type method to abort action on an open file on a device instance. More...
 
typedef int32(* DEVICELIST_SEEK) (DEVICELIST *dev, DEVICE_FILEDESCRIPTOR descriptor, Hq32x2 *destn, int32 flags)
 Device type method to seek an open file on a device instance. More...
 
typedef int32(* DEVICELIST_BYTES) (DEVICELIST *dev, DEVICE_FILEDESCRIPTOR descriptor, Hq32x2 *bytes, int32 reason)
 Device type method to get bytes available for an open file on a device instance. More...
 
typedef int32(* DEVICELIST_STATUS_FILE) (DEVICELIST *dev, uint8 *filename, STAT *statbuff)
 Device type method to check status of a file by name. More...
 
typedef void *(* DEVICELIST_START_LIST) (DEVICELIST *dev, uint8 *pattern)
 Device type method to start iterating file names on a device instance. More...
 
typedef int32(* DEVICELIST_NEXT) (DEVICELIST *dev, void **handle, uint8 *pattern, FILEENTRY *entry)
 Device type method to get the next file in an iteration. More...
 
typedef int32(* DEVICELIST_END_LIST) (DEVICELIST *dev, void *handle)
 Device type method to end iterating file names from a device instance. More...
 
typedef int32(* DEVICELIST_RENAME) (DEVICELIST *dev, uint8 *file1, uint8 *file2)
 Device type method to rename a file on a device instance. More...
 
typedef int32(* DEVICELIST_DELETE) (DEVICELIST *dev, uint8 *filename)
 Device type method to remove a file from a device instance. More...
 
typedef int32(* DEVICELIST_SET_PARAM) (DEVICELIST *dev, DEVICEPARAM *param)
 Device type method to set a device parameter. More...
 
typedef int32(* DEVICELIST_START_PARAM) (DEVICELIST *dev)
 Device type method to start iterating device parameters. More...
 
typedef int32(* DEVICELIST_GET_PARAM) (DEVICELIST *dev, DEVICEPARAM *param)
 Device type method to get the next device parameter. More...
 
typedef int32(* DEVICELIST_STATUS_DEVICE) (DEVICELIST *dev, DEVSTAT *devstat)
 Device type method to get the status of the device instance. More...
 
typedef int32(* DEVICELIST_DISMOUNT) (DEVICELIST *dev)
 Device type method to dismount the device instance. More...
 
typedef int32(* DEVICELIST_BUFFER_SIZE) (DEVICELIST *dev)
 Optional device type method to return the buffer size that a device requires for best operation. More...
 
typedef int32(* DEVICELIST_IOCTL) (DEVICELIST *dev, DEVICE_FILEDESCRIPTOR fileDescriptor, int32 opcode, intptr_t arg)
 Device type method for miscellaneous control options. More...
 
typedef struct DeviceType DEVICETYPE
 This is the structure used to represent a device type (class) implementation in the Harlequin RIP core. More...
 

Enumerations

enum  DEVICE_RESULT {
  DeviceNoError = HQN_RESULT_SUCCESS , DeviceInvalidAccess , DeviceIOError , DeviceLimitCheck ,
  DeviceUndefined , DeviceUnregistered , DeviceInterrupted , DeviceVMError ,
  DeviceReOutput , DeviceNotReady , DeviceCancelPage , DeviceReOutputPageBuffer ,
  DeviceTimeout
}
 Last error return values. More...
 
enum  PDF_FILESPEC_values {
  PDF_FILESPEC_None = 0x00 , PDF_FILESPEC_PDF = 0x01 , PDF_FILESPEC_DOS = 0x02 , PDF_FILESPEC_Mac = 0x03 ,
  PDF_FILESPEC_Unix = 0x04 , PDF_FILESPEC_FS = 0x08
}
 PDF_FILESPEC flags. More...
 
enum  DEVICEPARAM_type {
  ParamBoolean = 1 , ParamInteger = 2 , ParamString = 3 , ParamFloat = 4 ,
  ParamArray = 5 , ParamDict = 6 , ParamNull = 7
}
 DEVICEPARAM::type values. More...
 
enum  DEVICELIST_SET_PARAM_result {
  ParamAccepted = 1 , ParamTypeCheck = 2 , ParamRangeCheck = 3 , ParamConfigError = 4 ,
  ParamIgnored = 5 , ParamError = -1
}
 DEVICELIST_SET_PARAM return codes More...
 
enum  DEVICELIST_OPEN_flags {
  SW_RDONLY = 0x001 , SW_WRONLY = 0x002 , SW_RDWR = 0x004 , SW_APPEND = 0x008 ,
  SW_CREAT = 0x010 , SW_TRUNC = 0x020 , SW_EXCL = 0x040 , SW_FROMPS = 0x080 ,
  SW_FONT = 0x100
}
 DEVICELIST_OPEN flags More...
 
enum  DEVICELIST_SEEK_flags { SW_SET = 0 , SW_INCR = 1 , SW_XTND = 2 }
 DEVICELIST_SEEK flags More...
 
enum  DEVICELIST_BYTES_reasons { SW_BYTES_AVAIL_REL = 0 , SW_BYTES_TOTAL_ABS = 1 }
 DEVICELIST_BYTES reason codes More...
 
enum  DEVICELIST_NEXT_result {
  FileNameNoMatch = 0 , FileNameMatch = 1 , FileNameError = -1 , FileNameIOError = -1 ,
  FileNameRangeCheck = -2
}
 DEVICELIST_NEXT return codes More...
 
enum  DEVICETYPE_flags {
  DEVICEABSOLUTE = 0x0000 , DEVICERELATIVE = 0x0001 , DEVICEWRITABLE = 0x0002 , DEVICESMALLBUFF = 0x0004 ,
  DEVICELINEBUFF = 0x0008 , DEVICEENABLED = 0x0010 , DEVICEREMOVABLE = 0x0020 , DEVICENOSEARCH = 0x0040 ,
  DEVICEUNDISMOUNTABLE = 0x0080
}
 Bit mask flags for DEVICETYPE::devicetypeflags. More...
 

Functions

HqBool skindevices_init_last_error (void)
 Initialise error handling for skin devices. More...
 
void skindevices_finish_last_error (void)
 Finish error handling for skin devices. More...
 
DEVICE_result skindevices_last_error (DEVICELIST *dev)
 Method call for use in device definitions to get the last error for skin devices. More...
 
void skindevices_set_last_error (DEVICE_result error)
 Set the last error for a skin device. More...
 
HqnResult device_result_translate (DEVICE_result result)
 Translate a device API-specific error code to a generic HqnResult error code. More...
 
DEVICELISTSwFindDevice (uint8 *deviceName)
 Looks up a device by name, returns NULL on failure.
 
uint8SwAlloc (int32 bytes)
 Dynamically allocate memory from the core rip's memory space. More...
 
uint8SwRealloc (void *pointer, int32 bytes)
 Reallocate memory dynamically allocated from the core rip's memory space using SwAlloc(), preserving existing contents. More...
 
void SwFree (void *pointer)
 Free memory dynamically allocated from the core rip's memory space by SwAlloc() or SwRealloc(). More...
 
int32 SwPatternMatch (uint8 *pattern, uint8 *string)
 For use in DEVICELIST_NEXT to assist pattern matching on file names. More...
 
int32 SwLengthPatternMatch (uint8 *pattern, int32 plen, uint8 *string, int32 slen)
 For use in DEVICELIST_NEXT to assist pattern matching on file names. More...
 
int32 SwReadFilterBytes (DEVICELIST *dev, uint8 **ret_buff)
 Utility function to help when the RIP is reading bytes from a custom filter via the device interface. More...
 
int32 SwReplaceFilterBytes (DEVICELIST *dev, int32 len)
 Utility function to help when the RIP is reading bytes from a custom filter via the device interface. More...
 
int32 SwWriteFilterBytes (DEVICELIST *dev, uint8 *buff, int32 len)
 Utility function to help when the RIP is writing bytes to a custom filter via the device interface. More...
 
int32 SwSeekFilterBytes (DEVICELIST *dev, int32 offset)
 Utility function to help when the RIP is seeking on a custom filter via the device interface. More...
 
int32 SwTestAndTickle (void)
 This is a wrapper to SwOften() for use when adding custom filters via the device interface. More...
 

Detailed Description

The Harlequin device interface is a abstract file system API for reading, writing and manipulating streams of data and named objects, and parameter abstractions for reading, writing, and manipulating structured data.

Devices are one of the primary methods the RIP uses to interact with its environment, and perhaps the easiest method you can use to pass data between the RIP core and your application code. Using a device, you can:

The device interface is very flexible: almost any operation can be implemented using devices, however there may be a performance penalty converting data to and from one of the formats supported by a device (as a data stream, or as structured parameters). Global Graphics have introduced a number of other interfaces to directly address particular use cases, but still recommend using the device interface where:

What is a device?

A device (also sometimes known as a "PostScript device") is an instance of a device type; a device type is an implementation of a class of devices with the same semantics.

A device type is represented by a DEVICETYPE structure. The DEVICETYPE structure is shared by all device instances of a device type, it contains the function pointers for device type methods, the device type number, some flags and other auxiliary data used when constructing and managing device instances. A device is represented by a DEVICELIST structure. DEVICELIST structures are managed by the Harlequin RIP core. The DEVICELIST instance is presented in the method function arguments so that you can retrieve the private data pointer for a device instance and the device type methods, but apart from those uses must not be modified by your code.

A device type implements its operations in terms of two abstractions:

Files
Files are (usually named) streams of data. They may be opened, closed, read, written, queried, renamed, deleted, and iterated.
Parameters
Parameters are named values of a set of types: booleans, integers strings, real numbers (float), the null value, arrays of parameters and key-value associations (dictionaries) of parameters. Parameters may be set, retrieved individually, and iterated.

Device types do not need to implement file system behavior, or parameters: some device types exist solely to expose a parameter interface, some device types exist solely to expose a file-like interface.

There are two sub-classes of device type:

Relative devices
Relative devices implement standard file system abstractions that can store a number of files. The files on these devices can only be specified using an unqualified relative name or a qualified device relative name (one of the first and fourth filename forms below). Relative devices are indicated by including the DEVICERELATIVE flag in the DEVICETYPE::devicetypeflags field.
Absolute devices
Absolute devices have only one "file" on the device. These often are used to represent communication devices (serial, parallel, TCP socket, and so on). The one "file" of the device can only be specified using the device name, without the relative filename part (the second and third filename forms below). The file may be opened for reading or writing depending on the device type implementation, so two-way communication can be implemented by one device type. Absolute devices are indicated by including the DEVICEABSOLUTE flag in the DEVICETYPE::devicetypeflags field (this is also the default if the flag is omitted).

Before a device can be used by the Harlequin RIP, the device type must be added, and the device instance must be mounted to initialize it.

Device type methods

The DEVICETYPE structure contains methods to manipulate files and parameters, and some instance management and miscellaneous methods. In general, you should provide definitions for all method functions. Method that are not supported should generally return an error code and set the last error state of the device to something other than DeviceNoError. Some method stub definitions can return result values that indicate they should be ignored, e.g., the parameter get/set methods can return ParamIgnored.

Device type methods for instance management

The device instance initialization and finalisation methods should be implemneted by every device. DEVICETYPE::device_init() is called when a device is mounted, it should initialize the device instance's private data. DEVICETYPE::device_dismount() is called when a device is dismounted, it should free any data allocated by the device (but not the device's private data itself, the RIP manages that). The size of the private data structure needed by a device is indicated by the DEVICETYPE::sizeof_private field.

Device type methods for files

Files on a device are opened by calling the DEVICETYPE::open_file() method. If opened for read only or read/write, they can be read using DEVICETYPE::read_file() method; if open for write only or read/write, they can be written using the DEVICETYPE::write_file() method. Open files maintain a current position, which can be queried and changed using the DEVICETYPE::seek_file() method. The number of bytes readable from an open file can be read using the DEVICETYPE::bytes_file() method. Open files can be closed using the DEVICETYPE::close_file() or DEVICETYPE::abort_file() methods.

When preparing to read from or write to a device, the optional device type method DEVICETYPE::buffer_size() is called to determine the size of buffer the client should use. This can be used to tune reads and writes to match the optimal sizes for underlying software or hardware systems. If this method is not implemented, then the DEVICESMALLBUFF flag is examined, and either a default large or small buffer size will be chosen.

The DEVICETYPE::ioctl_call() method may or may not operate on open files, depending on the semantics of the device type. It takes a file descriptor parameter, but in some devices the file descriptor is not used, and it uses its other parameters to determine the operations provided. If a device type supports IOCtl operations, its documentation should describe how it is used.

The DEVICETYPE::start_file_list() method can be used to start an iteration over a filename pattern. The DEVICETYPE::next_file() method is used to get each file matching the pattern, and DEVICETYPE::end_file_list() method is used to free resources when the iteration is complete.

The DEVICETYPE::status_file() method can be used to query the size and other attributes of a file by name without opening it. The DEVICETYPE::rename_file() method can be used to rename files on a device, and DEVICETYPE::delete_file() can be used to delete files from a device.

Device type methods for parameters

Parameters on a device can be individually queried using the DEVICETYPE::get_param() method call. Parameters can also be iterated by calling the DEVICETYPE::start_param() method, and then calling DEVICETYPE::get_param() with an unspecified parameter name. There are requirements for callers related to returning composite objects from devices: the client must call DEVICETYPE::start_param() if the last DEVICETYPE::get_param() it called in sequence returned a composite object. See DEVICELIST_GET_PARAM for details.

If a parameter is requested that your device type implementation does not support, you should return ParamIgnored.

Parameters on a device can be set by calling the DEVICETYPE::set_param() method. If a parameter is set that your device type implementation does not support, you should return ParamIgnored.

Other device type methods

The DEVICETYPE::last_error() method can be used to retrieve the last error from a device instance. If implementing this method for your own devices, you should use a thread local variable to store the error code: your device may be called from multiple different RIP or SDK threads, and the last error variable should not be reset because an operation on a different thread succeeded before a caller could retrieve a failure code. If the error code is needed, the RIP or SDK call the DEVICETYPE::last_error() method from the same thread as the device operation that failed, and as soon as possible after a failure as they can. The RIP skins provide the functions skindevices_set_last_error() and skindevices_last_error() that you can use to set or retrieve a thread-local variable containing the device error. These functions can be called at any time after the Harlequin RIP SDK is started, until the Harlequin RIP SDK is shutdown.

All operations on a device instance, even if successful, should prepare the device's last error code for a call to DEVICETYPE::last_error(). If the operation was successful, the error code DeviceNoError should be returned by DEVICETYPE::last_error().

The DEVICETYPE::ioctl_call() method may or may not operate on open files, depending on the semantics of the device type. It takes a file descriptor parameter, but in some devices the file descriptor is not used, and it uses its other parameters to determine the operations provided. If a device type supports IOCtl operations, its documentation should describe how it is used.

There are some obsolete and unused method pointers in the DEVICETYPE function. DEVICETYPE::unused2 and DEVICETYPE::spare should be set to NULL.

Device type flags

As well as the DEVICEABSOLUTE or DEVICERELATIVE flags to indicate whether a device is absolute (single file) or relative (multiple files), there are some other flags that the device type may set:

Device instances inherit the device type flags, but also add some more specific to each instance:

Adding new device types

The Harlequin core library maintains a set of built-in device types, which can be augmented by devices supplied to the low-level SwStart() RIP initialization function. Additional device types can be added by the skin, using RDR. Devices are registered in RDR as instances of the class RDR_CLASS_DEVICETYPE, using the device type number as the RDR type, an RDR ID of zero, and a pointer to the DEVICETYPE structure and its size as the RDR pointer and size. Built-in devices take priority, but devices registered in RDR can be overridden at the time a device instance is mounted:

theIDevTypeNumber(devtype), 0, // ID
devtype, sizeof(*devtype),
// ...cleanup and return...
}
sw_rdr_result SwRegisterRDR(sw_rdr_class rdrclass, sw_rdr_type rdrtype, sw_rdr_id rdrid, void *ptr, size_t length, sw_rdr_priority priority)
Register an RDR.
@ RDR_CLASS_DEVICETYPE
Definition: rdrapi.h:523
@ SW_RDR_SUCCESS
Definition: rdrapi.h:617
@ SW_RDR_NORMAL
Definition: rdrapi.h:610

In the Harlequin RIP SDK, the SwLeAddCustomDevices() function can be used to register device type implementations in RDR. This function can be called at any time after the Harlequin RIP SDK is started, until the Harlequin RIP SDK is shutdown.

Instantiating new device type instances

The Harlequin core library maintains a list of instantiated devices, stored as DEVICELIST structures. These structures are maintained by the Harlequin core library, and should not be altered by your code. The Harlequin RIP creates a new instance of a device type and adds it to this internal list by mounting it. There are two methods of mounting a device:

  1. Use the PostScript devmount and setdevparams operators.
  2. Add a device type implementation of the Preboot device type before starting the RIP.

The first method is the most common, and should be used in nearly all cases. The second method can be used if you need to mount the %os% device that provides access to the RIP's SW/ data folder on a special device (for example, it is possible to mount it on a RAM disk or more exotic devices).

Mounting a device from PostScript is usually done during the RIP boot-up sequence, or in an initial job after boot-up, submitted by your application skin. The file SW/Sys/ExtraDevices contains the extra device mounts that are applied during boot-up. You may choose to add a new file to the SW/Sys/ExtraStart/ directory to mount your devices, rather than edit this file. The SW/Sys/ExtraDevices exemplifies several variations on how to mount device instances. First, it unconditionally mounts the %console% device using the PostScript:

(%console%) dup devmount pop
<<
  /Password 0
  /DeviceType 16#ffff0001
  /Enable true
>> setdevparams

The devmount operator associates a device name (without the leading and trailing % characters) with a DEVICELIST device instance structure and adds it to the core's list of device instances. The setdevparams operator sets parameters on a device instance. The first time it is used with a device name setdevparams must have a /DeviceType parameter in the dictionary, indicating the device type number to connect with the device name. In this first use, setdevparams will:

If there were no errors, then the device is now ready to use. The remaining parameters in the setdevparams dictionary will be set on the device. There are a few parameters that are managed by the RIP and not passed to the device, such as /Enable in the example above, but also /Password, /Searchable and /SearchOrder. See the Extensions Manual for more details.

If there is already a device mounted with the name chosen, then the PostScript code above will throw an error, stopping the RIP boot sequence. The SW/Sys/ExtraDevices file shows how to test if a device is mounted, and mount it only if it is not already mounted:

mark (%configps%) dup devstatus not {
  dup devmount pop
  <<
    /Password 0
    /DeviceType 54
    /Prefix (%os%/TestConfig/)
    /Enable true
    /SearchOrder -1
  >> setdevparams
} if cleartomark

This PostScript code mounts a device with the name %configps% using a prefix device, but only if there is no device already mounted using that name. This device name is used by the HHR SDK as the location to find RIP configurations.

Sometimes you may want to build an application that has an optional device, either a device you add for some customers' configurations, or perhaps a device you can mount for debugging problems. The SW/Sys/ExtraDevices file shows how to do this too. It defines a PostScript procedure, mountoptional, which will call the devmount and setdevparams procedures, trapping any errors, and cleaning up after itself. This is used for optional devices, such as mounting the %Calendar% device which may not be present in all skins:

/mountoptional { % devname params --mountoptional--
  $error /initializing 2 copy get 3 copy pop false put
  mark 6 4 roll % $error /initializing tf mark devname params
  { 1 index devmount pop setdevparams } stopped cleartomark
  put % restore $error /initializing value
} bind def

(%Calendar%)
<<
  /Password 0
  /DeviceType 16#ffff0005
  /Enable true
>> mountoptional

Devices mounted during boot-up

A couple of special device types will be mounted automatically during the RIP's boot sequence. An instance of the null device type will be mounted as %null%. This is an data source and sink device, any file object read from it or written to it treated as empty. If an instance of the preboot device type is discovered, it will be mounted as %preboot%, and the protocol for iterating its parameters to discover and mount other devices will be followed. If there was no device called %os% mounted by the preboot device (or no preboot device), then the RIP automatically mounts an instance of the OS device type (this device type is usually just an alias for a file system device type). The %os% device provides access to the RIP's SW/ data directory, so having this device mounted allows the RIP boot-up sequence to proceed, including finding the SW/Sys/ExtraDevices file that includes the other device mounts.

Dismounting device instances

Dismounting device instances is a rare operation. Dismounting a device instance calls the device type's DEVICELIST_DISMOUNT method, removes the DEVICELIST structure from the core's lists, and frees the private data and the device instance data. The RIP will automatically dismount device instances on shutdown, most of the time that will be sufficient to clean up device instance data. In the rare cases that you may want to dismount a device explicitly, the PostScript operator devdismount will do it.

Files and filenames for devices

The PostScript language (and thus the Harlequin Core) makes no distinction between binary and text files, and view a file as a stream of bytes with no other structure. If the underlying operating system does make such distinctions, the device implementation must take any necessary actions to conceal this from the Harlequin Core. The PostScript language definition does cater for the usual line endings of text files, however. Text files can use ASCII CR (character 13), ASCII LF (character 10) or CR/LF pairs to indicate the end of a line.

[RB3] does not define the maximum length of a filename or the characters that a filename can contain, saying that these are defined by the underlying operating system. In practice, this is not good enough, because a wide variety of PostScript language jobs use filenames that exceed common file system limits.

Global Graphics have defined that the Harlequin Core device implementations must support the following minimum restrictions:

Note
The Extensions manual describes these limits on file and device names and their variation between versions of the Harlequin RIP in more detail. Also in the Extensions manual, see the discussion of file name mapping.

You should also bear in mind that the eventual user of the product may wish to access any file on the underlying file system from the Harlequin Core; such files may have been created independently of the Harlequin Core. Any mapping scheme used should preferably allow some PostScript language filename to map to any possible underlying name, and the rules for this mapping should be part of the user documentation of your product.

The PostScript language does not treat any characters in a filename as special. In particular, / is not a directory separator, although it often makes sense to treat it as one in the underlying file system. The corollary to this is that directories on the underlying file system must be created (and possibly deleted) automatically, since the PostScript language provides no way of performing these operations.

If there is no underlying operating system, it may be simplest to implement a "flat" file system to support the Harlequin Core.

Wildcard matching in the PostScript language operator filenameforall also does not treat / or . specially; in particular, * will match a string that includes either or both. This is different from some common operating systems; for instance, UNIX shell * matching will not match a / separator, and on Windows * matching will not match a . used between a filename and its extension.

The PostScript language operators file, deletefile, renamefile, status and filenameforall take a file name operand that can be in one of four forms:

  1. filename
  2. %devicename
  3. %devicename%
  4. %devicename%filename

If the first form is given, the interpreter will attempt the operation on all devices that are mounted and searchable until one succeeds. If they all fail, a PostScript language error is produced, as documented in [RB3]. The devices are placed in a list whose order is predictable; for the Harlequin Core, this order is the same as the order in which the devices were mounted.

If the other forms are given, the Harlequin Core attempts the operation only on that specific device.

Device-relative filenames

The term "device-relative filename" is used in this document to refer to the third form of the file name on a device above, i.e.: %devicename%filename. The term is intended to convey that the filename is both on a relative device (supporting multiple named entities), and that the filename is specified relative to this particular device, and how it chooses to interpret the named entities.

Device types and numbers

Often, devices may be different instances of the same kind of device type; for instance, there may be more than one disk or serial line. The device type implementation is shared between these instances by informing the Harlequin Core that the devices have the same device type.

The device type is indicated by a 32-bit integer; the device type number. The allocation of possible values is:

0x00000000-0x0000ffff
Reserved for Global Graphics.
0xXXXX0000-0xXXXXffff
Reserved for OEM number XXXX.
0xffff0000-0xffffffff
Reserved for private use in closed environments (i.e., within a product that does not include any other third-party components that add devices).

OEM numbers are allocated by Global Graphics Software.

Device file descriptors

Similarly to other file system interfaces, the device interface manages files using file descriptors. File descriptors are of type DEVICE_FILEDESCRIPTOR. Note that on 64-bit platforms, this is a 64-bit type, so do not cast it or pass it through a 32-bit variable or parameter. Only non-negative file descriptors are valid: the DEVICELIST_OPEN method will return -1 on failure, but any negative file descriptor should be treated as an error.

Multiple files may be opened on a device at the same time, each will be given a different file descriptor. The device interface does not define what happens if you open the same file name on a device for writing and reading at the same time, or more than once for writing. The device implementation may define semantics for this, or you may get unexpected results from interleavings of operations.

A file descriptor will be returned by the DEVICELIST_OPEN method when a file is opened. This file descriptor is used by the DEVICELIST_READ, DEVICELIST_WRITE, and DEVICELIST_SEEK methods. The current position in a file must be maintained for each file descriptor independently. The DEVICELIST_CLOSE and DEVICELIST_ABORT methods close and invalidate the file descriptor, the difference being that DEVICELIST_ABORT signals abnormal processing of the the file. The DEVICELIST_BYTES method returns an indication and a number of bytes that can be read from the file descriptor. The DEVICELIST_IOCTL method takes a file descriptor, but not all device types use its file descriptor. This method is inherently device-type specific, in some cases the operation requested is determined and handled entirely using the opcode and generic argument parameters instead.

Well-known device type numbers

A number of device types are defined by the core library interface.

The OS device (device type 0)

This device type is expected to provide a FileSystem device, accessing files on the underlying operating system. It is expected to take a /Prefix parameter, which should set to root of the hierarchy accessed by the device (if supported by the underlying OS). A device type with this number must be provided by the RIP skin.

The null device (device type 1)

This is a built-in device type. It acts like an empty data source or sink for file operations, and returns DeviceIOError for most other operations.

The absolute device (device type 10)

This is a built-in device type provided for device absolute devices which map to a particular file on the %os% device: for example mounting a device of this type called %state% maps operations to the file %os%state

The relative device (device type 17)

This is a built-in device type provided to make multiple absolute devices appear as one relative device.

Preboot device (device type 18)

This device type may optionally be provided by the RIP skin in a device type list passed through the SwStart() parameters.

The preboot device type is a parameter-only device that allows device instances to be mounted and configured during the RIP boot sequence, primarily to allow the %os% device to be changed.

If a preboot device is discovered by the core during boot up, then its parameters are enumerated. The device's parameters are expected to be composite parameters, each with a key name and a dictionary value. The device named by the each parameter key will be mounted, and then the dictionary will be enumerated for key-value pairs to set as parameters on that device.

If the %os% device is mounted by this sequence, then the RIP boot continues as normal. If the %os% device is not mounted by this sequence, or there is no preboot device, then the %os% device is mounted on an instance of the OS_DEVICE_TYPE, with the default /Prefix provided by that device implementation. This method ensures compatibility for older RIPs and RIPs that lack a preboot device, but allows the RIP to provide options for mounting union or other complex devices before boot.

If a configuration generator device (%configps%) is desired by the OEM, then it could be added to the list of devices returned as parameters by the preboot device.

Prefix device (device type 19)

The is a built-in device type. It allows a sub-hierarchy of a file system to be referred to using shorter and simpler names. When accessing files, a prefix device prepends its prefix to the filename, and passes the operation to the underlying device. All other operations, except for setting and getting the /Prefix device parameter itself, are passed to the underlying device.

The RIP uses prefix device mounts for all sub-hierarchies of the %os% device that it mounts at start, including the default %tmp% location. If these or other sub-paths of %os% are mounted, it is important to use a prefix device to mount the path so it can function with a union device as %os% device.

Prefix devices can be mounted recursively on top of each other.

Band compression device (device type 23)

This device type may optionally be provided by the RIP skin in a device type list passed through the SwStart() parameters.

If the systemparam /CompressBands is true, and the %pagebuffer% device parameter /RIPCanCompress is true, then the RIP may attempt to compress rasterized band data using this device.

When active, the RIP will create a new instance of this device type for each band it wants to compress. The RIP will send these parameters to the device:

/MinBandCompressRatio (real)
The minimum compression ratio, copied from the pagebuffer device that will receive the data.
/CompressBands (integer)
A compression mode, copied from the pagebuffer device that will receive the data. If this is negative, compression will be disabled.
/BandWidth (integer)
The width of the band, in bits.
/ColorFactor (integer)
The number of colorants in each rasterized band.
/ScratchSize (integer)
The size in bytes of the data for each colorant in the rasterized band, multiplied by the minimum band compression ratio. This is provided so the device can allocate a buffer of a suitable size to compress into.

The RIP will then open a file on the device for the raster data. The rasterized band data will be written to the device, and then the same file will be immediately read back to retrieve the compressed data and closed. Compressed data can be no longer than the raw rasterized band data. If the device cannot actually compress the data, it should return -1 for either the write or the read request.

Union device (device type 40)

This device type may be built in to the RIP, depending on the product options.

The union device is used to make several PostScript devices appear as if they were one device. It is most useful for filesystem devices, but can be used for other types of devices too. The union device combines a set of read-only devices with an optional writable device, making them seamlessly appear like one device. Requests to open files, get parameters, read data, etc., are sent to the writable device first, and then down the sequence of readable devices until either the request is met, or the sequence of devices is exhausted. Files that appear on the writable device hide files of the same name on the readable devices, files on higher-priority readable devices hide files of the same name on lower priority readable devices. If an operation modifies a file that does not exist on the writable device but does exist on a readable device, data will be transferred from the readable device to the writable device. If a file is deleted, a special record will be written on the writable device that hides the file from other operations. File names are enumerated across all of the devices, excluding file names marked as deleted. The readable devices are never modified by file operations; only writable device files are modified.

The union device is configured through two device parameters:

/Read [ (%device%prefix)... ]
An array of one or more underlying readable devices. The devices may be specified as a device name only, or a device with a prefix. Names referenced on the union device are accessed on the readable devices by appending the name to this device and prefix. Whilst this device and prefix combination usually refers to a directory on the readable device, it does not need to. It may be an arbitrary partial path on the readable device. The first device in the array has the highest priority, files on it will hide files with the same name on devices later in the array.
/Write (%device%prefix)
An optional writable device and prefix. This is the device prefix used to write files that are modified or created on the union device. This may be set to an empty string (), in which case the union device will refuse all write operations.

You are cautioned not to modify the union device's /Read or /Write parameters whilst there are files open on the device. The same parameters can be set, however, so currentdevparams setdevparams will succeed.

The underlying devices for the union device need not be enabled nor searchable for the union to be enabled or searchable. It is indeed preferrable that they have /Enable set to false and /SearchOrder set to -1, so that they are not directly accessed by PostScript file operations. The /Enable and /Searchable (or /SearchOrder) keys of the union device itself control access to the entire collection.

It is important that only one instance of a union device maps the same writeable device and prefix. The union device caches some information in memory, so if two devices instances are created referring to the same writeable device, they will have inconsistent views of the file system state. Using the prefix device to map sub-trees of a file system is an important tool to ensure that there are not conflicting instances of the union device.

The "clrip" application has support for the simplest and most common use of the union device: using a writable directory for files that change, while keeping the SW directory unmodified. This use case allows multiple simultaneous RIP processes to be started using the same executable and SW directory, but not to interfere with each other because they do not write temporary files in the same place, or see each other's partially completed file writes. The -W option to clrip specifies a directory to be used to write files that would have been put in the SW directory. For example,

clrip -c Monochrome72dpi -W SW-write job.pdf

RIPs a PDF job, using the normal SW folder, but writing %os% and temporary files into the directory SW-write, relative to the current directory. Note that the SW-write directory stores a persistent state of the modified and written files. If used by a subsequent invocation of the RIP, the state will appear as it did when the previous RIP invocation finished.

clrip -c Monochrome72dpi -W C:\temp\write1 job.pdf

RIPs a PDF job, using the normal SW folder, but writing %os% and temporary files into an absolute directory path.

clrip -c Monochrome72dpi -W "%ram%" job.pdf

RIPs a PDF job, using the normal SW folder, but writing %os% and temporary files into a RAM filesystem. All file changes to SW made during the RIP instance will be forgotten on exit. This usage is not recommended for production use, because temporary files can become very large, and can consume all the system RAM.

When running multiple RIP instances, each RIP should specify a different writable directory using -W. Directories may be created empty before the first use, and may either be re-used without modification, or cleared out between subsequent invocations, depending on the your use case.

The Scalable RIP uses the union device to mount individual writeable SW folders for each Farm RIP, while sharing the base readable SW folders with the controller RIP.

The monitor event device (device type 52)

This is a built-in device type to support issuing tagged monitor event messages from PostScript. This is an absolute device, supporting open, write, close, and parameters to tag the messages written to it. The parameters supported are:

/Channel (string or integer)
The monitor channel to tag message with. The value should be one of Monitor, Progress, Halftone, stdout, or stderr, or an integer.
/Encoding (string)
The name of the encoding in which the messages are written to the device. The device will attempt to transcode messages into UTF-8 for issuing through monitor events.
/Timeline (integer)
A timeline reference. PostScript code should not set this unless it has a reference passed to it by compiled code (e.g., another device). If not configured, the device will use the current interpreter timeline reference.
/UID (integer)
A unique ID for the monitor message. See the timelineapi.h header for information about how the unique ID should be constructed.

Linked code (from Plugins or the RIP skin) should use the event API directly.

The RIP normally mounts this device using the well-known names %output% to output messages on the /Monitor channel, and %errors% to output messages on the /stderr channel.

Well-known device names

The core library looks for some device instances by name, rather than by device type. These device names may be mounted on any device that provides the correct semantics.

Temporary file device %tmp%

The RIP writes temporary files to storage, often to be able to recover space when memory is fully occupied. The location it uses for most temporary files is the %tmp% device. This is normally mounted as a prefix device on a sub-directory of the SW data directory, but you may want to redirect it to a fast SSD or other storage medium. Note that it is not a good idea to direct this to a RAM disk, because it is most heavily used when RAM available is limited. It is usually better to provide surplus RAM to the RIP for general use.

Calendar device %Calendar%

This parameter-only device may be implemented by the skin. It follows the specification in the Adobe PostScript Language Reference Manual Supplement for version 2014, 10 March 1994, except that all parameters are read-only, the clock cannot be stopped and started. The parameters are:

Year
The calendar time year, an integer in the range 1980-2079.
Month
The calendar time month, an integer in the range 1-12.
Day
The calendar time day of month, an integer in the range 1-31.
Hour
The calendar time hour, an integer in the range 0-23.
Minute
The calendar time minute, an integer in the range 0-59.
Second
The calendar time second, an integer in the range 0-59.
Running
A boolean parameter, indicating if the calendar time clock is running.

Pagebuffer device %pagebuffer%

The page buffer device defines the raster output interface between the core RIP and the skin. The documentation and protocol for the page buffer device have been withdrawn from circulation by Global Graphics. The page buffer device is implemented in the skin currently, however it is likely to move into the core library and/or be removed or restricted in future RIP releases. A direct raster output API is expected to replace the page buffer device.

Configuration device %config%

The configuration device is a low-level device used to connect the Harlequin RIP's server loop to the SDK library's input system and job submission interfaces. This description is for information only, you should not need to modify the configuration device provided by the SDK library.

A printer or typesetter using the Harlequin Core will either be processing a job or waiting for another job to arrive. While the RIP is waiting for a job to arrive, it can also accept configuration commands.

The implementation of this uses the configuration device %config%. This device controls the operation of the RIP; it supplies PostScript language text to the RIP that either configures the RIP, enquires about the state of the RIP, or sets up the RIP to process an incoming job. The configuration device can also indicate that none of these are needed now. The RIP will use this idle time for tasks such as caching characters that may allow a future job to complete more quickly.

When the RIP is not processing a job, it iterates around the "server loop", which is a section of PostScript language code that looks for and then processes a PDL file, and opens the %config% configuration device. It then enters an inner loop performing a bytesavailable test on the %config% device, which results in a call to the DEVICELIST_BYTES routine of the config device type. When there are no bytes available (DEVICELIST_BYTES returns zero), the RIP may perform idle-time tasks, for example caching fonts or garbage collection.

When bytes become available, the RIP exits this inner loop and reads and executes PostScript language text from the device, closing the file when the end of file is reached. The PostScript language executed can do arbitrary tasks, but should leave either false or two file objects and true on the operand stack when the end of file is reached.

If false is on the top of the operand stack, the RIP continues to run round the server loop. This should be returned when PostScript language text needs to be generated, perhaps for configuration or status enquiry, but there is no job to execute. Returning false should not be used indicate there is nothing to do; use the bytesavailable information to do that.

If true is on the top of the operand stack, then a job is executed; the lower of the two file objects is used as the source (%stdin%) of the job, and so must have been opened for reading, and the upper one as the standard output (%stdout%) while the job is executing, and so must have been opened for writing. Using this mechanism, the RIP does not need to know where the job is coming from. If there are several possible sources for a job, the configuration device is responsible for polling the various sources, identifying the source of the next job, and supplying appropriate file objects to the RIP.

The configuration device need implement only the DEVICELIST_OPEN, DEVICELIST_CLOSE, DEVICELIST_READ, DEVICELIST_BYTES, and DEVICELIST_LAST_ERROR routines. The last error routine is not needed if the other routines never return errors. It may be useful to implement some of the other routines; a common choice is to implement the DEVICELIST_WRITE routine to have somewhere to send output during the execution of the PostScript language text read from %config%.

PS configuration device %configps%

This device is used for read-only filesystem access to configuration files. This device is normally a prefix device mounted on a sub-directory of the %os% device. See PS configuration.

JSON configuration device %jsonfile%

This device translates JSON configurations read from the PS configuration device into PostScript configuration commands. See JSON configuration.

Screen export device %screeninfo%

The screen export device can be used, when outputting RLE format raster data from the RIP, to export details of AM halftone screens used on a page to a special device. Global Graphics has in the past provided, under contract conditions, a screening library that can convert these screening parameters into threshold tables or other data formats to allow customers to apply Harlequin HPS screening in their own raster processing pipeline.

Progress device %progress%

This is a legacy device for handling progress messages that are created by the RIP core itself, and are not part of a job's output. See the legacy progress device.

Monitor device %monitor% and console device %console%

These are alternate names for a legacy device for handling output messages from the RIP core. See the legacy monitor and console devices.

Extra skin device types

Some device types are not mandated or referenced by the core library, but are may be provided by the RIP skins. The Harlequin RIP SDK provides some extra devices. Extra devices may include:

The font encryption/decryption device (device type 128)

This device type may optionally be provided by the RIP skin in a device type list passed through the SwStart() parameters.

This device type is used by the RIP when construcing the FONTDecode filter for reading or the FONTEncode filter for writing. Implementation of filters using devices is described in the Extensions Manual.

For certain font types, the data defining the outlines can be protected by custom encryption methods. The FONTDecode filter will be used to read outline data for rasterisation if a font is detected with custom encryption. The FONTEncode filter will be used for writing if the path data is requested from HDLT: custom encrypted font outlines will otherwise not be available from the RIP.

This device type may support an integer /Strategy parameter for different encryption methods. The RIP will create instances of the device by iterating the strategy values from MINPOSSIBLESTRATEGY to MAXPOSSIBLESTRATEGY when attempting to decode font data.

Filter devices

PostScript language filters may be implemented using absolute device types, as described in the Extensions Manual. The /FilterNumber used in the filter resource dictionary should match the device type number you use to register the filter device in the RIP. Decoding filters can use (r) or (d) for the /FilterType parameter; encoding filters can use (w) or (e) for the /FilterType parameter in the filter resource dictionary.

A decoding filter implemented by a device will have its DEVICELIST_READ function called to decode data in the buffer provided; an encoding filter implemented by a device will have its DEVICELIST_WRITE function called to encode data in the buffer provided.

Notes on devices

skindevices_last_error() and skindevices_set_last_error() provide thread-safe support of the last error protocol for DEVICELIST_LAST_ERROR functions. Device implementations in the RIP skin should call skindevices_set_last_error() to set one of the DEVICE_RESULT error codes or a valid error UID. The device's last error function should return the error code returned by skindevices_last_error(). skindevices_last_error() and skindevices_set_last_error() must not be called before reaching state SW_LE_DO_RIP_START or after reaching state SW_LE_DO_RIP_STOP when using SwLeDo(), i.e., between SwLeStart() and SwLeStop().

Macro Definition Documentation

◆ ABS_DEVICE_TYPE

#define ABS_DEVICE_TYPE   10

Absolute mapping device type.

This is a built-in device type provided for device absolute devices which map to a particular file on the %os% device: for example mounting a device of this type called %state% maps operations to the file %os%state

◆ COMPRESS_DEVICE_TYPE

#define COMPRESS_DEVICE_TYPE   23

Device type to perform compression on raster band data.

This device type may optionally be provided by the RIP skin in a device type list passed through the SwStart() parameters.

If the systemparam /CompressBands is true, and the %pagebuffer% device parameter /RIPCanCompress is true, then the RIP may attempt to compress rasterized band data using this device.

When active, the RIP will create a new instance of this device type for each band it wants to compress. The RIP will send these parameters to the device:

/MinBandCompressRatio (real)
The minimum compression ratio, copied from the pagebuffer device that will receive the data.
/CompressBands (integer)
A compression mode, copied from the pagebuffer device that will receive the data. If this is negative, compression will be disabled.
/BandWidth (integer)
The width of the band, in bits.
/ColorFactor (integer)
The number of colorants in each rasterized band.
/ScratchSize (integer)
The size in bytes of the data for each colorant in the rasterized band, multiplied by the minimum band compression ratio. This is provided so the device can allocate a buffer of a suitable size to compress into.

The RIP will then open a file on the device for the raster data. The rasterized band data will be written to the device, and then the same file will be immediately read back to retrieve the compressed data and closed. Compressed data can be no longer than the raw rasterized band data. If the device cannot actually compress the data, it should return -1 for either the write or the read request.

◆ DeviceIOCtl_OSDeviceName

#define DeviceIOCtl_OSDeviceName   2

Opcode for DEVICELIST_IOCTL. Arg is a pointer to an OS_FILESPEC.

Deprecated:
Obsolete, provided for compatibility.

◆ DeviceIOCtl_ShortRead

#define DeviceIOCtl_ShortRead   0

Opcode for DEVICELIST_IOCTL.

Deprecated:
Obsolete, provided for compatibility.

◆ FONT_ND_CRYPT_DEVICE_TYPE

#define FONT_ND_CRYPT_DEVICE_TYPE   128

Device type for encrypting or decrypting OEM encrypted fonts.

This device type may optionally be provided by the RIP skin in a device type list passed through the SwStart() parameters.

This device type is used by the RIP when construcing the FONTDecode filter for reading or the FONTEncode filter for writing. Implementation of filters using devices is described in the Extensions Manual.

For certain font types, the data defining the outlines can be protected by custom encryption methods. The FONTDecode filter will be used to read outline data for rasterisation if a font is detected with custom encryption. The FONTEncode filter will be used for writing if the path data is requested from HDLT: custom encrypted font outlines will otherwise not be available from the RIP.

This device type may support an integer /Strategy parameter for different encryption methods. The RIP will create instances of the device by iterating the strategy values from MINPOSSIBLESTRATEGY to MAXPOSSIBLESTRATEGY when attempting to decode font data.

◆ LONGESTDEVICENAME

#define LONGESTDEVICENAME   50

Device names should not exceed this length.

◆ MAXPOSSIBLESTRATEGY

#define MAXPOSSIBLESTRATEGY   128

If provided, the FONT_ND_CRYPT_DEVICE_TYPE may support multiple methods for encrypting OEM font data. These "strategies" are iterated by index when the RIP is attempting to encrypt or decrypt font data. This is the last strategy index used by the RIP.

◆ MINPOSSIBLESTRATEGY

#define MINPOSSIBLESTRATEGY   1

If provided, the FONT_ND_CRYPT_DEVICE_TYPE may support multiple methods for encrypting OEM font data. These "strategies" are iterated by index when the RIP is attempting to encrypt or decrypt font data. This is the first strategy index used by the RIP.

◆ MONEVENT_DEVICE_TYPE

#define MONEVENT_DEVICE_TYPE   52

Device type used for sending textual output from %stdout, %stderr and %monitor.

This is a built-in device type to support issuing tagged monitor event messages from PostScript. This is an absolute device, supporting open, write, close, and parameters to tag the messages written to it. The parameters supported are:

/Channel (string or integer)
The monitor channel to tag message with. The value should be one of Monitor, Progress, Halftone, stdout, or stderr, or an integer.
/Encoding (string)
The name of the encoding in which the messages are written to the device. The device will attempt to transcode messages into UTF-8 for issuing through monitor events.
/Timeline (integer)
A timeline reference. PostScript code should not set this unless it has a reference passed to it by compiled code (e.g., another device). If not configured, the device will use the current interpreter timeline reference.
/UID (integer)
A unique ID for the monitor message. See the timelineapi.h header for information about how the unique ID should be constructed.

Linked code (from Plugins or the RIP skin) should use the event API directly.

◆ NULL_DEVICE_TYPE

#define NULL_DEVICE_TYPE   1

Data source/sink device type.

This is a built-in device type. It acts like an empty data source or sink for file operations, and returns DeviceIOError for most other operations.

◆ OS_DEVICE_TYPE

#define OS_DEVICE_TYPE   0

The OS file system device type.

This device type is expected to provide a FileSystem device, accessing files on the underlying operating system. It is expected to take a /Prefix parameter, which should set to root of the hierarchy accessed by the device (if supported by the underlying OS). A device type with this number must be provided by the RIP skin.

◆ PREBOOT_DEVICE_TYPE

#define PREBOOT_DEVICE_TYPE   18

Device to support alternate %os% mounting methods.

This device type may optionally be provided by the RIP skin in a device type list passed through the SwStart() parameters.

The preboot device type is a parameter-only device that allows device instances to be mounted and configured during the RIP boot sequence, primarily to allow the %os% device to be changed.

If a preboot device is discovered by the core during boot up, then its parameters are enumerated. The device's parameters are expected to be composite parameters, each with a key name and a dictionary value. The device named by the each parameter key will be mounted, and then the dictionary will be enumerated for key-value pairs to set as parameters on that device.

If the %os% device is mounted by this sequence, then the RIP boot continues as normal. If the %os% device is not mounted by this sequence, or there is no preboot device, then the %os% device is mounted on an instance of the OS_DEVICE_TYPE, with the default /Prefix provided by that device implementation. This method ensures compatibility for older RIPs and RIPs that lack a preboot device, but allows the RIP to provide options for mounting union or other complex devices before boot.

If a configuration generator device (%configps%) is desired by the OEM, then it could be added to the list of devices returned as parameters by the preboot device.

◆ PREFIX_DEVICE_TYPE

#define PREFIX_DEVICE_TYPE   19

Device type to add Prefix support to relative devices.

The is a built-in device type. It allows a sub-hierarchy of a file system to be referred to using shorter and simpler names. When accessing files, a prefix device prepends its prefix to the filename, and passes the operation to the underlying device. All other operations, except for setting and getting the /Prefix device parameter itself, are passed to the underlying device.

The RIP uses prefix device mounts for all sub-hierarchies of the %os% device that it mounts at start, including the default %tmp% location. If these or other sub-paths of %os% are mounted, it is important to use a prefix device to mount the path so it can function with a union device as %os% device.

Prefix devices can be mounted recursively on top of each other.

◆ RELATIVE_DEVICE_TYPE

#define RELATIVE_DEVICE_TYPE   17

Relative mapping device type.

This is a built-in device type provided to make multiple absolute devices appear as one relative device.

◆ setDevParamTypeAndCName

#define setDevParamTypeAndCName (   _dp,
  _type,
  _name 
)     setDevParamTypeAndName((_dp), (_type), (uint8 *)(_name), CSTRING_LENGTH(_name))

Utility macro to set the type and name of a DEVICEPARAM, using a constant C string for the name.

We cannot use CSTRING_AND_LENGTH() for the _name parameter expansion because macro expansion works outside in, and the number of parameters are already set.

◆ SW_DEVICE_NAME_PROGRESS

#define SW_DEVICE_NAME_PROGRESS   "progress"

A "well known" device name that can be passed to SwFindDevice().

◆ UNION_DEVICE_TYPE

#define UNION_DEVICE_TYPE   40

Unified view of multiple devices.

This device type may be built in to the RIP, depending on the product options.

The union device is used to make several PostScript devices appear as if they were one device. It is most useful for filesystem devices, but can be used for other types of devices too. The union device combines a set of read-only devices with an optional writable device, making them seamlessly appear like one device. Requests to open files, get parameters, read data, etc., are sent to the writable device first, and then down the sequence of readable devices until either the request is met, or the sequence of devices is exhausted. Files that appear on the writable device hide files of the same name on the readable devices, files on higher-priority readable devices hide files of the same name on lower priority readable devices. If an operation modifies a file that does not exist on the writable device but does exist on a readable device, data will be transferred from the readable device to the writable device. If a file is deleted, a special record will be written on the writable device that hides the file from other operations. File names are enumerated across all of the devices, excluding file names marked as deleted. The readable devices are never modified by file operations; only writable device files are modified.

The union device is configured through two device parameters:

/Read [ (%device%prefix)... ]
An array of one or more underlying readable devices. The devices may be specified as a device name only, or a device with a prefix. Names referenced on the union device are accessed on the readable devices by appending the name to this device and prefix. Whilst this device and prefix combination usually refers to a directory on the readable device, it does not need to. It may be an arbitrary partial path on the readable device. The first device in the array has the highest priority, files on it will hide files with the same name on devices later in the array.
/Write (%device%prefix)
An optional writable device and prefix. This is the device prefix used to write files that are modified or created on the union device. This may be set to an empty string (), in which case the union device will refuse all write operations.

You are cautioned not to modify the union device's /Read or /Write parameters whilst there are files open on the device. The same parameters can be set, however, so currentdevparams setdevparams will succeed.

The underlying devices for the union device need not be enabled nor searchable for the union to be enabled or searchable. It is indeed preferrable that they have /Enable set to false and /SearchOrder set to -1, so that they are not directly accessed by PostScript file operations. The /Enable and /Searchable (or /SearchOrder) keys of the union device itself control access to the entire collection.

It is important that only one instance of a union device maps the same writeable device and prefix. The union device caches some information in memory, so if two devices instances are created referring to the same writeable device, they will have inconsistent views of the file system state. Using the prefix device to map sub-trees of a file system is an important tool to ensure that there are not conflicting instances of the union device.

◆ VOIDPTR_TO_DEVICE_FILEDESCRIPTOR

#define VOIDPTR_TO_DEVICE_FILEDESCRIPTOR (   d)    ((DEVICE_FILEDESCRIPTOR)((uintptr_t)(d) >> 1))

Convert a (void*) to a device file descriptor.

Allocated data structures are assumed to be at least 4 byte aligned. Right shift is to ensure that the device file descriptor is not a negative value which is an invalid device file descriptor.

Typedef Documentation

◆ DEVICE_result

Type for return value from DEVICELIST_LAST_ERROR functions.

DEVICE_result is a subclass of HqnResult that also supports some specific extra error codes generated by devices (declared as the DEVICE_RESULT enumeration). Before assigning to values of HqnResult type or any of its other subclasses, DEVICE_result values must be converted to change the device specific values to HQN_RESULT_SUCCESS or a monitor UID error code greater than MON_CLASS_ERROR. This can be done by calling the function device_result_translate().

◆ DEVICELIST

typedef struct devicelist DEVICELIST

PostScript device instances.

These are instances of device types. This is stored in Harlequin core memory, and managed by the Harlequin core library. Do not change any fields in this structure.

◆ DEVICELIST_ABORT

typedef int32( * DEVICELIST_ABORT) ( DEVICELIST *dev, DEVICE_FILEDESCRIPTOR descriptor)

Device type method to abort action on an open file on a device instance.

Parameters
devThe current device.
descriptorA descriptor returned by a previous open call.
Returns
0 for success, -1 for failure.

Calling this method is equivalent to calling a DEVICELIST_CLOSE method, except that it signals an error in the processing of the file. Any data waiting to be written to the file will be discarded.

◆ DEVICELIST_BUFFER_SIZE

typedef int32( * DEVICELIST_BUFFER_SIZE) ( DEVICELIST *dev)

Optional device type method to return the buffer size that a device requires for best operation.

Parameters
devThe current device.
Returns
The buffer size requested in bytes. If this is less than zero, then the DEVICESMALLBUFF flag is examined to determine the size of the buffer.

◆ DEVICELIST_BYTES

typedef int32( * DEVICELIST_BYTES) ( DEVICELIST *dev, DEVICE_FILEDESCRIPTOR descriptor, Hq32x2 *bytes, int32 reason)

Device type method to get bytes available for an open file on a device instance.

Parameters
devThe current device.
descriptorA descriptor returned by a previous open call.
bytesThe number of bytes available.
reasonOne of SW_BYTES_AVAIL_REL, SW_BYTES_TOTAL_ABS.
Returns
TRUE if there are bytes available (in which case return 0 in bytes if the number is not known), FALSE for failure.

This routine returns the number of bytes available for reading without waiting. See the bytesavailable operator, described in [RB3]. If the number of bytes available is not known, but it is possible that there are some, 0 should be returned in bytes and TRUE should be returned. If the file has reached EOF or when some other error occurs, such as when the file is open for writing only, FALSE should be returned and the DEVICELIST_LAST_ERROR method should return DeviceIOError.

The value of reason is one of:

SW_BYTES_AVAIL_REL
Return the number of bytes immediately available after the current position.
SW_BYTES_TOTAL_ABS
Return the total extent of the file in bytes.

◆ DEVICELIST_CLOSE

typedef int32( * DEVICELIST_CLOSE) ( DEVICELIST *dev, DEVICE_FILEDESCRIPTOR descriptor)

Device type method to close an open file on a device instance.

Parameters
devThe current device.
descriptorA descriptor returned by a previous open call.
Returns
0 for success, -1 for failure.

Any data waiting to be written on the file will be written before this call returns. Note that the Harlequin Core itself buffers data read from or written to a file, and so the device implementation normally need not (and indeed should not) also implement a buffering scheme.

◆ DEVICELIST_DELETE

typedef int32( * DEVICELIST_DELETE) ( DEVICELIST *dev, uint8 *filename)

Device type method to remove a file from a device instance.

Parameters
devThe current device.
filenameThe name of a file to remove.
Returns
0 for success, -1 for failure.

This routine removes the file with the given name. If the file has been opened it is implementation-dependent whether any further operations can be done with the open file. This permits the file to be closed in the underlying operating system, if necessary, before deleting this file, as is necessary for example with Windows.

If there is no file named filename, then the DEVICELIST_LAST_ERROR method should return DeviceUndefined. If the device does not support renaming, or the particular filename is not permitted to be changed, then the DEVICELIST_LAST_ERROR method should return DeviceInvalidAccess. After any other failure, the DEVICELIST_LAST_ERROR method should return DeviceIOError.

◆ DEVICELIST_DISMOUNT

typedef int32( * DEVICELIST_DISMOUNT) ( DEVICELIST *dev)

Device type method to dismount the device instance.

Parameters
devThe current device.
Returns
0 for success, -1 for failure. This should normally return 0, even if most device operations are not implemented.

This routine is called when a device is dismounted. All files open when the Harlequin Core unmounted the device will have been closed. The routine should perform any required tasks, such as freeing any resources used by that device.

◆ DEVICELIST_END_LIST

typedef int32( * DEVICELIST_END_LIST) ( DEVICELIST *dev, void *handle)

Device type method to end iterating file names from a device instance.

Parameters
devThe current device.
handleA file list iterator pointer returned by the DEVICELIST_START_LIST method.
Returns
0 for success, -1 for failure.

This method is called to free any resources allocated to enumerate file names. If DEVICELIST_START_LIST was successful, this routine will be called at any time after it. It is possible that not all matches have been requested.

After a failure, the DEVICELIST_LAST_ERROR method should return DeviceIOError.

◆ DEVICELIST_GET_PARAM

typedef int32( * DEVICELIST_GET_PARAM) ( DEVICELIST *dev, DEVICEPARAM *param)

Device type method to get the next device parameter.

Parameters
devThe current device.
paramA structure in which to store the parameter value. If the paramname field is NULL, then store the next parameter in an iteration, otherwise store the value of the requested parameter.
Returns
One of the values: ParamIgnored, ParamAccepted, ParamError (or -1).

This routine has two functions. If the DEVICEPARAM::paramname field of the param argument is NULL when it is called, the next parameter name and value in an iteration started by DEVICELIST_START_PARAM should be returned through the DEVICEPARAM structure. If the DEVICEPARAM::paramname field is not NULL then the value of that specific parameter name should be returned through the DEVICEPARAM structure.

In the second case if the parameter name is not recognized the routine should return ParamIgnored, otherwise it should return ParamAccepted. If an error occurs, ParamError should be returned and the DEVICELIST_LAST_ERROR method should return an appropriate error code.

If not returning ParamIgnored, the DEVICEPARAM::type field must be set to one of DEVICEPARAM_type values. The appropriate union field and length if necessary should be set to the value of the parameter. If a string value is returned, the string value field should point to the device's local copy of the string. The RIP will copy the string into its own storage. If returning a composite object (an array or a dictionary), the implementation may allocate memory for the DEVICEPARAM array representing the composite object and store the memory pointer in the DEVICEPARAM::paramval.compobval field. The RIP will copy the value into its own storage as necessary. This memory should be freed by the device type implementation on the next call to DEVICELIST_GET_PARAM or DEVICELIST_START_PARAM. The client is required to call DEVICELIST_START_PARAM if the final call it made to DEVICELIST_GET_PARAM returned a composite object.

If returning the next parameter (DEVICEPARAM::paramname is NULL on function entry) the DEVICEPARAM::paramname field should be set to point to the name of the parameter being returned, and the DEVICEPARAM::paramnamelen field set to the length of that name.

Note
The iteration may not be thread-safe, so can generally only be used from PostScript language code, or code called from the PostScript language.

The Harlequin RIP SDK provides some utility routines to assist writing parameter methods:

◆ DEVICELIST_INIT

typedef int32( * DEVICELIST_INIT) ( DEVICELIST *dev)

Device type method to initialise a device instance.

Parameters
devThe current device.
Returns
0 for success, -1 for failure.

This call is made once for each device instance, and will be the first call for the device instance.

◆ DEVICELIST_IOCTL

typedef int32( * DEVICELIST_IOCTL) ( DEVICELIST *dev, DEVICE_FILEDESCRIPTOR fileDescriptor, int32 opcode, intptr_t arg)

Device type method for miscellaneous control options.

Parameters
devThe current device.
fileDescriptorA descriptor returned by a previous open call.
opcodeA device-specific value, or one of the generic values:
DeviceIOCtl_PDFFilenameToPS
This may be used on file system devices, when interpreting PDF files. The data value arg should be cast to a PDF_FILESPEC. The filename in this structure should be converted from a platform specific form to a generic form.
DeviceIOCtl_OSDeviceName
This may be used on file system devices, when interpreting SOAR host device files. The data value arg should be cast to an OS_FILESPEC. The filename in this structure should be converted from a platform specific form to a suitable form for the %os% device.
DeviceIOCtl_RasterRequirements
Only used by the page buffer device. The data value arg should be cast to a RASTER_REQUIREMENTS pointer.
DeviceIOCtl_RenderingReady
Only used by the page buffer device. The data value arg should be cast to a RASTER_REQUIREMENTS pointer.
DeviceIOCtl_RenderingPass
Only used by the page buffer device. The data value arg should be cast to a RASTER_REQUIREMENTS pointer.
DeviceIOCtl_RenderingSheet
Only used by the page buffer device. The data value arg should be cast to a RASTER_REQUIREMENTS pointer.
DeviceIOCtl_GetBufferForRaster
Only used by the page buffer device. The data value arg should be cast to a RASTER_DESTINATION pointer.
DeviceIOCtl_RasterBandSize
Only used by the page buffer device. The data value arg should be cast to a RASTER_BANDSIZE pointer.
DeviceIOCtl_BlankPage
Only used by the page buffer device. The data value arg should be cast to a RASTER_BLANK pointer.
Parameters
argA data parameter for the control function.
Return values
0for success
-1for failure.
-2if the opcode is not implemented.

◆ DEVICELIST_LAST_ERROR

typedef DEVICE_result( * DEVICELIST_LAST_ERROR) ( DEVICELIST *dev)

Device type method to return last error for a device instance.

Parameters
devThe current device.
Returns
One of the values: DeviceNoError, DeviceInvalidAccess, DeviceIOError, DeviceLimitCheck, DeviceUndefined, DeviceUnregistered, DeviceVMError, DeviceTimeout, DeviceInterrupted. The %pagebuffer% device may also return one of: DeviceReOutput, DeviceNotReady, DeviceCancelPage, DeviceReOutputPageBuffer. Any value greater than or equal to MON_CLASS_ERROR will be interpreted as a sw_mon_type error UID, and may be deconstructed using the macros in monevent.h to get the error subclass, PostScript error, and error UID.

This method should use a thread local variable to store and retrieve the error code. The device instance may be called from multiple different RIP or SDK threads. The RIP skins provide the functions skindevices_set_last_error() and skindevices_last_error() that a device type implementation can use to set or retrieve a thread-local variable containing the device error.

◆ DEVICELIST_NEXT

typedef int32( * DEVICELIST_NEXT) ( DEVICELIST *dev, void **handle, uint8 *pattern, FILEENTRY *entry)

Device type method to get the next file in an iteration.

Parameters
devThe current device.
handleA file list iterator pointer returned by the device type's DEVICELIST_START_LIST method.
patternThe pattern passed to the DEVICELIST_START_LIST method.
entryA structure in which to store the next matching filename.
Returns
One of the values: FileNameMatch, FileNameRangeCheck, FileNameNoMatch, FileNameError (or -1).

If there is another match for the pattern, a pointer to the filename should be stored in the entry argument's FILEENTRY::name field, and its length should be stored in the FILEENTRY::namelength field. The file name need not be zero-terminated. It must not be string on the C stack. The return value of the method should be FileNameMatch if there was a match.

After a failure, the DEVICELIST_LAST_ERROR method should return:

FileNameRangeCheck
If the filename is too long.
FileNameNoMatch
If there are no more matches.
FileNameError
If an error occurred while looking for a match.

After a failure, the DEVICELIST_LAST_ERROR method should return DeviceIOError.

Note that if the underlying file system supports directories and the permissions on one or more directories do not allow the filenames in those directories to be enumerated this should not be treated as an error. The routine should just ignore those directories and continue the search for matches.

The Harlequin Core provides two routines to help implement this method in a device type. These are:

  • SwPatternMatch(), which returns TRUE if a zero-terminated string matches a zero-terminated pattern, or FALSE if the string does not match the pattern.
  • SwLengthPatternMatch(), which is similar to SwPatternMatch(), but the pattern and string are given by start address and length, and need not be zero-terminated.

◆ DEVICELIST_OPEN

typedef DEVICE_FILEDESCRIPTOR( * DEVICELIST_OPEN) ( DEVICELIST *dev, uint8 *filename, int32 openflags)

Device type method to open a file on a device instance.

Parameters
devThe current device.
filenameThe file name to open.
openflagsOne of the following: SW_RDONLY, SW_WRONLY, SW_RDWR, Combined (using bitwise OR) with any combination of: SW_APPEND, SW_CREAT, SW_TRUNC, SW_EXCL.
Returns
A non-negative file descriptor if successful, -1 for failure.

Descriptors have to be unique only for each device; different devices (even of the same device type) can use the same number for different files without confusion.

The PostScript language model of files is of a stream of bytes; that is, there is no record structure or distinction between binary and text files. The implementation of this method call must open the file in the appropriate way to support this (for example, by opening all files in binary mode on Windows).

After a failure, the DEVICELIST_LAST_ERROR method should return:

DeviceUndefined
If the filename is invalid for the device, or the file does not exist and the value of openflags does not imply creation.
DeviceInvalidAccess
If the requested access set by openflags are not allowed for this file.
DeviceLimitCheck
If the file cannot be opened because to do so would exceed some implementation-defined limit on the number of open files.
DeviceVMError
If the device type implementation could not allocate memory required to represent the open file.
DeviceIOError
For any other error that cannot be distinguished.

◆ DEVICELIST_READ

typedef int32( * DEVICELIST_READ) ( DEVICELIST *dev, DEVICE_FILEDESCRIPTOR descriptor, uint8 *buff, int32 len)

Device type method to read data from an open file on a device instance.

Parameters
devThe current device.
descriptorA descriptor returned by a previous open call.
buffBuffer into which the data read is stored.
lenThe maximum number of bytes to read.
Returns
The number of bytes of data read on success, 0 if the file is at EOF, or -1 for failure.

Unless the device type specifies an explicit size (as described in device_buffersize determine file buffer size the space available in buff (len) is guaranteed to be at least 1024 bytes, although the read routine can return fewer if appropriate.

If an error occurs, the Harlequin Core will not assume anything about the contents of the buffer. Thus, it is safe to put bytes into this buffer even if an error occurs at some point before all the bytes have been read. After a failure, the DEVICELIST_LAST_ERROR method should return DeviceIOError.

◆ DEVICELIST_RENAME

typedef int32( * DEVICELIST_RENAME) ( DEVICELIST *dev, uint8 *file1, uint8 *file2)

Device type method to rename a file on a device instance.

Parameters
devThe current device.
file1The name of a file to rename.
file2The name to which file1 will be renamed.
Returns
0 for success, -1 for failure.

If there is no file named file1, then the DEVICELIST_LAST_ERROR method should return DeviceUndefined. If the device does not support renaming, or the particular filenames are not permitted to be changed, then the DEVICELIST_LAST_ERROR method should return DeviceInvalidAccess. After any other failure, the DEVICELIST_LAST_ERROR method should return DeviceIOError.

◆ DEVICELIST_SEEK

typedef int32( * DEVICELIST_SEEK) ( DEVICELIST *dev, DEVICE_FILEDESCRIPTOR descriptor, Hq32x2 *destn, int32 flags)

Device type method to seek an open file on a device instance.

Parameters
devThe current device.
descriptorA descriptor returned by a previous open call.
destnThe location to seek to.
flagsOne of SW_SET, SW_INCR, SW_XTND.
Returns
TRUE for success, FALSE for failure.

Some devices will be able to support positionable files that is, there is a current file position associated with the open file and the next read or write will read from, or write to, bytes at that point, and this current file position can be set.

The flags parameter indicates how the destn parameter should be interpreted. If flags is SW_SET, the current file position should be set to destn bytes from the start of the file. If flags is SW_INCR, the current file position should be changed by destn bytes, and if flags is SW_XTND, the current file position should be set to the length of the file plus destn. If this results in the current file position being beyond the current end of the file, the file is open for writing, and the file permissions allow it to be extended, then file will be extended to the current file position. [RB3] does not specify the values in any bytes between the old and new lengths of the file.

Calls to this method with a value of zero in the destn argument have special meanings. The meaning of such a call depends on the value of the flags argument. Even if a device cannot support seeking, it is usually possible to implement support for some or all of these special calls:

SW_SET
The RIP uses this flags value and a destn value of zero to ask a device if it supports arbitrary seeks. A device should return TRUE if it does, or FALSE otherwise.
SW_INCR
The RIP uses this flags value and a destn value of zero when it wants to know the current file position. It is often possible to support this feature even when other seeks are not supported. If supported, the file position value should be written back into destn.
SW_XTND
The RIP uses this flags value and a destn value of zero to ask a device to flush the file, discarding any remaining input. This may not always require reading the remaining input for example, a network connection could be shut down instead.

After a failure, the DEVICELIST_LAST_ERROR method should return DeviceIOError.

◆ DEVICELIST_SET_PARAM

typedef int32( * DEVICELIST_SET_PARAM) ( DEVICELIST *dev, DEVICEPARAM *param)

Device type method to set a device parameter.

Parameters
devThe current device.
paramA structure describing the parameter to set and its value.
Returns
One of the values: ParamAccepted, ParamTypeCheck, ParamRangeCheck, ParamConfigError, ParamIgnored, ParamError (or -1).

The PostScript language operator setdevparams will call this device routine. The param argument specifies the device parameter name and its value in the DEVICEPARAM structure. Parameters are always named by a string, specified by DEVICEPARAM::paramname and DEVICEPARAM::paramnamelen, and accessible through theIDevParamName() and theIDevParamNameLen() macros. Note that the parameter name is not necessarily zero-terminated, the parameter length should always be checked when accessing the parameter name.

The DEVICEPARAM::type field indicates the type of the parameter to set. This will be one of:

ParamBoolean
A boolean value is stored in the DEVICEPARAM::paramval.boolval union field, accessible through theIDevParamBoolean() macro.
ParamInteger
An integer value is stored in the DEVICEPARAM::paramval.intval union field, accessible through theIDevParamInteger() macro.
ParamFloat
A real value is stored in the DEVICEPARAM::paramval.floatval union field, accessible through theIDevParamFloat() macro.
ParamNull
No value is stored. The interpretation of a null parameter depends on the device type.
ParamString
A real value is stored in the DEVICEPARAM::paramval.strval union field and the DEVICEPARAM::paramval.strvallen length, accessible through theIDevParamString() and theIDevParamStringLength() macros. Note that this string value is not necessarily zero-terminated, the string length should always be checked when accessing string values.

Strings set using this method are stored in the Harlequin Core internal memory which may be re-used; therefore, if the device needs to keep referring to the string, it must copy it into its own memory.

ParamArray
An array of DEVICEPARAM structures are stored in the DEVICEPARAM::paramval.compobval union field and the DEVICEPARAM::paramval.strvallen length, accessible through theIDevParamArray() and theIDevParamArrayLen() macros. The DEVICEPARAM structures in this array (and any sub-objects in them) are only guaranteed to remain valid for the duration of this method invocation. Therefore, if the device needs to keep referring to them, it must copy them into its own memory or unpack them into device-specific structures. The parameter name fields of the array of DEVICEPARAM structures are not used, and should not be dereferenced.
ParamDict
An array of DEVICEPARAM structures (arranged in pairs) are stored in the DEVICEPARAM::paramval.compobval union field and the DEVICEPARAM::paramval.strvallen length, accessible through theIDevParamDict() and theIDevParamDictLen() macros. The array of DEVICEPARAM structures is twice the length of theIDevParamDictLen(). The first structure in each pair represents a dictionary key; the second structure in each pair represents a dictionary value. The DEVICEPARAM structures in this array (and any sub-objects in them) are only guaranteed to remain valid for the duration of this method invocation. Therefore, if the device needs to keep referring to them, it must copy them into its own memory or unpack them into device-specific structures. The parameter name fields of the array of DEVICEPARAM structures are not used, and should not be dereferenced.

This method returns a code to indicate the success or failure of setting the parameter:

ParamAccepted
The value ParamAccepted means that the parameter has been set successfully. This does not necessarily mean the exact value was used, or that the parameter will read back with the value just set: these are implementation defined.
ParamTypeCheck
ParamTypeCheck means the value set was an incorrect type for the parameter of that name.
ParamRangeCheck
ParamRangeCheck indicates that the value was unreasonable for the device parameter.
ParamConfigError
ParamConfigError indicates that the value of the parameter was reasonable, but not achievable with this implementation.
ParamIgnored
If the parameter name is not supported by this device, ParamIgnored should be returned.
ParamError
ParamError means that some other error occurred for example, this error might be that configuring underlying hardware failed. If ParamError is returned, the DEVICELIST_LAST_ERROR method should return an appropriate error code.

The following device parameters are valid for all devices, and are not passed to the device. They are handled internally by the Harlequin Core:

/Password
See the description of setdevparams in [RB3].
/DeviceType
Binds an uninitialized device mount to a particular device type, and initializes an instance of the device.
/Enable
If set to true, permits file system operations on that device. An invalidaccess error is generated if the device's type has not been set yet.

The Harlequin RIP SDK provides some utility routines to assist writing parameter methods:

◆ DEVICELIST_START_LIST

typedef void*( * DEVICELIST_START_LIST) ( DEVICELIST *dev, uint8 *pattern)

Device type method to start iterating file names on a device instance.

Parameters
devThe current device.
patternA file pattern to match.
Returns
A pointer to an iterator structure if successful, NULL for failure. If it is known that no files match the pattern, then NULL may be returned, and an immediate call to the DEVICELIST_LAST_ERROR routine should return DeviceNoError.

This routine should do any initializion necessary such that successive calls to DEVICELIST_NEXT return filenames matching that template. The pointer returned by this function will be passed to the each call to DEVICELIST_NEXT. The implementation of DEVICELIST_NEXT should use the pointer to identify where in the enumeration of files matching this pattern it has reached. It is possible to have recursive calls to filenameforall, so nested filename enumerations must be supported.

If for some reason the enumeration cannot be started, the routine should return NULL. After a failure, the DEVICELIST_LAST_ERROR method should return:

DeviceNoError
If it is known that the enumeration will never return a matching file name. In this case the RIP will not then call DEVICELIST_NEXT and DEVICELIST_END_LIST.
DeviceLimitCheck
If the nesting level of filename enumerations is too deep, or some other limit has been exceeded.
DeviceVMError
If the device type implementation could not allocate memory required to enumerate files matching the pattern.
DeviceIOError
For any other error that cannot be distinguished.

If this function succeeds, the device type's DEVICELIST_END_LIST method must be called after iterating file names.

◆ DEVICELIST_START_PARAM

typedef int32( * DEVICELIST_START_PARAM) ( DEVICELIST *dev)

Device type method to start iterating device parameters.

Parameters
devThe current device.
Returns
The number of device parameters to enumerate (this may be 0 if there are no device parameters), or -1 for failure.

This routine is called by the PostScript language operator currentdevparams to determine how many parameters will be returned, and to start enumerating them. The number returned need not be the same as the number of device parameter names recognized by the device, because some device parameters can be write only, or a parameter may only be returned once a value has been set for it. The number excludes the parameters that are handled by the interpreter itself (/Password, /DeviceType, /Enable). Following this call, DEVICELIST_GET_PARAM will be called multiple times with a NULL DEVICEPARAM::paramname field to get each of the parameters.

If there are no such device parameters, 0 should be returned. If an error occurs, -1 should be returned.

Note
The iteration may not be thread-safe, so can generally only be used from PostScript language code, or code called from the PostScript language.

◆ DEVICELIST_STATUS_DEVICE

typedef int32( * DEVICELIST_STATUS_DEVICE) ( DEVICELIST *dev, DEVSTAT *devstat)

Device type method to get the status of the device instance.

Parameters
devThe current device.
devstatA structure in which to return the status of the device.
Returns
0 for success, -1 for failure.

This routine returns information on the device. The interpretation of these is device-dependent, but for a device that supports files such as a hard disk:

  • DEVSTAT::block_size is the size of blocks on the device.
  • DEVSTAT::size is the total size of the device.
  • DEVSTAT::free is the amount of space available on the device.

◆ DEVICELIST_STATUS_FILE

typedef int32( * DEVICELIST_STATUS_FILE) ( DEVICELIST *dev, uint8 *filename, STAT *statbuff)

Device type method to check status of a file by name.

Parameters
devThe current device.
filenameThe file to check status.
statbuffPointer to a structure in which to put the file status.
Returns
0 for success, -1 for failure.

This routine returns information about a named file on the device. If the file exists, the fields in the structure pointed to by the statbuff argument should be set appropriately and 0 is returned to indicate success:

  • The STAT::bytes field should be set to the length of the file in bytes.
  • The STAT::referenced field should be set to the time of the last read or write operation to that file.
  • The STAT::created field should be set to the time that the file was created.

Suitable default values may be substituted for either time if they are not supported by the underlying file system. The time units and origin are not defined by [RB3]: the only legal interpretation of these values by a PostScript language program is to assume that a larger value means a later time. This implies that the value should not overflow a signed 32-bit integer in the near future. Global Graphics recommends that if the implementation has a real time clock, the times should be measured in seconds since 00:00:00 (midnight), 1st Jan. 1970. If additionally, the implementation supports time zones, this should be in measured in the UTC time zone. This is the same as the UNIX definition. If there is no real time clock, any monotonically increasing value can be used. If files persist between invocations of the product, the current value of this "clock" must be stored in some permanent storage.

After a failure, the DEVICELIST_LAST_ERROR method should return DeviceIOError.

◆ DEVICELIST_WRITE

typedef int32( * DEVICELIST_WRITE) ( DEVICELIST *dev, DEVICE_FILEDESCRIPTOR descriptor, uint8 *buff, int32 len)

Device type method to write data to an open file on a device instance.

Parameters
devThe current device.
descriptorA descriptor returned by a previous open call.
buffBuffer from which the data written is taken.
lenThe maximum number of bytes to write.
Returns
The number of bytes of data written on success, or -1 for failure.

After a failure, the DEVICELIST_LAST_ERROR method should return DeviceIOError.

◆ DEVICETYPE

typedef struct DeviceType DEVICETYPE

This is the structure used to represent a device type (class) implementation in the Harlequin RIP core.

A number of macros, e.g., theIDevTypeNumber(), are for convenience in accessing the fields of the structures: don't feel obliged to use them. You may want to call methods functions on a device in your own code, and the macros provide a notation for doing so.

◆ OS_FILESPEC

typedef struct _os_filespec OS_FILESPEC

A pointer to OS_FILESPEC will be passed as the arg to DEVICELIST_IOCTL routine when opcode is DeviceIOCtl_OSDeviceName.

The filename specifies the name of a file for which an %os% device filename is required.

On entry to DEVICELIST_IOCTL the buffer member must contain a pointer to and the length of the buffer to be written to. If the call is successful buffer.len will contain the byte count of the contents written into the buffer.

◆ PDF_FILESPEC

typedef struct _pdf_filespec PDF_FILESPEC

PDF_FILESPEC - a pointer to PDF_FILESPEC will be passed as the arg to DEVICELIST_IOCTL when the opcode is DeviceIOCtl_PDFFilenameToPS.

The constants PDF_FILESPEC_XXX specify information about the arguments passed through in the members filename and filesytem. All the other members must be specified.

On entry to DEVICELIST_IOCTL the buffer member must contain a pointer to and the length of the buffer to be written to. If the call is successful buffer.len will contain the byte count of the contents written into the buffer.

Enumeration Type Documentation

◆ DEVICE_RESULT

Last error return values.

The DEVICELIST_LAST_ERROR function may return these codes, or any value greater than MON_CLASS_ERROR. Values greater than MON_CLASS_ERROR will be interpreted as sw_mon_type error UIDs, and may be deconstructed using the macros in monevent.h to get the error subclass, PostScript error equivalent, and error UID. This is the preferred method to pass detailed errors from devices.

Enumerator
DeviceNoError 

Status code for success.

DeviceInvalidAccess 

Status code for wrong access permissions.

DeviceIOError 

Status code for I/O error.

DeviceLimitCheck 

Status code for a parameter out of range.

DeviceUndefined 

Status code for unknown file/device.

DeviceUnregistered 

Status code for an illegal operation.

DeviceInterrupted 

Status code for an interrupt.

DeviceVMError 

Status code for out of memory.

DeviceReOutput 
Deprecated:
Status code to request reoutputting the page.
DeviceNotReady 

Status code for output channel not ready.

DeviceCancelPage 

Status code to cancel the page.

DeviceReOutputPageBuffer 
Deprecated:
Status code to request reoutputting the page buffer.
DeviceTimeout 

Status code for a timeout.

◆ DEVICELIST_BYTES_reasons

DEVICELIST_BYTES reason codes

Enumerator
SW_BYTES_AVAIL_REL 

Indicates the byte count returned is the amount immediately available after the current position.

SW_BYTES_TOTAL_ABS 

Indicates the byte count returned is the total extent of file in bytes.

◆ DEVICELIST_NEXT_result

DEVICELIST_NEXT return codes

Enumerator
FileNameNoMatch 

no file name match

FileNameMatch 

file name matched

FileNameError 

error

FileNameIOError 

I/O error. Synonymous with FileNameError, for upward compatibility

FileNameRangeCheck 

range error

◆ DEVICELIST_OPEN_flags

DEVICELIST_OPEN flags

Enumerator
SW_RDONLY 

Open for reading only.

SW_WRONLY 

Open for writing only.

SW_RDWR 

Open for reading or writing.

SW_APPEND 

Open (write guaranteed at end)

SW_CREAT 

Open with file create.

SW_TRUNC 

Open with truncation.

SW_EXCL 

Open with exclusive access.

SW_FROMPS 

Open by the PostScript "file" operator.

SW_FONT 

Possibly try to open font resource if any.

◆ DEVICELIST_SEEK_flags

DEVICELIST_SEEK flags

Enumerator
SW_SET 

Absolute offset.

SW_INCR 

Relative to current offset.

SW_XTND 

Relative to end of file.

◆ DEVICELIST_SET_PARAM_result

DEVICELIST_SET_PARAM return codes

Enumerator
ParamAccepted 

Parameter accepted successfully.

ParamTypeCheck 

Parameter is wrong type.

ParamRangeCheck 

Parameter is out of range.

ParamConfigError 

Configuration error on parameter.

ParamIgnored 

Parameter ignored.

ParamError 

Error return code from DEVICELIST_SET_PARAM. Set if last_error should be checked.

◆ DEVICEPARAM_type

DEVICEPARAM::type values.

Enumerator
ParamBoolean 

DEVICEPARAM is boolean.

ParamInteger 

DEVICEPARAM is integer.

ParamString 

DEVICEPARAM is string.

ParamFloat 

DEVICEPARAM is float.

ParamArray 

DEVICEPARAM is array.

ParamDict 

DEVICEPARAM is dictionary.

ParamNull 

DEVICEPARAM is null *‍/.

◆ DEVICETYPE_flags

Bit mask flags for DEVICETYPE::devicetypeflags.

Enumerator
DEVICEABSOLUTE 

Flag "set" if device must not take file name

DEVICERELATIVE 

Flag set if device must take file name

DEVICEWRITABLE 

Set if device can be written to

DEVICESMALLBUFF 

A smaller buffer is used

DEVICELINEBUFF 

Files of dev type will be line buffered

DEVICEENABLED 

Flag set if device in search path

DEVICEREMOVABLE 

Set if media can be removed

DEVICENOSEARCH 

Set if a general filenameforall omits the device (SearchOrder set to -1)

DEVICEUNDISMOUNTABLE 

Set if device can't be dismounted

◆ PDF_FILESPEC_values

PDF_FILESPEC flags.

Enumerator
PDF_FILESPEC_None 

unspecified

PDF_FILESPEC_PDF 

PDF filename.

PDF_FILESPEC_DOS 

Dos based filename.

PDF_FILESPEC_Mac 

Mac based filename.

PDF_FILESPEC_Unix 

Unix based filename.

PDF_FILESPEC_FS 

filesystem slot is defined

Function Documentation

◆ device_result_translate()

HqnResult device_result_translate ( DEVICE_result  result)

Translate a device API-specific error code to a generic HqnResult error code.

Parameters
[in]resultOne of the DEVICE_RESULT values, or an error value greater than MON_CLASS_ERROR.
Returns
Either HQN_RESULT_SUCCESS, or an error value greater than MON_CLASS_ERROR.

◆ skindevices_finish_last_error()

void skindevices_finish_last_error ( void  )

Finish error handling for skin devices.

After this call, neither skindevices_last_error() nor skindevices_set_last_error() should be called.

◆ skindevices_init_last_error()

HqBool skindevices_init_last_error ( void  )

Initialise error handling for skin devices.

Neither skindevices_last_error() nor skindevices_set_last_error() should be called before this function.

Return values
TRUESkin device error handling was initialised. skindevices_finish_last_error() should be called to terminate error handling when finished.
FALSESkin device error handling was not initialised. The RIP should terminate without calling skindevices_finish_last_error().

◆ skindevices_last_error()

DEVICE_result skindevices_last_error ( DEVICELIST dev)

Method call for use in device definitions to get the last error for skin devices.

Returns
The thread local error value for this thread.

The protocol for handling device errors is that the device should set a thread-local storage value to the error, and the caller should retrieve the value immediately on return using the device's last_error call. Errors set by other threads simultaneously accessing the same device will not affect the thread local value. This call gets the thread local error value.

◆ skindevices_set_last_error()

void skindevices_set_last_error ( DEVICE_result  error)

Set the last error for a skin device.

Parameters
errorThe error number to set for this thread.

The protocol for handling device errors is that the device should set a thread-local storage value to the error, and the caller should retrieve the value immediately on return using the device's last_error call. Errors set by other threads simultaneously accessing the same device will not affect the thread local value. This call sets the thread local error value.

◆ SwAlloc()

uint8* SwAlloc ( int32  bytes)

Dynamically allocate memory from the core rip's memory space.

The three functions, SwAlloc(), SwRealloc(), and SwFree(), allow external devices to dynamically allocate memory from the core rip's memory space. These functions can be safely called any time after SwInit() and before the RIP is shutdown. Large blocks should be freed as soon as possible to avoid interfering with jobs.

Parameters
bytesThe size in bytes of the memory block to allocate.
Returns
A pointer to a new block of memory, or NULL if a block of bytes could not be allocated. If a new block of memory was allocated, it must be deallocated using SwFree() or reallocated using SwRealloc() at some future point before the RIP is shut down.

The Harlequin RIP SDK also supports the functions MemAlloc() and MemFree(), which should be used for allocations in the same memory arena as the RIP, but which may be made before the RIP is booted, or may persist after the RIP is shut down.

◆ SwFree()

void SwFree ( void *  pointer)

Free memory dynamically allocated from the core rip's memory space by SwAlloc() or SwRealloc().

Parameters
pointerA pointer to memory previously returned by SwAlloc() or SwRealloc(), and not subsequently freed.

The Harlequin RIP SDK also supports the functions MemAlloc() and MemFree(), which should be used for allocations in the same memory arena as the RIP, but which may be made before the RIP is booted, or may persist after the RIP is shut down.

◆ SwLengthPatternMatch()

int32 SwLengthPatternMatch ( uint8 pattern,
int32  plen,
uint8 string,
int32  slen 
)

For use in DEVICELIST_NEXT to assist pattern matching on file names.

Parameters
[in]patternA pattern to match. The wildcards '?' and '*' match any single character and any sequence of characters in string respectively. These wildcards may be escaped as '\?' or '*' to match an explicit question mark or asterisk.
plenThe length in bytes of pattern.
[in]stringA zero-terminated string to match against pattern.
slenThe length in bytes of string.
Return values
TRUEif string was matched by pattern.
FALSEif there was no match.

◆ SwPatternMatch()

int32 SwPatternMatch ( uint8 pattern,
uint8 string 
)

For use in DEVICELIST_NEXT to assist pattern matching on file names.

Parameters
[in]patternA zero-terminated pattern to match. The wildcards '?' and '*' match any single character and any sequence of characters in string respectively. These wildcards may be escaped as '\?' or '*' to match an explicit question mark or asterisk.
[in]stringA zero-terminated string to match against pattern.
Return values
TRUEif string was matched by pattern.
FALSEif there was no match.

◆ SwReadFilterBytes()

int32 SwReadFilterBytes ( DEVICELIST dev,
uint8 **  ret_buff 
)

Utility function to help when the RIP is reading bytes from a custom filter via the device interface.

This function allows the Core RIP's pluggable device filter mechanism to read bytes from a device directly into the RIP's underlying filter buffer, without extra copying. It should be used in the device implementation's DEVICETYPE::read_file() method to get bytes from the device's underlying filter.

Parameters
devThe DEVICELIST for this instance of the filter device type.
[out]ret_buffOn exit, this is set to a pointer to a buffer containing bytes from the underlying filter. This buffer of data is assumed to have been read from the underlying filter.
Returns
>0 Values greater than zero are the number of bytes in *ret_buff.
Return values
0End of file on the underlying filter (no more bytes).
-1I/O error on the underlying filter.

◆ SwRealloc()

uint8* SwRealloc ( void *  pointer,
int32  bytes 
)

Reallocate memory dynamically allocated from the core rip's memory space using SwAlloc(), preserving existing contents.

Parameters
pointerA pointer to memory previously returned by SwAlloc() or SwRealloc(), and not subsequently freed.
bytesThe size in bytes of the re-allocated memory block. The existing contents memory in pointer (up to bytes, if shorter than the previous allocation) are copied into the new block allocated.
Returns
A pointer to a new block of memory, or NULL if a block of bytes could not be allocated. If a new block of memory was allocated, the memory at pointer has been freed and should not be dereferenced again; the new block of memory must be deallocated using SwFree() or reallocated using SwRealloc() at some future point before the RIP is shut down. If a new block of memory could not be allocated, the existing allocation at pointer is not affected and must still be deallocated using SwFree() at some point before the RIP is shut down.

Use of this function is discouraged: re-allocators are notoriously prone to misuse. This function has mainly been provided to help the integration of third-party libraries, allowing their memory management to use the RIP's memory space.

The Harlequin RIP SDK also supports the functions MemAlloc(), MemRealloc() and MemFree(), which should be used for allocations in the same memory arena as the RIP, but which may be made before the RIP is booted, or may persist after the RIP is shut down.

◆ SwReplaceFilterBytes()

int32 SwReplaceFilterBytes ( DEVICELIST dev,
int32  len 
)

Utility function to help when the RIP is reading bytes from a custom filter via the device interface.

This function is used to backtrack the underlying file ptr over unused bytes obtained by SwReadFilterBytes(). The underlying file may return buffered data from a file or other source that extends past the end of the data that the device filter should consume. This call allows the device filter to return that data to the underlying filter's buffer so that a subsequent caller can interpret it.

Parameters
devThe DEVICELIST for this instance of the filter device type.
lenThe number of bytes at the end of the previous SwReadFilterBytes() call which should not have been consumed.
Return values
0if successful
EOFif there is a consistency check error.

◆ SwSeekFilterBytes()

int32 SwSeekFilterBytes ( DEVICELIST dev,
int32  offset 
)

Utility function to help when the RIP is seeking on a custom filter via the device interface.

Seek on the underlying file ptr for the device filter, if seekable.

Parameters
devThe DEVICELIST for this instance of the filter device type.
offsetAn offset from the start position of the filter stream.
Return values
0if successful,
-1if a consistency check error or I/O error.

◆ SwTestAndTickle()

int32 SwTestAndTickle ( void  )

This is a wrapper to SwOften() for use when adding custom filters via the device interface.

See also
SwOften().

◆ SwWriteFilterBytes()

int32 SwWriteFilterBytes ( DEVICELIST dev,
uint8 buff,
int32  len 
)

Utility function to help when the RIP is writing bytes to a custom filter via the device interface.

This function allows the Core RIP's pluggable device filter mechanism to write bytes from a device to the RIP's underlying filter. It should be used in the device implementation's DEVICETYPE::write_file() method to send bytes to the next filter in the chain.

Parameters
devThe DEVICELIST for this instance of the filter device type.
[in]buffA buffer containing bytes to write to the underlying filter.
lenThe number of bytes to write to the underlying filter.
Returns
Number of bytes written to the underlying filter, or -1 on error.