Copyright (c) Hyperion Entertainment and contributors.

Datatypes Library

From AmigaOS Documentation Wiki
Jump to navigation Jump to search

Introduction

The purpose of the DataTypes Library is to provide tools for handling data in an object-oriented way. The object-oriented approach means that your application can work with numerous data file standards without having to worry about the complex details of each one. Instead you only need to understand the simple conventions of the library.

The DataTypes Library is built on Intuition's BOOPSI facility (BOOPSI is an acronym for Basic Object-Oriented Programming System for Intuition). Although not required, it is very helpful to know a little about how BOOPSI works before trying to use the DataTypes Library. Some familiarity with object-oriented theory and practice is also helpful, though not required.

Since the library uses the TagItem structure for passing parameters to functions, you will have to understand how TagItems work before you can call the library functions. For more information on TagItems refer to the Utility Library.

Spelling Conventions

In software development, the term “datatype” or “data type” is often used in the general sense, whereas the AmigaOS DataTypes framework establishes a rather special context. In order to avoid possible confusion, this documentation uses capitalized spelling in reference to components and programming entities that are part of the said framework, such as: the DataTypes Library, a DataType subclass, a DataType object, Picture DataType, etc.

Why Use DataTypes?

Here's a summary of main properties and features:

  • Support for multiple file formats across various types of data (text, sound, image, animation etc.). Load data the easy way without having to write dedicated loader code!
  • Simple and consistent handling of multiple data standards. Once you have learned how to manipulate one type of data with the DataTypes Library, you will find that the other types are handled in much the same way.
  • Extensible. New data types can be added to those already supported.
  • Clipboard support. The DataTypes Library provides a consistent and easy-to-use interface to the Amiga's clipboard device to encourage data sharing between applications.
  • Intuition gadget support. Because the DataTypes Library is implemented with BOOPSI, the data objects it handles can also be treated as gadgets. Gadget operations can be performed on data objects within Intuition's task context, the same as other BOOPSI gadgets.
  • Automatic conversion from one format to another. Future versions of the DataTypes Library will support other types of data objects. Conversion from one format to another will be automatically handled by the library.
  • Validation. For example, you can easily check to see if a file is a valid JPEG (AIFF, AmigaGuide etc.) or not.

Classes, Objects and Methods

The jargon used to describe the DataTypes Library may be a little confusing if you have never worked with object-oriented systems before. For instance, the kinds of data supported by the library are divided into classes and subclasses. The term class is used here in a familiar way; the members of a class simply have a common set of properties. The members of a subclass have all the properties of the parent class (superclass) and additional properties specific to the subclass. (Each subclass can be further broken down into sub-subclasses and so on.)

Class Ungulate Has hooves, can run.
Subclass Cow Has udder, can be milked (also has hooves and can run).
Object Daisy An instance of class Cow; can run and can be milked.

An actual instance of a class or subclass is referred to as an object. The term object is appropriate because in general we want to ignore the details of each individual case and concentrate instead on what we can do with an object based on its class. In the example above the Daisy object can run and can be milked. The operations that can be performed with an object are referred to as methods and the object is said to inherit the methods and other attributes of its parent class (which in turn inherits the methods and attributes of its parent class, if it has one).

The datatypes.library implements datatypesclass from which all other DataType classes inherit from. The following BOOPSI class diagram illustrates how the various DataTypes classes relate to each other.

DataTypes Class Diagram
DataTypes Library Object Classes
Object Classes Autodoc File Showing the Methods Supported Type of Data Object
Picture class picture_dtc.doc IFF graphic image file
Sound class sound_dtc.doc IFF audio sample file
Text class text_dtc.doc ASCII characters
AmigaGuide class amigaguide_dtc.doc Hypertext databases
Animation class animation_dtc.doc Animations containing graphics and sound

The examples programs listed below demonstrate how to perform some basic methods on ILBM and 8SVX class objects.

DataTypes Class Attributes

DataType classes have other attributes in addition to the methods (operations) that they support. For each attribute, there is a corresponding TagItem defined in the DataTypes Library that you can use to examine or set that attribute in a particular object. For example, picture objects have a display mode attribute. The tag that controls this attribute is named PDTA_ModeID and is described in the Autodoc file picture_dtc.doc. See the Autodoc files for each class (as shown in Table 1) for a complete list of all class attributes.

The class attribute descriptions in the include files also have a set of codes that indicate the applicability of the attribute. The codes are as follows:

I - Initialize You can initialize the attribute when the object is created
S - Set You can set the attribute to a new value after the object is created
G - Get You can get the value of the attribute after the object is created
N - Notify Changing the attribute triggers the object to send notification
U - Update Attribute can be set using the object's OM_UPDATE method

