< Home < Developers < Development Support < Documentation

## 3 Personal Data Interchange

Table of Contents | < Previous | Next > | Index

| Title - Palm OS® Programmer's Companion vol. II: Communications 3 Personal Data Interchange About Personal Data Interchange About vObjects Overview of vObject Structure About the PDI Library PDI Property and Parameter Types The PDI Library Properties Dictionary PDI Readers PDI Writers Format Compatibility International Considerations Features Not Yet Supported Using the PDI Library Accessing the PDI Library Unloading the PDI Library Creating a PDI Reader Reading Properties Reading Property Values Creating a PDI Writer Writing Properties Writing Property Values Specifying PDI Versions Using UDA for Different Media About the UDA Library Using a PDI Reader - An Example Using a PDI Writer - An Example Summary of Personal Data Interchange Summary of Unified Data Access Manager |  |  |  | The Palm OS® provides the PDI library API for exchanging Personal Data Interchange (PDI) information with other devices and media. This chapter contains the following sections that describe how to use the Palm OS PDI library: About Personal Data Interchange briefly introduces the PDI standard and provides links to sources of more complete information. About the PDI Library describes how the Palm OS PDI library implements PDI reader and writer objects for exchanging information. Using the PDI Library describes how to use the functions in the PDI library. Using UDA for Different Media describes how you can use the Unified Data Access (UDA) Manager to access data from different media in your PDI reader or writer. Using a PDI Reader - An Example provides a detailed walk-through of a code segment that creates a PDI reader and then uses it to parse vCard information. Using a PDI Writer - An Example provides a detailed walk-through of a code segment that creates a PDI writer and then uses it to generate vCal information. For detailed information about the PDI library data types, constants, and functions, see Chapter 78, "Personal Data Interchange Library" in the Palm OS SDK Reference. The PDI reader and writer objects make use of the United Data Access (UDA) Manager to manage input and output data streams. "Using UDA for Different Media" provides an overview of using the UDA Manager. The reference information for UDA functions is in Chapter 79, "Unified Data Access Manager," in Palm OS Programmer's API Reference. ## About Personal Data Interchange Personal data interchange involves the exchange of information using a communications medium. The Palm OS PDI Library facilitates the exchange of information using standard vObjects, including data formatted according to vCard and vCal standards. The vObject standards are maintained by a group known as the versit consortium, which consists of individuals from a number of companies and institutions. The best information about the PDI standards can be found at the consortium's web site:
    http://www.imc.org/pdi/
These standards are finding increased use in a number of computers and hand-held devices that wish to exchange personal data such as business card and calendar information. The PDI Library provides a PdiReaderType object for reading vObjects from an input stream, and a PdiWriterType object for writing vObjects to an output stream. The input streams and output streams can be connected to various data sources. ## About vObjects This section provides a brief overview of vObject standards. Two common vObject types are vCards and vCals: vCards are used to exchange virtual business card information electronically. Each vCard can include a large variety of personal and business information about an individual, including name, address, and telecommunications numbers. vCals are used to exchange virtual calendaring and scheduling information electronically. Each vCal can include: - vEvent objects, each of which represents a scheduled amount of time on a calendar - vTodo objects, each of which defines an action item or assignment ## Overview of vObject Structure This section provides a brief overview of vObject standards, including the vCard and vCal standards. Each vObject standard provides the same, basic organizational structure: Each vObject is a collection of one or more property definitions. Each property definition contains a name, a value, and an optional collection of property parameter definitions. Each property parameter definition contains a name and a value. Each parameter value qualifies the property definition with additional information. A property value can be structured to contain multiple values. The values are typically separated with commas or semicolons. The vObject standards also allow developers to add custom extensions. All vObject readers that conform to the standard, including the PdiReaderType object, can read these extensions, though not all readers will act upon the information contained in them. Each property has the following syntax:
    PropertyName [';' Parameters] ':' PropertyValue
Note that property and parameter names are case insensitive. Listing 3.1 shows a typical vCard definition. Listing 3.1 Example of a vCard definition
    BEGIN:VCARD
    VERSION:2.1
    N:Smith, John;M.;Mr.; Esq.
    TEL;WORK;VOICE; MSG:+1 (408) 555-1234
    TEL;CELL:+1 (408) 555-4321
    TEL;WORK;FAX:+1 (408) 555-9876
    ADR;WORK;PARCEL;POSTAL;DOM:Suite 101;1 Central  St.;Any Town;NC;28654
    END:VCARD
