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... | |
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... | |
DEVICELIST * | SwFindDevice (uint8 *deviceName) |
Looks up a device by name, returns NULL on failure. | |
uint8 * | SwAlloc (int32 bytes) |
Dynamically allocate memory from the core rip's memory space. More... | |
uint8 * | SwRealloc (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... | |
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:
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:
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:
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.
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.
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.
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.
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.
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
.
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:
/Enable
parameter to setdevparams
). Devices that are not enabled are excluded from search operations and explicit file operations from PostScript or PDF. Special-purpose devices that are only called from C or C++ code often have this flag set.filenameforall
, but other file operations (opening, reading, etc.) are allowed if the device is enabled. Special-purpose devices that do not behave as file systems should have this flag set.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:
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.
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:
devmount
and setdevparams
operators.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:
/DeviceType
number and store it in the device instance's DEVICELIST::devicetype field.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
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 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.
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:
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:
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.
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.
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:
OEM numbers are allocated by Global Graphics Software.
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.
A number of device types are defined by the core library interface.
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.
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.
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
This is a built-in device type provided to make multiple absolute devices appear as one relative device.
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.
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.
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:
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.
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:
()
, 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.
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:
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.
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.
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.
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:
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.
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%
.
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.
This device translates JSON configurations read from the PS configuration device into PostScript configuration commands. See JSON configuration.
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.
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.
These are alternate names for a legacy device for handling output messages from the RIP core. See the legacy monitor and console devices.
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:
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.
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.
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().
#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
#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:
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.
#define DeviceIOCtl_OSDeviceName 2 |
Opcode for DEVICELIST_IOCTL. Arg is a pointer to an OS_FILESPEC.
#define DeviceIOCtl_ShortRead 0 |
Opcode for DEVICELIST_IOCTL.
#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.
#define LONGESTDEVICENAME 50 |
Device names should not exceed this length.
#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.
#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.
#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:
Linked code (from Plugins or the RIP skin) should use the event API directly.
#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.
#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.
#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.
#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.
#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.
#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.
#define SW_DEVICE_NAME_PROGRESS "progress" |
A "well known" device name that can be passed to SwFindDevice().
#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:
()
, 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.
#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 HqnResult 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().
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.
typedef int32( * DEVICELIST_ABORT) ( DEVICELIST *dev, DEVICE_FILEDESCRIPTOR descriptor) |
Device type method to abort action on an open file on a device instance.
dev | The current device. |
descriptor | A descriptor returned by a previous open call. |
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.
typedef int32( * DEVICELIST_BUFFER_SIZE) ( DEVICELIST *dev) |
Optional device type method to return the buffer size that a device requires for best operation.
dev | The current device. |
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.
dev | The current device. |
descriptor | A descriptor returned by a previous open call. |
bytes | The number of bytes available. |
reason | One of SW_BYTES_AVAIL_REL, SW_BYTES_TOTAL_ABS. |
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:
typedef int32( * DEVICELIST_CLOSE) ( DEVICELIST *dev, DEVICE_FILEDESCRIPTOR descriptor) |
Device type method to close an open file on a device instance.
dev | The current device. |
descriptor | A descriptor returned by a previous open call. |
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.
typedef int32( * DEVICELIST_DELETE) ( DEVICELIST *dev, uint8 *filename) |
Device type method to remove a file from a device instance.
dev | The current device. |
filename | The name of a file to remove. |
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.
typedef int32( * DEVICELIST_DISMOUNT) ( DEVICELIST *dev) |
Device type method to dismount the device instance.
dev | The current device. |
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.
typedef int32( * DEVICELIST_END_LIST) ( DEVICELIST *dev, void *handle) |
Device type method to end iterating file names from a device instance.
dev | The current device. |
handle | A file list iterator pointer returned by the DEVICELIST_START_LIST method. |
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.
typedef int32( * DEVICELIST_GET_PARAM) ( DEVICELIST *dev, DEVICEPARAM *param) |
Device type method to get the next device parameter.
dev | The current device. |
param | A 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. |
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.
The Harlequin RIP SDK provides some utility routines to assist writing parameter methods:
typedef int32( * DEVICELIST_INIT) ( DEVICELIST *dev) |
Device type method to initialise a device instance.
dev | The current device. |
This call is made once for each device instance, and will be the first call for the device instance.
typedef int32( * DEVICELIST_IOCTL) ( DEVICELIST *dev, DEVICE_FILEDESCRIPTOR fileDescriptor, int32 opcode, intptr_t arg) |
Device type method for miscellaneous control options.
dev | The current device. |
fileDescriptor | A descriptor returned by a previous open call. |
opcode | A device-specific value, or one of the generic values: |
%os%
device. arg | A data parameter for the control function. |
0 | for success |
-1 | for failure. |
-2 | if the opcode is not implemented. |
typedef DEVICE_result( * DEVICELIST_LAST_ERROR) ( DEVICELIST *dev) |
Device type method to return last error for a device instance.
dev | The current device. |
%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.
typedef int32( * DEVICELIST_NEXT) ( DEVICELIST *dev, void **handle, uint8 *pattern, FILEENTRY *entry) |
Device type method to get the next file in an iteration.
dev | The current device. |
handle | A file list iterator pointer returned by the device type's DEVICELIST_START_LIST method. |
pattern | The pattern passed to the DEVICELIST_START_LIST method. |
entry | A structure in which to store the next matching filename. |
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:
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:
TRUE
if a zero-terminated string matches a zero-terminated pattern, or FALSE
if the string does not match the pattern.typedef DEVICE_FILEDESCRIPTOR( * DEVICELIST_OPEN) ( DEVICELIST *dev, uint8 *filename, int32 openflags) |
Device type method to open a file on a device instance.
dev | The current device. |
filename | The file name to open. |
openflags | One 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. |
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:
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.
dev | The current device. |
descriptor | A descriptor returned by a previous open call. |
buff | Buffer into which the data read is stored. |
len | The maximum number of bytes to read. |
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.
typedef int32( * DEVICELIST_RENAME) ( DEVICELIST *dev, uint8 *file1, uint8 *file2) |
Device type method to rename a file on a device instance.
dev | The current device. |
file1 | The name of a file to rename. |
file2 | The name to which file1 will be renamed. |
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.
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.
dev | The current device. |
descriptor | A descriptor returned by a previous open call. |
destn | The location to seek to. |
flags | One of SW_SET, SW_INCR, SW_XTND. |
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:
TRUE
if it does, or FALSE
otherwise.After a failure, the DEVICELIST_LAST_ERROR method should return DeviceIOError.
typedef int32( * DEVICELIST_SET_PARAM) ( DEVICELIST *dev, DEVICEPARAM *param) |
Device type method to set a device parameter.
dev | The current device. |
param | A structure describing the parameter to set and its value. |
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:
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.
This method returns a code to indicate the success or failure of setting the parameter:
The following device parameters are valid for all devices, and are not passed to the device. They are handled internally by the Harlequin Core:
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:
typedef void*( * DEVICELIST_START_LIST) ( DEVICELIST *dev, uint8 *pattern) |
Device type method to start iterating file names on a device instance.
dev | The current device. |
pattern | A file pattern to match. |
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:
If this function succeeds, the device type's DEVICELIST_END_LIST method must be called after iterating file names.
typedef int32( * DEVICELIST_START_PARAM) ( DEVICELIST *dev) |
Device type method to start iterating device parameters.
dev | The current device. |
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.
typedef int32( * DEVICELIST_STATUS_DEVICE) ( DEVICELIST *dev, DEVSTAT *devstat) |
Device type method to get the status of the device instance.
dev | The current device. |
devstat | A structure in which to return the status of the device. |
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:
typedef int32( * DEVICELIST_STATUS_FILE) ( DEVICELIST *dev, uint8 *filename, STAT *statbuff) |
Device type method to check status of a file by name.
dev | The current device. |
filename | The file to check status. |
statbuff | Pointer to a structure in which to put the file status. |
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:
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.
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.
dev | The current device. |
descriptor | A descriptor returned by a previous open call. |
buff | Buffer from which the data written is taken. |
len | The maximum number of bytes to write. |
After a failure, the DEVICELIST_LAST_ERROR method should return DeviceIOError.
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.
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.
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.
enum 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 |
|
DeviceNotReady | Status code for output channel not ready. |
DeviceCancelPage | Status code to cancel the page. |
DeviceReOutputPageBuffer |
|
DeviceTimeout | Status code for a timeout. |
DEVICELIST_BYTES reason codes
DEVICELIST_NEXT return codes
DEVICELIST_OPEN 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 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. |
enum 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 */. |
enum DEVICETYPE_flags |
Bit mask flags for DEVICETYPE::devicetypeflags.
enum PDF_FILESPEC_values |
HqnResult device_result_translate | ( | DEVICE_result | result | ) |
Translate a device API-specific error code to a generic HqnResult error code.
[in] | result | One of the DEVICE_RESULT values, or an error value greater than MON_CLASS_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.
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.
TRUE | Skin device error handling was initialised. skindevices_finish_last_error() should be called to terminate error handling when finished. |
FALSE | Skin device error handling was not initialised. The RIP should terminate without calling skindevices_finish_last_error(). |
DEVICE_result skindevices_last_error | ( | DEVICELIST * | dev | ) |
Method call for use in device definitions to get the last error for skin devices.
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.
void skindevices_set_last_error | ( | DEVICE_result | error | ) |
Set the last error for a skin device.
error | The 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.
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.
bytes | The size in bytes of the memory block to allocate. |
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.
void SwFree | ( | void * | pointer | ) |
Free memory dynamically allocated from the core rip's memory space by SwAlloc() or SwRealloc().
pointer | A 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.
For use in DEVICELIST_NEXT to assist pattern matching on file names.
[in] | pattern | A 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. |
plen | The length in bytes of pattern. | |
[in] | string | A zero-terminated string to match against pattern. |
slen | The length in bytes of string. |
TRUE | if string was matched by pattern. |
FALSE | if there was no match. |
For use in DEVICELIST_NEXT to assist pattern matching on file names.
[in] | pattern | A 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] | string | A zero-terminated string to match against pattern. |
TRUE | if string was matched by pattern. |
FALSE | if there was no match. |
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.
dev | The DEVICELIST for this instance of the filter device type. | |
[out] | ret_buff | On 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. |
0 | End of file on the underlying filter (no more bytes). |
-1 | I/O error on the underlying filter. |
Reallocate memory dynamically allocated from the core rip's memory space using SwAlloc(), preserving existing contents.
pointer | A pointer to memory previously returned by SwAlloc() or SwRealloc(), and not subsequently freed. |
bytes | The 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. |
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.
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.
dev | The DEVICELIST for this instance of the filter device type. |
len | The number of bytes at the end of the previous SwReadFilterBytes() call which should not have been consumed. |
0 | if successful |
EOF | if there is a consistency check error. |
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.
dev | The DEVICELIST for this instance of the filter device type. |
offset | An offset from the start position of the filter stream. |
0 | if successful, |
-1 | if a consistency check error or I/O error. |
int32 SwTestAndTickle | ( | void | ) |
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.
dev | The DEVICELIST for this instance of the filter device type. | |
[in] | buff | A buffer containing bytes to write to the underlying filter. |
len | The number of bytes to write to the underlying filter. |