These codes may seem a little mysterious until you have actually tried using the DataTypes Library. The N and U codes in particular are for special applications that want to implement their own object classes, an advanced topic beyond the scope of this article.

Basic Functions of the DataTypes Library

If all these new concepts seem a little daunting, rest assured; the DataTypes Library uses conventional C language function calls to get the job done. The calls you will be using most often are listed below. Notice that for each of these basic functions of DataTypes Library there is an equivalent BOOPSI call in the Intuition Library.

datatypes.library intuition.library Purpose
NewDTObject() NewObject() Create a DataType object in memory from a file or clip
DisposeDTObject() DisposeObject() Free an object created earlier with NewDTObject() (or NewObject() )
GetDTAttrs() GetAttr() Get attributes of a DataType object
SetDTAttrs() SetAttrs() Set attributes for a DataType object
DoDTMethod() IDoMethod() Perform the given method (operation) with a DataType object

There are also additional functions used to access DataType objects.

Function Name Purpose
AddDTObject() Add a DataType object to a window.
RefreshDTObjectA() Refresh the rendering of a DataType object.
RemoveDTObject() Remove a DataType object from a window.
GetDTMethods() Get a list of the methods that a DataTypes object supports. Write, Copy, and Select are examples of methods that an object may support.
GetDTTriggerMethods() Get a list of the trigger methods that a DataType object supports. An action like Play, Pause, and Resume are examples of trigger methods that an object may support.
PrintDTObject() Asynchronously print a DataType object.
GetDTString() Get the localized text string for a DataTypes text id. Useful for obtaining localized error messages.

In a typical application the sequence of calls might be performed like this:

  1. Use NewDTObject() to create an object in memory from given data.
  2. Get (or perhaps set) attributes of the object using GetDTAttr() (or SetDTAttrs() ).
  3. Perform methods (operations) with the object using DoDTMethod().
  4. Free the object and any memory or other resources it was using with the DisposeDTObject() call.

Basic Structures of the DataTypes Library

There are a lot of structures used with DataTypes Library function calls; too many to summarize in this article. However, here's a listing of the relevant include files that contain the structure definitions of interest to class users.

<datatypes/datatypes.h> Group IDs, error numbers plus library overhead
<datatypes/datatypesclass.h> Defines DataType methods and associated structures
<datatypes/picture.h> Structures specific to the picture class
<datatypes/sound.h> Structures specific to the sound class
<datatypes/text.h> Structures specific to the text class
<libraries/amigaguide.h> Structures and methods for AmigaGuide databases
<intuition/classusr.h> Defines general BOOPSI object methods
<intuition/gadgetclass.h> Defines gadget methods and associated structures

The two most important definitions in these include files appear in <intuition/classusr.h>. The objects used with DataTypes Library functions (and the BOOPSI functions in Intuition) are defined as follows:

typedef ULONG   Object;     /* abstract handle */

Since we want to treat objects as black boxes and don't really care how they are implemented, this definition is very appropriate. When a method is performed with an object, the parameter used to identify the method is a Msg structure defined as follows:

typedef struct {
    ULONG MethodID;
    /* method-specific data goes here */
} *Msg;

Some methods require more information than just the method identifier. Such methods have a custom structure defined in the include files. All method structures, however, begin with a field that contains the method ID.

Creating a DataType Object

The DataTypes function NewDTObjectA() must be used to create a new DataType object.

Object *dto = IDataTypes->NewDTObjectA (APTR name, struct TagItem *attrs);

The pointer that NewDTObjectA() returns is a pointer to a BOOPSI object. Like other BOOPSI objects, DataType objects are "black boxes" and are not to be peeked and poked without using the provided interface.

To create a DataType object, NewDTObjectA() needs to know the where to obtain the data used to create the object. By default the name is treated as file name.

The attrs tag list is a list of tag/value pairs, each of which contains an initial value for an attribute. There are a number of attributes defined in <datatypes/datatypesclass.h> that can be used at creation time.

DTA_SourceType
Specify the type of the source data. The default is DTST_FILE.
DTST_RAM Source data is in RAM.
DTST_FILE Source data is a file. Name is the name of the file.
DTST_CLIPBOARD Source data is in the clipboard. Name is the unit number. For example, (APTR)0, for clipboard unit zero.
DTST_HOTLINK Reserved for future use.
DTA_Handle
Can be used instead of the name field. If the source type is DTST_FILE then handle must be a valid BPTR file handle. If the source type is DTST_CLIPBOARD then handle must be a valid IFFHandle.
DTA_DataType
Can be used to specify the class for handling the data. Data must be a pointer to a valid DataType. This should only be used when attempting to create a new object that doesn't have source data, or could be handled by multiple classes (for example, could be used to force an object to be handled by the AmigaGuide class).
DTA_GroupID
If this tag is present, then the data must be of the specified type, or the object creation will fail with ERROR_OBJECT_WRONG_TYPE. This can be used by a Sound editor to ensure that only sounds can be loaded, for example.