Each line in Listing 3.1 is a property definition, with the exception of the next to last line, which is a continuation of the ADR property definition, and begins with white space. Each property definition is delimited by a CR/LF sequence. The BEGIN, VERSION, and END lines are examples of simple property definitions. The N (Name) property has a structured value. The components of the name are separated by semicolons. Each TEL (Telephone) property has parameters that qualify the kind of telephone number that is being specified. The ADR (Address) property has parameters and a structured value. NOTE: The vObject specifications also allow long lines of text to be folded. This means that wherever you can have white space in a property definition, you can insert a CR/LF followed by white space, as shown in the next to last line in Listing 3.1 When the vObject reader finds a CR/LF followed by white space, it unfolds the text back into one long line. #### Grouping vObjects You can specify multiple vObjects in a single vObject data stream. You can also specify a vObject as the value of a property; for example, you can include a vCard as the value of the ADR property of another vCard. #### Grouping Properties You can specify a name for a group of related properties within a vObject. The name is a single character that you use as a prefix to each property in the group. One use of this facility is to group a comment that describes a property with the property to keep the two together. For example, the following creates a group named G that includes a vCard home telephone property with a comment property:
    G.TEL;HOME:+1 (831) 555-1234
    G.Note: This is my home office number.
#### Encodings The default encoding for vObject properties is 7-bit. You can override this encoding for individual property values by using the ENCODING parameter. You can specify various encoding values, including BASE64, QUOTED-PRINTABLE, and 8-BIT. #### Character Sets The default character set for vObject properties is ASCII. You can override the character set for individual property values by using the CHARSET parameter. You can specify any character set that has been registered with the Internet Assigned Numbers Authority (IANA). For example, to specify the Latin/Hebrew encoding, you would use the value ISO-8859-8. #### Finding More Information For a complete description of the vObject specifications, visit the versit consortium's web site:
    http://www.imc.org/pdi/
## About the PDI Library The Palm OS PDI library is a shared library that provides objects and functions for: Reading vCard objects from an input data stream. The section Creating a PDI Reader describes how to create and use a PDI reader, and the section Using a PDI Reader - An Example provides an example of reading vCard data from an input stream. Writing vCard objects to an output data stream. The section Creating a PDI Writer describes how to create and use a PDI reader, and the section Using a PDI Writer - An Example provides an example of reading vCard data from an input stream. The PDI library handles reading and writing objects in a number of different formats, and from or to a variety of media. For more information about specifying the media, see "Using UDA for Different Media." ## PDI Property and Parameter Types The PDI library provides constants that you can use with the reader and writer objects to specify property information. These include the following types of constants that specify vObject standard entities: The Property Name constants represent the PDI property names. Each of the property name constants starts with the kPdiPRN_ prefix. For example, the kPdiPRN_ADR constant represents the ADR property name. For more information, see the section Property Name Constants in Chapter 78, "Personal Data Interchange Library," in Palm OS Programmer's API Reference. The Property Value Field constants represent the position of property value fields for properties with structured field values. Each of the property value field constants starts with the kPdiPVF_ prefix. For example, the kPdiPVF_ADR_COUNTRY constant represents the COUNTRY field of an ADR property value. For more information, see the section Property Value Field Constants in Chapter 78, "Personal Data Interchange Library," in Palm OS Programmer's API Reference. The Parameter Name constants represent the names of vObject property parameters. Each of the parameter name constants starts with the kPdiPAN_ prefix. For example, the kPdiPAN_Type constant represents the TYPE parameter, and the kPdiPAN_Encoding constant represents the ENCODING parameter. For more information, see the section Parameter Name Constants in Chapter 78, "Personal Data Interchange Library," in Palm OS Programmer's API Reference. The Parameter Value constants represent the combined name and value of parameters. Each of the parameter value constants starts with the kPdiPAV_ prefix. For example, kPdiPAV_ENCODING_BASE64 constant represents the Base64 encoding. For more information, see the section Parameter Value Constants in Chapter 78, "Personal Data Interchange Library," in Palm OS Programmer's API Reference. For a complete list of all of these constants, see the PdiConst.h file. ## The PDI Library Properties Dictionary The PDI library features a dictionary that stores information about the properties that are considered "well-known." A well-known property is one that is defined in one of the vObject standard specifications, including the vCard and vCal standards. Both of these standards can be found online at the PDI developer's web page:
    http://www.imc.org/pdi/pdiproddev.html
PDI readers and writers use information in the properties dictionary to determine how to read or write a certain property. Specifically, the dictionary stores information about the format of each property value; the reader uses this information to correctly parse the property value, and the writer uses this information to correctly format the written value. This information is important because some property values are structured with multiple fields, while others contain a single value field. For example, the standard address (ADR) property has a structured value with seven required fields, and the fields are separated by semicolons. The dictionary stores this information, and the PDI reader then knows to read seven, semicolon-separated fields when parsing an ADR property. By default, each PDI reader and writer uses a standard dictionary when parsing input and generating output. You can, however, override this behavior to parse or generate the value for a property in some other way. For more information, see "Reading Property Values" and "Writing Property Values." You can also amend or replace the dictionary to add parsing and/or generation of customized PDI properties for your application. For more information, see "Adding Custom Extensions." ## PDI Readers The PDI library provides the PDI reader object for reading and parsing vObject input. A PDI reader object is a structure that stores the current state of parsing through a PDI input stream. The PDI reader parses the input stream one property at a time, starting with the Begin Object property and finishing with the End Object property. The PdiReaderType structure stores a variety of information about the current state of parsing the input stream, including the following information about the current property: the encoding and character set the type of the current property, parameter, and property value the name of the current property and parameter the current property's value string a mask of the parsing events encountered for the current property #### About Parsing Events The PDI reader records each parsing event that it encounters while processing a property. For example, when it parses a BEGIN:VCARD property, the PDI reader records the kPdiBeginObjectEventMask, and when it parses a property name, the PDI reader records the kPdiPropertyNameEventMask. Each event is represented by one of the Reader Event Constants, which are described in Chapter 78, "Personal Data Interchange Library," in Palm OS Programmer's API Reference. The PDI reader records the event by adding (OR'ing) the event constant into the events field of the PdiReaderType structure. You can determine if a specific event has occurred while parsing the current property by testing that event's constant against the events field in the reader structure. For example, the following statement returns false if the end of the input stream was reached.
    return((reader->events & kPdiEOFEventMask)==0);