There are additional attributes that can specified at creation time, but are dependant on the data type of the object being created. See the header files <datatypes/#?class.h> for more attributes.

The following attributes, which are defined in <intuition/gadgetclass.h>, are also valid.

Tag Description
GA_Left Specify the left edge of the gadget.
GA_RelRight Specify the left edge of the gadget being relative to the right edge of the containing window.
GA_Top Specify the top edge of the gadget.
GA_RelBottom Specify the top edge of the gadget being relative to the bottom edge of the containing window.
GA_Width Specify the width of the gadget.
GA_RelWidth Specify the width of the gadget being relative to the width of the containing window.
GA_Height Specify the heigh of the gadget.
GA_RelHeight Specify the heigh of the gadget being relative to the height of the containing window.
GA_ID Specify a ID associated with the gadget.
GA_UserData Attach application data to the gadget.
GA_Immediate Indicate that the application should be notified of gadget down events for this gadget.
GA_RelVerify Indicate that the application should be notified of gadget up events for this gadget.
GA_Previous For adding the gadget to a list of gadgets.
GA_DrawInfo A pointer to a struct DrawInfo.

In order for the application to receive information from the DataType object, it must set up a target for the notification attributes that the object sends out.

ICA_TARGET
Specify a target for the notification attributes that the DataType object sends out.
ICA_MAP
Specify an attribute mapping for the notification attributes that the DataType object sends out.

The usual method to obtain notification is to set up an ICA_TARGET of ICTARGET_IDCMP so that the application will receive the attributes via the IDCMP_IDCMPUPDATE Intuition message class. But it is also possible to set up another BOOPSI object as the receiver.

If NewDTObjectA() is successful, it returns a pointer to a DataType object. Otherwise it returns NULL and the reason for failure can be obtained using IoErr(). See the Autodocs for datatypes.library for more information.

Obtaining Environment Information for a DataType

In order to embed a DataType object in a window, it is neccessary to ask the object what its minimum environment is. For example, since the remap code doesn't handle remapping HAM pictures, they must be shown on a HAM screen, and therefore can't be added to a window that is on a non-HAM screen.

ULONG modeid = INVALID_ID;
LONG nomwidth, nomheight;
BOOL useScreen = FALSE;
struct dtFrameBox dtf;
struct FrameInfo fri;
 
/* Get the attributes that we are interested in */
IDataTypes->GetDTAttrs(dto,
    /* Get the mode ID */
    PDTA_ModeID,    &modeid,
 
    /* Get the desired size */
    DTA_NominalHoriz, &nomwidth,
    DTA_NominalVert,  &nomheight,
 
    TAG_END);
 
/* Clear the structures */
IUtility->ClearMem(&dtf, sizeof (struct dtFrameBox));
IUtility->ClearMem(&fri, sizeof (struct FrameInfo));
 
/* Fill in the message */
dtf.MethodID          = DTM_FRAMEBOX;
dtf.dtf_FrameInfo     = &fri;
dtf.dtf_ContentsInfo  = &fri;
dtf.dtf_SizeFrameInfo = sizeof (struct FrameInfo);
 
/* Perform the frame method */
if (IDataTypes->DoDTMethodA (dto, NULL, NULL, (Msg) &dtf))
{
  /* Check to see if the object requires a HAM screen */
  if (fri.fri_PropertyFlags & DIPF_IS_HAM)
  {
      IDOS->Printf ("HAM\n");
      useScreen = TRUE;
  }
  /* Check to see if the object requires an ExtraHalfBrite screen */
  else if (fri.fri_PropertyFlags & DIPF_IS_EXTRAHALFBRITE)
  {
      IDOS->Printf ("ExtraHalfBrite\n");
      useScreen = TRUE;
  }
  /* A safety check to see if a screen is required */
  else if ((fri.fri_PropertyFlags == 0) && (modeid & 0x800) && (modeid != INVALID_ID))
  {
      IDOS->Printf ("ModeID=0x%08lx\n", modeid);
      useScreen = TRUE;
  }
}
else
{
  /* No special environment required, can be attached to any screen mode */
}

Adding a DataType Object to a Window

A DataType object must be added to a window using the AddDTObject() function of DataTypes.

LONG AddDTObject (struct Window *w, struct Requester *r, Object *dto, LONG pos)

This function will add a DataTypes object to the existing gadget list for the specified window. The recommended value for pos is -1 which will cause the DataType object to be added to the end of the list.

DataType objects should not be added using the WA_Gadgets attribute to OpenWindowTagList() or by using the AddGList() function. There is special information that DataTypes requires that will not obtained if any method other than AddDTObject() is used.

When the DataType object is added to the window, the layout method for the object will be invoked. It is possible that the layout will take a while to perform, in that case the object will spawn a process to handle the layout asynchronously. In order to refresh the object's visual information, it is necessary to obtain IDCMP_IDCMPUPDATE messages from the object and refresh the object when a DTA_Sync attribute is received.

The following code fragment illustrates adding a DataType object to a window.

Object *dto;
 
struct IntuiMessage *imsg;
struct Window *win;
ULONG sigr;
 
struct TagItem *tstate, *tags;
ULONG tidata;
ULONG errnum;
 
BOOL going = TRUE;
 
/* Set the pertinent attributes of the DataType object */
IDataTypes->SetDTAttrs (dto, NULL, NULL,
 
    /* Set the dimensions of the object */
    GA_Left,    win->BorderLeft,
    GA_Top,     win->BorderTop,
    GA_Width,   win->Width - win->BorderLeft - win->BorderRight,
    GA_Height,  win->Height - win->BorderTop - win->BorderBottom,
 
    /* Make sure we receive IDCMP_IDCMPUPDATE messages from
     * the object */
    ICA_TARGET, ICTARGET_IDCMP,
    TAG_END);
 
/* Add the object to the window */
IDataTypes->AddDTObject (win, NULL, dto, -1);
 
/* Refresh the DataType object */
IDataTypes->RefreshDTObjects (dto, win, NULL, NULL);
 
/* Keep going until we're told to stop */
while (going)
{
    /* Wait for an event */
    sigr = IExec->Wait ((1L << win->UserPort->mp_SigBit) | SIGBREAKF_CTRL_C);
 
    /* Did we get a break signal */
    if (sigr & SIGBREAKF_CTRL_C)
        going = FALSE;
 
    /* Pull Intuition messages */
    while (imsg = (struct IntuiMessage *) IExec->GetMsg (win->UserPort))
    {
        /* Handle each message */
        switch (imsg->Class)
        {
            case IDCMP_IDCMPUPDATE:
                /* Get a pointer to the attribute list */
                tstate = tags = (struct TagItem *) imsg->IAddress;
 
                /* Step through the attribute list */
                while (tag = IUtility->NextTagItem (&tstate))
                {
                    tidata = tag->ti_Data;
                    switch (tag->ti_Tag)
                    {
                        /* Change in busy state */
                        case DTA_Busy:
                            if (tidata)
                                IIntuition->SetWindowPointer (win, WA_BusyPointer, TRUE, TAG_END);
                            else
                                IIntuition->SetWindowPointer (win, WA_Pointer, NULL, TAG_END);
                            break;
 
                        /* Error message */
                        case DTA_ErrorLevel:
                            if (tidata)
                            {
                                errnum = IUtility->GetTagData (DTA_ErrorNumber, NULL, tags);
                                IDOS->PrintErrorMsg (errnum, (STRPTR) options[OPT_NAME]);
                            }
                            break;
 
                        /* Time to refresh */
                        case DTA_Sync:
                            /* Refresh the DataType object */
                            IDataTypes->RefreshDTObjects (dto, win, NULL, NULL);
                            break;
                    }
                }
                break;
        }
 
        /* Done with the message, so reply to it */
        IExec->ReplyMsg ((struct Message *) imsg);
    }
}

Removing a DataType Object from a Window

A DataType object must be removed from the window using the RemoveDTObject() function.

LONG RemoveDTObject (struct Window *w, Object *dto)

This function removes the DataType object from the window's gadget list.

This is the only way that a DataType object should be removed from the window list. Using RemoveGList() is not supported, nor is removing the object manually.

Setting an Existing DataType Object's Attributes

An objects attributes are not necessarily static. An application can ask an object to set certain attributes using the SetDTAttrs() function.

ULONG SetDTAttrsA (Object *dto, struct Window *w, struct Requester *r, struct TagItem *attrs)

The return value is DataType object specific, but generally a non-zero value means that the object needs to be visually refreshed.

The following fragment illustrates how to set the current top values for a DataType object, using the VarArgs version of SetDTAttrsA().