## PDI Writers The PDI library provides the PDI writer object for writing vObject output. A PDI writer object is a structure that stores the current state of and manages the generation of PDI data. The PDI writer sends data to the output stream one property at a time, starting with the Begin Object property and finishing with the End Object property. The PdiWriterType structure stores information about the current state of writing the output stream, including the following: the encoding and character set of the current property the mode used to write the current property value, which specifies how the property value is structured the number of required fields for the current property value ## Format Compatibility The PDI library can read and write data streams in the following formats: vCard 3.0 vCard 2.1 vCal 1.0 iCalendar Palm format You can use the PDI library to convert an input data stream that uses one format into an output data stream in another format. For more information, see "Specifying PDI Versions." #### Compatibility with Earlier Versions of the Palm OS The PDI library has been designed to maintain compatibility with earlier versions of the Palm OS, which means that you can use the library functions to receive vObjects from or send vObjects to devices that use those earlier versions. To take advantage of this compatibility, the PDI library has been built to send or receive data in different formats, one of which is the format supported by earlier versions of the Palm OS that included the ImcUtils implementation. To include support for this compatibility in a PDI Reader, specify the kPdiOpenParser constant in your call to the PdiReaderNew function. To include support for this compatibility in a PDI Writer, specify the kPdiPalmCompatibility option when calling the PdiWriterNew function. ## International Considerations The PDI library handles various character sets, including Katakana. If you specify the CHARSET parameter in the input stream, the PDI reader will correctly read the property value. The PDI library included with version 4.0 of the Palm OS® understands the following character sets: charEncodingAscii charEncodingISO8859_1 charEncodingShiftJIS charEncodingISO2022Jp If you specify an unknown character set, the current character set becomes unknown, as represented by the charEncodingUnknown constant. ## Features Not Yet Supported The PDI library included with version 4.0 of the Palm OS does not handle the following features: Multi-part MIME messages are not handled. The XML version of vObjects is not supported. Applications ignore grouping. The PDI reader parses group identifiers, but ignores them. However, the name of the group most recently parsed is stored in the groupName field of the PdiReaderType object. ## Using the PDI Library This section describes how to use the functions in the PDI library to read or write PDI content. Figure 3.1 shows the typical sequences of calls that you make to read or write vObjects. To read vObjects, you need to: access the PDI library create a PDI reader read each property in the input stream: - read the property name - read any parameters for the property - read the property value delete the PDI reader unload the PDI library To write vObjects, you need to: access the PDI library create a PDI writer write each property in the input stream: - write the property name - write any parameters for the property - write the property value delete the PDI writer unload the PDI library The remainder of this section describes the following operations: Accessing the PDI Library Unloading the PDI Library Creating a PDI Reader Reading Properties Creating a PDI Writer Writing Property Values Specifying PDI Versions Using UDA for Different Media The section "Using a PDI Reader - An Example" provides a detailed example of creating a PDI Reader and using it to import vCard data into a database. The section "Using a PDI Writer - An Example" provides a detailed example of creating a PDI Writer and using it to export data from a database in vCal format. Figure 3.1 Using the PDI library ## Accessing the PDI Library Before you can use the PDI library, you must load the library and obtain a reference number for it. Each of the functions in the library requires a reference number argument, which is used with the system code to access a shared library. The example function LoadPdiLibrary, which is shown in Listing 3.2, makes sure that the PDI library is loaded and returns a reference number for it. Listing 3.2 Loading the PDI library
    Static Err LoadPdiLibrary(UInt16 *libRefNum)
    {
       Err   error

       error = SysLibFind(kPdiLibName, librefNum);
       if (error != 0)
       {
          error = SysLibLoad(sysResTLibrary,
                                   sysFileCPdiLib, libRefNum);
       }
       if (error)
       {
          ErrNonFatalDisplay(kPdiLibName "not found")
          return error;
       }
       error = PdiLibOpen(*libRefNum);
       return error;
    }
The LoadPdiLibrary function first calls the SysLibFind function to determine if the library has already been loaded, which might be the case if your code has been called by another application that has already loaded the library. Note that the call to SysLibFind uses the kPdiLibName constant, which is defined as follows in the PdiLib.h file:
    #define kPdiLibName "Pdi.lib"