IDataTypes->SetDTAttrs(dto, window, NULL,
    DTA_TopVert,  0,
    DTA_TopHoriz, 0,
    TAG_END);

This will cause the DataType object to update its vertical and horizontal top values. If the object has been added to a window, then the display will be updated accordingly.

Note that it is not OK to call SetGadgetAttrs() or SetAttrs() on a DataType object.

Getting a DataType Object's Attributes

The DataTypes function GetDTAttrsA() is used to obtain the values for a list of attributes from a DataType object.

ULONG GetDTAttrsA (Object *dto, struct TagItem *attrs)

Where dto is a pointer to a DataType object returned by NewDTObjectA().

And attrs is a TAG_END terminated array of attributes. Where the data element of each pair contains the address of the storage variable for that attribute.

This function will return a number that indicates that number of attributes that it was able to obtain. For example if four attributes asked for and GetDTAttrs returns a four, then all the attributes were obtained.

The following code fragment illustrates how to get the current top values for a DataTypes object using the VarArgs form of GetDTAttrsA().

LONG topv, toph;
 
if (IDataTypes->GetDTAttrs (dto, DTA_TopVert, &topv, DTA_TopHoriz, &toph, TAG_END) == 2)
{
    IDOS->Printf ("Top: vertical=%ld, horizontal=%ld\n", topv, toph);
}
else
{
    IDOS->Printf ("couldn't obtain the top values\n");
}

A Simple DataTypes Example

The example program listed here should clarify some of the concepts discussed so far. Suppose you have a communications program and want to add the capability of playing back a user-specified 8SVX sample file for the bell sound (Ctrl-G). The program below shows how to play a sound with the DataTypes Library.

In this program, objects are of class 8SVX (a subclass of the Sound DataType). The method performed with the object is named DTM_TRIGGER (described in the Autodoc file sound_dtc.doc). The DTM_TRIGGER method (with type set to STM_PLAY) causes a sampled sound to be played on the Amiga's audio hardware. Since the DTM_TRIGGER method requires other information in addition to the method ID, a dtTrigger structure is used. This structure is defined in <datatypes/datatypesclass.h>.

Note that if the Sound DataType is enhanced to support other types of sound files in a future version of AmigaOS, the code given here will automatically support the new type. This example expects the file name and path to a sound file.

/* Run from CLI only. */
 
#include <exec/types.h>
#include <datatypes/datatypesclass.h>  /* This includes other files we need */
 
#include <proto/exec.h>          /* Prototypes for system functions */
#include <proto/intuition.h>
#include <proto/datatypes.h>
#include <proto/dos.h
 
struct IntuitionIFace *IIntuition = NULL;
struct DataTypesIFace *IDataTypes = NULL;
 
int main(int argc, char **argv)
{
  APTR dtobject = NULL       /* Pointer to a DataTypes object */
  struct dtTrigger mydtt;    /* A trigger structure for the DTM_TRIGGER method */
 
  if(argc <= 1 ) /* CLI only, at least one argument please. */
  {
    IDOS->Printf("Give a file name too.\n");
    return RETURN_FAIL;
  }
 
  struct Library *IntuitionBase = IExec->OpenLibrary("intuition.library", 50);
  IIntuition = (struct IntuitionIFace*)IExec->GetInterface(IntuitionBase, "main", 1, NULL);
 
  struct Library *DataTypesBase = IExec->OpenLibrary("datatypes.library", 50);
  IDataTypes = (struct DataTypesIFace*)IExec->GetInterface(DataTypesBase, "main", 1, NULL);
 
  if (IIntuition != NULL && IDataTypes != NULL)
  {
    /* Attempt to make an 8svx sound object from the file name the user */
    /* specified in the command line.  For a list of possible error     */
    /* returns, see the Autodocs for NewDTObjectA().  The group ID tag  */
    /* will allow only Sound DataType files to be accepted for the call.*/
    if (dtobject = IDataTypes->NewDTObject(argv[1], DTA_GroupID, GID_SOUND,
                                                    TAG_END) )
    {
      mydtt.MethodID     = DTM_TRIGGER; /* Fill in the dtTrigger struct */
      mydtt.dtt_GInfo    = NULL;
      mydtt.dtt_Function = STM_PLAY;
      mydtt.dtt_Data     = NULL;
 
      /* The return value of the DTM_TRIGGER method used with the 8svx */
      /* Sound DataType is undefined in V39.  This is likely to change */
      /* in future versions of the Amiga operating system.             */
      uint32 dores = IDataTypes->DoDTMethodA(dtobject, NULL, NULL, &mydtt);
 
      // Let the 8svx sound finish playing. Another way is to use
      // SDTA_SignalTask and SDTA_SignalBit to find out when it is
      // finished playing.
      IExec->Wait(SIGBREAKF_CTRL_C);
 
      IDataTypes->DisposeDTObject(dtobject);
    }
    else IDOS->Printf("Couldn't create new object or not a sound data file\n");
  }
  else IDOS->Printf("Can't open interfaces\n");
 
  IExec->DropInterface((struct Interface*)IDataTypes);
  IExec->CloseLibrary(DataTypesBase);
 
  IExec->DropInterface((struct Interface*)IIntuition);
  IExec->CloseLibrary(IntuitionBase);
 
  return 0;
}

In addition to playing back a sampled sound, the DataTypes Library allows sound objects to become gadgets (the library includes default imagery for a sound gadget). Since all DataTypes are implemented as a subclass of the BOOPSI gadgetclass, they all support the methods of gadget objects as described in BOOPSI.

Embedding DataTypes

Since DataTypes are a subclass of the Intuition gadgetclass, DataType objects can be attached to an Intuition window in a similiar way that gadgets can be added to a window. DataTypes use a parallel set of functions because it requires additional information that the Intuition functions weren't able to provide.

Currently the handling of the data is limited to reading, writing, printing, viewing (audio or visual), and clipboard access. Utilities like MultiView or MultiViewer are examples of applications that can embed DataType objects.

Determining Data Type

One of the main features of the DataTypes system is its ability to determine the type of a block of data. This data block can reside in a file or the clipboard.

The following functions are used to determine the DataType of a data block:

ObtainDataTypeA() Obtain the DataType descriptor for a data block.
ReleaseDataType() Release the DataType descriptor for a data block.

The data type detection functions use the DataType structure.

struct DataType
{
    struct Node            dtn_Node1;
    struct Node            dtn_Node2;
    struct DataTypeHeader *dtn_Header;
    struct List            dtn_ToolList;
    STRPTR                 dtn_FunctionName;
    struct TagItem        *dtn_AttrList;
    ULONG                  dtn_Length;
};

The DataType structure is read-only. The only pertinent field is the dtn_Header field, which points to a DataTypeHeader structure.

struct DataTypeHeader
{
    STRPTR   dth_Name;
    STRPTR   dth_BaseName;
    STRPTR   dth_Pattern;
    WORD    *dth_Mask;
    ULONG    dth_GroupID;
    ULONG    dth_ID;
    WORD     dth_MaskLen;
    WORD     dth_Pad;
    UWORD    dth_Flags;
    WORD     dth_Priority;
};

The DataTypeHeader structure fields are as follows:

dth_Name
Descriptive name of the data type. For example, the description for an ILBM data type could possibly be "Amiga BitMap Picture".
dth_BaseName
This is the base name for the data type and is used to obtain the class that handles this data type.
dth_GroupID
This identifies the general type of data that the object contains. Following are the possible values:
GID_SYSTEM Fonts, Executables, Libraries, Devices, etc...
GID_TEXT Formatted or unformatted text.
GID_DOCUMENT Formatted text with embedded DataTypes (such as pictures).
GID_SOUND Audio samples.
GID_INSTRUMENT Audio samples used for playing music.
GID_MUSIC Musical scores.
GID_PICTURE Graphic picture or brush.
GID_ANIMATION Moving picture or cartoon.
GID_MOVIE Moving picture or cartoon with sound.
dth_ID
This is an individual indentifier for the DataType. For IFF files it is the same as the FORM type, for example ILBM for an Amiga BitMap picture. For non-IFF files, it is the first four characters of dth_Name.
dth_Flags
The flags field contains, among other information, the coarse type of data. The type can be obtained by ANDing DTF_TYPE_MASK with this field.
DTF_IFF Interchange File Format
DTF_BINARY Non-readable characters
DTF_ASCII Readable characters
DTF_MISC Disks and drawers
dth_Pattern
dth_Mask
dth_MaskLen
dth_Priority
These fields are used by the detection code in datatypes.library for determining the data type. See the "Defining a DataType Descriptor" section for more information.