If the library has not already been loaded, LoadPdiLibrary calls the SysLibLoad function to load the library and obtain a reference number for it. After obtaining a reference number for the library, LoadPdiLibrary calls the PdiLibOpen function to open the loaded library. ## Unloading the PDI Library When you are done with the library, you should unload it. The example function UnloadPdiLibrary, which is shown in Listing 3.2, unloads the PDI library. Listing 3.3 Unloading the PDI library
    static void UnloadPdiLibrary(UInt16 refNum)
    {
       if (PdiLibClose(refNum) == 0)
       {
          SysLibRemove(refNum);
       }
    }
Note that the library reference number becomes invalid after you call the SysLibRemove function. ## Creating a PDI Reader To create a PDI reader, you need to first access the library, and then call the PdiReaderNew function, which is declared as follows:
    PdiReaderType* PdiReaderNew(UInt16 libRefnum,
    UDAReader *input, UInt16 optionFlags)
The PdiReaderNew parameters are: The library reference number, as described in "Accessing the PDI Library." The Unified Data Access (UDA) input stream to use with the reader. The UDA Manager allows you to read input from various sources, including strings and the Exchange Manager. For more information, see "Using UDA for Different Media." Option flags that control the parsing behavior of the reader, including its default encoding and compatibility settings. The option flags are described in Reader and Writer Options Constants in Chapter 78, "Personal Data Interchange Library," in Palm OS Programmer's API Reference. Once you have created the reader, you can use it to parse properties from the input stream. The section "Using a PDI Reader - An Example" provides an example of creating and using a PDI reader. ## Reading Properties To read PDI property data with a PDI reader, you need to call the data reading functions: PdiReadProperty reads a property and all of its parameters from the input stream. PdiReadPropertyName reads just the name of the next property from the input stream. You can call this function if you want to then handle the reading of the property's parameters individually. PdiReadParameter reads a single parameter and its value from the input stream. PdiReadPropertyField reads a property value field. A property value can a simple value, or it can be structured to contain multiple fields that are separated by commas or semicolons, as described in "Reading Property Values." The most common way to read input data is to follow these steps: Call PdiReadProperty to read the vObject Begin property. For example, if you are reading vCards, you can call PdiReadProperty until it reads the kPdiPRN_BEGIN_VCARD property from the input stream. Once you have found the beginning of the object, repeatedly call PdiReadProperty to read the next property and its parameters. For each property, call the PdiReadPropertyField function as required to read the fields of the property. Continue reading properties until you read the vObject End property. For vCards, you process properties until PdiReadProperty reads the kPdiPRN_END_VCARD property from the input stream. #### Examining Property Information After calling a property-reading function, you can access fields of the PdiReaderType object to determine information about the current property. The current property is the one that is currently being parsed, or which has just been parsed. For example, you can examine the property field of the PdiReaderType object to determine which type of property has just been read, or you can call the PdiParameterPairTest macro to determine if a certain parameter pair was present in the property definition. ## Reading Property Values Some properties have simple values and others have structured values. A structured property value has multiple fields that are separated by commas or semicolons. For example, the following phone property definition has a simple value:
    TEL;CELL:+1 (408) 555-4321
Note that the phone property contains a semicolon to separate the CELL parameter from the property name. Each property's value follows the colon in the definition. The following name property definition has a structured value that contains four fields separated by semicolons:
    N:Smith; John;M.;Mr.; Esq.
You must pass a parameter to the PdiReadPropertyField function to tell it how to process a property value. To specify how the field is formatted, use one of the Property Value Format Constants described in Chapter 78, "Personal Data Interchange Library," in Palm OS Programmer's API Reference. You can specify kPdiDefaultFields to allow the PDI reader to determine the property value format. The reader looks up the property name in the dictionary to determine its format. Specify kPdiNoFields to have the reader parse the entire value in one operation. Specify kPdiCommaFields or kPdiSemicolonFields to have the reader parse a single field from the value. Specify kPdiConvertComma or kPdiConvertSemicolon to have the reader parse all of the fields in a value into a single value. You can usually specify kPdiDefaultFields and allow the PDI Reader to use the information in the dictionary to properly parse the value. However, this might not always meet your needs, especially if your input stream contains custom properties. Table 3.1 shows the results of using the different format constants to read the same property from the input stream. The example property is a standard address (ADR) property that has a structured value with seven, semicolon-delimited fields:
    ADR:postoffice;extended;street;locale;region;postal_code;country
Note that since the ADR property is defined in the vCard standard as a structured value with seven, semicolon-delimited field, the PDI library dictionary defines its default format as kPdiSemicolon. #####
Table 3.1 Parsing a structured value with different value format types
Value format type | Description of PdiReadPropertyField results
--- | ---
kPdiNoFields | One call returns the entire value as a string: "postoffice;extended;street;locale;region;postal_code;country"
kPdiSemicolon | Each call returns a single, semicolon-delimited field from the value. For example: the first call returns "postoffice" the second call returns "extended" the third call returns "street"
kPdiComma | Each call returns a single, comma-delimited field from the value. For example, if the input string is "postoffice,extended,street," then: the first call returns "postoffice" the second call returns "extended" the third call returns "street"
kPdiConvertSemicolon | One call returns the entire value as a string that has newline characters wherever a semicolon appeared in the input: "postoffice extended street locale region postal_code country"
kPdiConvertComma | One call returns the entire value as a string that has newline characters wherever a comma appeared in the input: "postoffice extended street locale region postal_code country"
kPdiDefaultFields | Same as kPdiSemicolon, because the PDI library dictionary defines the property value format of the ADR field as kPdiSemicolon.
#### Reading Value Fields One At a Time If you are reading the fields in a structured value one at a time, and you don't know the exact number of fields, you can call PdiReadPropertyField repeatedly until it returns a nonzero result. For example, the following code segment from the DateTransfer.c program parses each field of the EXDATE property value fields: Listing 3.4 Reading an undetermined number of value fields
    while (PdiReadPropertyField(pdiRefNum, reader, &tempP,
                             kPdiResizableBuffer, kPdiSemicolonFields) == 0)
       {
                   // Resize handle to hold exception
          err = MemHandleResize(exceptionListH,
    sizeof(ExceptionsListType) + sizeof(DateType) * exceptionCount);
          ErrFatalDisplayIf(err != 0, "Memory full");
                  // Lock exception handle
          exceptionListP = MemHandleLock(exceptionListH);
                  // Calc exception ptr
          exceptionP = (DateType*)((UInt32)exceptionListP
                             + (UInt32)sizeof(UInt16)
                             + (UInt32)(sizeof(DateType) * exceptionCount));
                   // Store exception into exception handle
          MatchDateTimeToken(tempP, exceptionP, NULL);
                   // Increase exception count
          exceptionCount++;
                   // Unlock exceptions list handle
          MemHandleUnlock(exceptionListH);
       }
NOTE: If you leave fields in a structured value unread, the next call to PdiReadProperty will skip over them and correctly find the beginning of the next property. #### Adding Custom Extensions The vObject standards are extensible, which means that you can add custom properties to vCards and other vObjects. The PDI library handles these custom properties; however, you must either add an entry to the library's dictionary for each custom property, or specify a constant other than kPdiDefaultFields when parsing the property's value. Each PDI reader object and each PDI writer object can have a custom dictionary associated with it. You can configure the custom dictionary to amend or to replace the standard, built-in dictionary. To associate a custom dictionary with a reader or writer, you need to first create the dictionary with the You can then call the PdiDefineReaderDictionary function to associate that dictionary with a reader object or call the PdiDefineWriterDictionary function to associate the dictionary with a writer object. NOTE: For more information about the dictionary tool at http://www.palmos.com/dev/tech/kb. ## Creating a PDI Writer To create a PDI writer, you need to first access the library, and then call the PdiWriterNew function, which is declared as follows:
    PdiWriterType* PdiWriterNew(UInt16 libRefnum,
    UDAWriter *output, UInt8 optionFlags)