Following is a code fragment that shows how to determine the data type of a file. This fragment uses functions from the DataTypes Library, DOS Library, and IFFParse Library.

    STRPTR name = "somefilename";
    BPTR lock;
 
    struct DataTypeHeader *dth;
    struct DataType *dtn;
    UBYTE idesc[5];
    STRPTR tdesc;
    STRPTR gdesc;
    UWORD ttype;
 
    /* Obtain a lock on the file that we want information on */
    if (lock = IDOS->Lock (name, ACCESS_READ))
    {
	/* Get a pointer to the appropriate DataType structure */
	if (dtn = IDataTypes->ObtainDataTypeA (DTST_FILE, (APTR)lock, NULL))
	{
	    /* Get a pointer to the DataTypeHeader structure */
	    dth = dtn->dtn_Header;
 
	    /* Get the coarse type */
	    ttype = dth->dth_Flags & DTF_TYPE_MASK;
 
	    /* Get a pointer to the text strings */
	    tdesc = IDataTypes->GetDTString (ttype + DTMSG_TYPE_OFFSET);
	    gdesc = IDataTypes->GetDTString (dth->dth_GroupID);
 
	    /* Convert the ID to a string. */
	    IIFFParse->IDtoStr (dth->dth_ID, idesc);
 
	    /* Display the information */
	    IDOS->Printf ("   Description: %s\n", dth->dth_Name);
	    IDOS->Printf ("     Base Name: %s\n", dth->dth_BaseName);
	    IDOS->Printf ("          Type: %d - %s\n", ttype, tdesc);
	    IDOS->Printf ("         Group: %s\n", gdesc);
	    IDOS->Printf ("            ID: %s\n", idesc);
 
	    /* Release the DataType structure now that we are done with it */
	    IDataTypes->ReleaseDataType (dtn);
	}
 
	/* Release the DOS lock on the file */
	IDOS->UnLock (lock);
    }

A Picture Class Example

Here is a second, more complex example showing how to use all the DataTypes Library functions described so far. In this example the objects used are of class ILBM, a subclass of the Picture DataType.