The PdiWriterNew parameters are: The library reference number, as described in "Accessing the PDI Library.". The UDA output stream to use with the writer. For more information, see "Using UDA for Different Media." Option flags that control the output generation behavior of the writer, including its default encoding and compatibility settings. The option flags are described in Reader and Writer Options Constants in Chapter 78, "Personal Data Interchange Library," in Palm OS Programmer's API Reference. Once you have created the writer, you can use it to generate properties to the output stream. The section "Using a PDI Writer - An Example" provides an example of creating and using a PDI writer. ## Writing Properties To write PDI data with a PDI writer, you need to call the data writing functions. The most commonly used functions are: PdiWriteBeginObject, which writes a vObject Begin tag to the output stream. PdiWriteEndObject, which writes a vObject End tag to the output stream. PdiWriteProperty, which writes a property to the output stream. PdiWritePropertyValue, which writes a property value to the output stream. The most common way to write output data is to follow these steps: Call PdiWriteBeginObject to write the vObject Begin property. For example, if you are writing vCards, you call PdiWriteBeginObject to write the kPdiPRN_BEGIN_VCARD property to the output stream. For each property that you want to write, call PdiWriteProperty to write the next property and its parameters, and then call the PdiWritePropertyValue function to write the property's value. Call PdiWriteEndObject to write the vObject End property. For example, if you are writing vCards, you call PdiWriteEndObject to write the kPdiPRN_END_VCARD property to the output stream. ## Writing Property Values In many cases, you can simply call the PdiWritePropertyValue function to write a value to the output stream. If a value contains a variable number of fields, you can instead use the PdiWritePropertyFields to write the fields from an array. Or you can use the PdiWritePropertyStr to write multiple fields separated by commas or semicolons. ## Specifying PDI Versions The PDI library options constants control how the PDI reader and PDI writer operate. These options are described in Reader and Writer Options Constants in Chapter 78, "Personal Data Interchange Library," in Palm OS Programmer's API Reference. ## Using UDA for Different Media The PDI reader and writer objects use Unified Data Access (UDA) Manager objects for reading from and writing to a variety of media. The UDA data types, constants, and functions are documented in Chapter 79, "Unified Data Access Manager," in Palm OS Programmer's API Reference. This section provides an overview of using UDA objects with the PDI library. ## About the UDA Library The UDA Manager provides an abstract layer for reading, filtering, and writing data to and from different media. The UDA Manager provides three general purpose object types: UDAReaderType objects (UDA Readers) read data from an input stream. UDAFilterType objects (UDA Filters) take input from UDA Readers or UDA Filters, perform some encoding or decoding operations, and output the data to a memory buffer. UDAWriterType objects (UDA Writers) write data to a filter or an output stream. The UDA Manager provides general purpose functions for creating these object types. In addition, the UDA Manager provides built-in object types for working with memory buffers and the Exchange Manager. NOTE: The implementation of the UDA Manager in version 4.0 of the Palm OS does not provide built-in filter objects. These objects are planned for future versions. #### Interfacing with the Exchange Manager The UDA Manager provides two functions for interfacing with the Exchange Manager: The UDAExchangeReaderNew function creates a UDA Reader object that reads data from an Exchange Manager socket. The UDAExchangeWriterNew function creates a UDA Writer object that writes data to an Exchange Manager socket. The Exchange Manager, which is described in Chapter 1, "Object Exchange," provides a mechanism for reading typed data in a transport-independent manner. When you use the UDA interface to the Exchange Manager, you add the benefits of a simple, uniform way to read and write data in a transport-independent manner. This allows you to create PDI readers and writers that can work on data that is stored on a variety of media types. If you wish to parse PDI objects from memory, you can use an object created by the UDAMemoryReaderNew function instead of an Exchange Manager reader object. The PDI Reader example in the next section reads its data from an Exchange Manger socket, using the UDAExchangeReaderNew function to create the reader object. The PDI Writer example in "Using a PDI Writer - An Example" writes its data to an Exchange Manager socket, using the UDAExchangeWriterNew function to create the writer object. ## Using a PDI Reader - An Example This section provides an example of reading PDI data from an input stream and storing it in a database. This example is from the AddressTransfer.c file, which is located inside of the Examples/Address/Src folder. Listing 3.5 shows the TransferReceiveData function from the AddressTransfer.c sample program. This function controls the reading of vCard data into the address database by performing the following operations: Calls the ExgAccept function to accept a connection from a remote device. Calls a local function, PrvTransferPdiLoadLibrary, to load an open the PDI library. The PrvTransferPdiLoadLibrary function is almost exactly the same as the LoadPdiLibrary function shown in Listing 3.2. Calls the UDAExchangeReaderNew function to create an input data stream for connection with the Exchange Manager. Calls the PdiReaderNew function to create a new PDI reader object that reads from the input stream. Repeatedly calls the local function TransferImportVCard to read vCard data and store it into the address database. This function is described in the next section, Importing vCard Data Into a Database. Calls the ExgDisconnect function to terminate the transfer and close the connection. Calls the PrvTransferPdiLibUnload function to unload the PDI library. Deletes the PDI reader and UDA input stream objects. Listing 3.5 Reading a PDI input stream
    extern Err TransferReceiveData(DmOpenRef dbP, ExgSocketPtr exgSocketP)
    {
       volatile Err err;
       UInt16 pdiRefNum = sysInvalidRefNum;
       PdiReaderType* reader = NULL;
       UDAReader* stream = NULL;
       Boolean loaded;

       if ((err = ExgAccept(exgSocketP)) != 0)
          return err;
       if ((err = PrvTransferPdiLibLoad(&pdiRefNum, &loaded)))
       {
          pdiRefNum = sysInvalidRefNum;
          goto errorDisconnect;
       }
       if ((stream = UDAExchangeReaderNew(exgSocketP)) == NULL)
       {
          err = exgMemError;
          goto errorDisconnect;
       }
       if ((reader = PdiReaderNew(pdiRefNum, stream, kPdiOpenParser)) == NULL)
       {
          err = exgMemError;
          goto errorDisconnect;
       }
       reader->appData = exgSocketP;
       ErrTry
       {
          while(TransferImportVCard(dbP, pdiRefNum, reader, false, false)){};
       }
       ErrCatch(inErr)
       {
          err = inErr;
       } ErrEndCatch
       if (err == errNone && exgSocketP->goToParams.uniqueID == 0)
          err = exgErrBadData;
    errorDisconnect:
       if (reader)
          PdiReaderDelete(pdiRefNum, &reader);
       if (stream)
          UDADelete(stream);
       if (pdiRefNum != sysInvalidRefNum)
          PrvTransferPdiLibUnload(pdiRefNum, loaded);
       ExgDisconnect(exgSocketP, err); // closes transfer dialog
       err = errNone; // error was reported, so don't return it
       return err;
    }