Two methods will be performed with the object, DTM_PROCLAYOUT and DTM_FRAMEBOX. Both these methods have associated structures (gpLayout and dtFrameBox respectively). DTM_PROCLAYOUT makes the object available within the context of your application task (as opposed to Intuition's). DTM_FRAMEBOX queries the display environment required by the picture.

Other attributes of the picture are obtained with a call to GetDTAttrs() and then a matching Intuition screen is created and the ILBM object is displayed. This example expects the file and path name of a picture file.

/* Run from CLI only.
 */
 
#include <exec/types.h>
#include <datatypes/datatypes.h>
#include <datatypes/pictureclass.h>
 
#include <proto/exec.h>
#include <proto/dos.h>
#include <proto/intuition.h>
#include <proto/datatypes.h>
#include <proto/graphics.h>
 
struct IntuitionIFace *IIntuition = NULL;
struct GraphicsIFace *IGraphics = NULL;
struct DataTypesIFace *IDataTypes = NULL;
 
int main(int argc, char **argv)
{
  APTR dtobject=NULL;                   /* Pointer to a DataTypes object       */
  uint32 res;                           /* Variable for function return values */
  struct dtFrameBox mydtFrameBox;       /* Use this with DTM_FRAMEBOX method   */
  struct FrameInfo myFrameInfo;         /* For info returned from DTM_FRAMEBOX */
  struct gpLayout mygpLayout;           /* Use this with DTM_PROCLAYOUT method */
 
  uint32 modeID = INVALID_ID;           /* Variables for storing the display */
  struct Screen *myScreen=NULL;         /* environment information obtained  */
  struct BitMap *bm = NULL;             /* the DataType object.              */
  uint32 *cregs = NULL;
  uint32 i,r,g,b,numcolors;
 
  struct Library *IntuitionBase = IExec->OpenLibrary("intuition.library", 50);
  struct Library *GfxBase = IExec->OpenLibrary("graphics.library", 50);
  struct Library *DataTypesBase = IExec->OpenLibrary("datatypes.library", 50);
 
  IIntuition = (struct IntuitionIFace*)IExec->GetInterface(IntuitionBase, "main", 1, NULL);
  IGraphics = (struct GraphicsIFace*)IExec->GetInterface(GfxBase, "main", 1, NULL);
  IDataTypes = (struct DataTypesIFace*)IExec->GetInterface(DataTypesBase, "main", 1, NULL);
 
  if (IIntuition != NULL)
  {
    if (IGraphics != NULL)
    {
      if (IDataTypes != NULL)
      {
        if(argc > 1 ) /* CLI only, at least one argument please.  */
        {
            /* Attempt to create a picture object in memory from the file    */
            /* name given by the user in the command line.  If we wanted to  */
            /* show the picture in a screen set up ahead of time, we could   */
            /* set PDTA_Remap to TRUE and provide a pointer to the screen    */
            /* with the PDTA_Screen tag (datatypes.library handles the rest).*/
            /* However in this case we want to first find out the attributes */
            /* of the picture object and set up a matching screen and do the */
            /* remapping later.  Therefore PDTA_Remap is set to false.       */
            /* The group ID tag ensures that we get only a picture file type.*/
            if (dtobject = IDataTypes->NewDTObject(argv[1], PDTA_Remap,  FALSE,
                                                DTA_GroupID, GID_PICTURE,
                                                TAG_END) )
            {
                /* Here we want to find the display environment required by  */
                /* this picture.  To do that, perform the DTM_FRAMEBOX method */
                /* on the object.  The DataTypes Library fills in the struct */
                /* FrameBox you give it with the info on the display needed.  */
                mydtFrameBox.MethodID         = DTM_FRAMEBOX;
                mydtFrameBox.dtf_GInfo        = NULL;
                mydtFrameBox.dtf_ContentsInfo = NULL;
                mydtFrameBox.dtf_FrameInfo    = &myFrameInfo;
                mydtFrameBox.dtf_SizeFrameInfo= sizeof (struct FrameInfo);
                mydtFrameBox.dtf_FrameFlags   = 0L;
 
                /* The return value from DTM_FRAMEBOX is currently undefined */
                res = IIntuition->IDoMethodA(dtobject, &mydtFrameBox);
 
                /* OK, now do the layout (remap) of the object on our process */
                mygpLayout.MethodID   = DTM_PROCLAYOUT;
                mygpLayout.gpl_GInfo  = NULL;
                mygpLayout.gpl_Initial= 1L;
 
                /* The return value of DTM_PROCLAYOUT is non-zero for success */
                if( res = IIntuition->IDoMethodA(dtobject, &mygpLayout) )
                {
                   /* Get the attributes of this picture object.  You could  */
                   /* use a series of GetAttr() function calls here instead.  */
                   res = IDataTypes->GetDTAttrs(dtobject, PDTA_ModeID, &modeID,
                                              PDTA_CRegs, &cregs,
                                              PDTA_BitMap, &bm,
                                              TAG_END);
 
                   /* Did we get all threee attributes? */
                   if( (modeID!=INVALID_ID) && (cregs) && (bm) )
                   {
                       /* Open a screen that matches the picture object */
                       if( myScreen = IIntuition->OpenScreenTags( NULL,
                           SA_Width,     myFrameInfo.fri_Dimensions.Width,
                           SA_Height,    myFrameInfo.fri_Dimensions.Height,
                           SA_Depth,     myFrameInfo.fri_Dimensions.Depth,
                           SA_DisplayID, modeID,
                           SA_BitMap,    bm,
                           TAG_END) )
                       {
                           /* Now fill in the color registers for this screen */
                           numcolors = 2<<(myFrameInfo.fri_Dimensions.Depth-1);
                           for( i=0; i < numcolors; i++ )
                           {
                              r = cregs[i * 3 + 0];
                              g = cregs[i * 3 + 1];
                              b = cregs[i * 3 + 2];
                              IGraphics->SetRGB32(&myScreen->ViewPort, i, r, g, b);
                           }
 
                           IDOS->Printf("Ctrl-C in this window to quit\n");
                           /* Wait for the user to have a look...  */
                           IExec->Wait(SIGBREAKF_CTRL_C);
 
                           IIntuition->CloseScreen(myScreen);
                       }
                       else IDOS->Printf("Couldn't open required screen\n");
                   }
                   else IDOS->Printf("Couldn't get picture attributes\n");
 
                   IDataTypes->DisposeDTObject(dtobject);
                }
                else IDOS->Printf("Couldn't perform PROC_LAYOUT\n");
            }
            else IDOS->Printf("Couldn't create new object or not a picture file\n");
        }
        else IDOS->Printf("Give a file name too.\n");
      }
      else IDOS->Printf("Can't open DataTypes Library\n");
    }
    else IDOS->Printf("Can't open Graphics Library\n");
  }
  else IDOS->Printf("Can't open Intuition Library\n");
 
  IExec->DropInterface((struct Interface*)IDataTypes);
  IExec->DropInterface((struct Interface*)IGraphics);
  IExec->DropInterface((struct Interface*)IIntuition);
 
  IExec->CloseLibrary(DataTypesBase);
  IExec->CloseLibrary(GfxBase);
  IExec->CloseLibrary(IntuitionBase);
 
  return 0;
}

As with 8SVX objects, the DataTypes Library allows ILBM objects to be treated as gadgets. Remember that all DataTypes are a subclass of the BOOPSI gadgetclass and therefore support the gadget methods described in BOOPSI Gadgets.