#### Importing vCard Data Into a Database The TransferImportVCard function imports a vCard record from an input stream. Listing 3.6 shows the basic outline of the TransferImportVCard function; you can review the entire function by viewing the AddressTransfer.c file, which is located inside of the Examples/Address/Src folder. Listing 3.6 Importing vCard data into a database
    Boolean TransferImportVCard(DmOpenRef dbP, UInt16 pdiRefNum,
    PdiReaderType* reader, Boolean obeyUniqueIDs, Boolean beginAlreadyRead)
    {

    ...    // local declarations and initialization code

       ErrTry
       {
          phoneField = firstPhoneField;
          if (!beginAlreadyRead)
          {
             PdiReadProperty(pdiRefNum, reader);
             beginAlreadyRead = reader->property == kPdiPRN_BEGIN_VCARD;
          }
          if (!beginAlreadyRead)
             ErrThrow(exgErrBadData);
          PdiEnterObject(pdiRefNum, reader);
          PdiDefineResizing(pdiRefNum, reader, 16, tableMaxTextItemSize);
          while (PdiReadProperty(pdiRefNum, reader) == 0
                   && (property = reader->property) != kPdiPRN_END_VCARD)
          {
             switch(property)
             {
             case kPdiPRN_N:
             PdiReadPropertyField(pdiRefNum, reader,
                            (Char **) &newRecord.fields[name],
                               kPdiResizableBuffer, kPdiDefaultFields);
             PdiReadPropertyField(pdiRefNum, reader,
                            (Char **) &newRecord.fields[firstName],
                               kPdiResizableBuffer, kPdiDefaultFields);
          break;
             case kPdiPRN_NOTE:
                PdiDefineResizing(pdiRefNum, reader, 16,
                               noteViewMaxLength);
                PdiReadPropertyField(pdiRefNum, reader,
                            Char **) &newRecord.fields[note],
                               kPdiResizableBuffer, kPdiNoFields);
                PdiDefineResizing(pdiRefNum, reader, 16,
                               tableMaxTextItemSize);
                 break;

    ,,,  // other cases here for other properties

          }
          } // end while
                    if (newRecord.fields[name] != NULL
             && newRecord.fields[company] != NULL
             && newRecord.fields[firstName] != NULL
             && StrCompare(newRecord.fields[name],
                                  newRecord.fields[company]) == 0)
          {     // if company & name fields are identical, assume company only
             MemPtrFree(newRecord.fields[name]);
             newRecord.fields[name] = NULL;
          }
    AddRecord:
             err = AddrDBNewRecord(dbP, (AddrDBRecordType*) &newRecord,
                                     &indexNew);
             if (err)
                ErrThrow(exgMemError);

       ...      // handle category assignment here

       }   //end of ErrTry
       if (error == exgErrBadData)
          return false;
       if (error != errNone)
          ErrThrow(error);
       return ((reader->events & kPdiEOFEventMask) == 0);
    }
The TransferImportVCard function performs the following operations: Calls the PdiReadProperty function to read the BEGIN:VCard property from the input stream. Calls the PdiEnterObject function to notify the PDI library that it is reading a new object from the input stream. Calls the PdiDefineResizing function to set the maximum buffer size for reading properties for the address card. Repeatedly calls the PdiReadProperty function to read properties of the address card. This repeats until PdiReadProperty reads the END:VCard property, which indicates the end of data for the address card. For each address card property, calls PdiReadPropertyField as required to read the values associated with the property. For example, when it reads the kPdiPRN_N name property, AddrImportVCard calls PdiReadPropertyField twice: once to read the last name, and a second time to read the first name. Creates a new address record and adds it to the Address Book database. Deallocates memory that it has allocated and performs other cleanup operations. Again, note that Listing 3.6 only shows the outline of this function. You can find the entire function in the AddressTransfer.c file. ## Using a PDI Writer - An Example This section provides an example of writing PDI data from a database record to an output stream. This example is from the ToDoTransfer.c file, which is located inside of the Examples/ToDo/Src folder. Listing 3.7 shows an example of creating and using a PDI writer. The ToDoSendRecordTryCatch function controls the writing of data from the To Do database to vCal objects by performing the following operations: Calls a local function, LoadPdiLibrary, to load and open the PDI library. The LoadPdiLibrary function is shown in Listing 3.2. Calls the PdiWriterNew function to create a new PDI writer object that writes to the UDA output stream specified by the media parameter. Calls the PdiWriteBeginObject function to write the BEGIN:VCAL property to the output stream. Calls the PdiWriteProperty function to write the VERSION property, and then calls the PdiWritePropertyValue function to write the version value. Calls the ToDoExportVCal function to write the To Do record, as described in the next section, Exporting vCal Data From a Database. Calls the PdiWriteEndObject function to write the END:VCAL property to the output stream. Deletes the PDI writer object and unloads the PDI library. Listing 3.7 Writing a PDI Output Stream
    static Err ToDoSendRecordTryCatch (DmOpenRef dbP,
            Int16 recordNum, ToDoDBRecordPtr recordP, UDAWriter* media)
    {
       volatile Err error = 0;
       UInt16 pdiRefNum;
       PdiWriterType* writer;

       if ((error = LoadPdiLibrary(&pdiRefNum)))
           return error;
       writer = PdiWriterNew(pdiRefNum, media, kPdiPalmCompatibility);
       if (writer)
          {
    ErrTry
          {
             PdiWriteBeginObject(pdiRefNum, writer,
                                                      kPdiPRN_BEGIN_VCALENDAR);
             PdiWriteProperty(pdiRefNum, writer, kPdiPRN_VERSION);
             PdiWritePropertyValue(pdiRefNum, writer, (Char*)"1.0",
                                             kPdiWriteData);
              ToDoExportVCal(dbP, recordNum, recordP, pdiRefNum,
                                     writer, true);
              PdiWriteEndObject(pdiRefNum, writer,
                                                             kPdiPRN_END_VCALENDAR);
              }
    ErrCatch(inErr)
            {
               error = inErr;
            } ErrEndCatch
             PdiWriterDelete(pdiRefNum, &writer);
           }
       UnloadPdiLibrary(pdiRefNum);
       return error;
    }
#### Exporting vCal Data From a Database The ToDoExportVCal function exports a vCal record from the To Do database to an output stream. Listing 3.8 shows the basic outline of the ToDoExportVCal function; you can review the entire function by viewing the ToDoTransfer.c file, which is located inside of the Examples/Address/Src folder. Listing 3.8 Exporting vCal data from a database
    extern void ToDoExportVCal(DmOpenRef dbP, Int16 index,
    ToDoDBRecordPtr recordP, UInt16 pdiRefNum, PdiWriterType* writer,
    Boolean writeUniqueIDs)
    {
    Char *          note;
          UInt32      uid;
          Char        tempString[tempStringLengthMax];
          UInt16      attr;
    ...

       PdiWriteBeginObject(pdiRefNum, writer, kPdiPRN_BEGIN_VTODO);
          // Emit the Category
       PdiWriteProperty(pdiRefNum, writer, kPdiPRN_CATEGORIES);
          // ...code to create the property string (tempString)
       PdiWritePropertyValue(pdiRefNum, writer, tempString, kPdiWriteText);

          // Code to emit the record information, including the:
          //   - due date
          //   - completed flag
          //   - priority value
          //   - description text
    ...

          // Emit the note
       if (*note != '\0')
       {
          PdiWriteProperty(pdiRefNum, writer, kPdiPRN_ATTACH);
          PdiWritePropertyValue(pdiRefNum, writer, note, kPdiWriteText);
       }

          // Emit an unique id
       if (writeUniqueIDs)
       {
          PdiWriteProperty(pdiRefNum, writer, kPdiPRN_UID);
          // Get the record's unique id and append to the string.
          DmRecordInfo(dbP, index, NULL, &uid, NULL);
          StrIToA(tempString, uid);
          PdiWritePropertyValue(pdiRefNum, writer, tempString, kPdiWriteData);
       }

       PdiWriteEndObject(pdiRefNum, writer, kPdiPRN_END_VTODO);
    }
The ToDoExportVCal function performs the following operations: Calls the PdiWriteBeginObject function to write the BEGIN:VTODO property to the output stream. Calls the PdiWriteProperty function to write the category information for the To Do record. Calls the PdiWriteProperty function to write other information for the To Do record, including the due date, completed flag, priority value, and description text. Calls the PdiWriteProperty function to write the note and again to write a unique ID for the note. Calls the PdiWriteEndObject function to write the END:VTODO property to the output stream. Again, note that Listing 3.8 only shows the outline of this function. You can find the entire function in the ToDoTransfer.c file. ## Summary of Personal Data Interchange #####
PDI Library Functions |
--- | ---
Library Open and Close
PdiLibClose | PdiLibOpen
Object Creation and Deletion
PdiReaderNew PdiReaderDelete | PdiWriterNew PdiWriterDelete
Property Reading
PdiDefineResizing PdiEnterObject PdiParameterPairTest PdiReadParameter | PdiReadProperty PdiReadPropertyField PdiReadPropertyName
Property Writing
PdiSetCharset PdiSetEncoding PdiWriteBeginObject PdiWriteEndObject PdiWriteParameter | PdiWriteParameterStr PdiWriteProperty PdiWritePropertyBinaryValue PdiWritePropertyFields PdiWritePropertyStr PdiWritePropertyValue
Property Dictionary
PdiDefineReaderDictionary | PdiDefineWriterDictionary
## Summary of Unified Data Access Manager ##### #####
UDA Manager Functions
UDAControl UDADelete UDAEndOfReader UDAFilterJoin UDAInitiateWrite | UDAMoreData UDARead UDAWriterFlush UDAWriterJoin
Object Creation |
UDAExchangeReaderNew UDAExchangeWriterNew | UDAMemoryReaderNew