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 88, "Personal Data Interchange Library," in Palm OS Programmer's API 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 89, "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:
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, thekPdiPRN_ADR
constant represents theADR
property name. For more information, see the section Property Name Constants in Chapter 88, "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, thekPdiPVF_ADR_COUNTRY
constant represents theCOUNTRY
field of anADR
property value. For more information, see the section Property Value Field Constants in Chapter 88, "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, thekPdiPAN_Type
constant represents theTYPE
parameter, and thekPdiPAN_Encoding
constant represents theENCODING
parameter. For more information, see the section Parameter Name Constants in Chapter 88, "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 theBase64
encoding. For more information, see the section Parameter Value Constants in Chapter 88, "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 88, "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:
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:
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 thePdiReaderType
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:
- 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:
- 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 88, "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 callPdiReadProperty
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 thekPdiPRN_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 88, "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
orkPdiSemicolonFields
to have the reader parse a single field from the value. - Specify
kPdiConvertComma
orkPdiConvertSemicolon
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
.
Description of |
|
---|---|
One call returns the entire value as a string: "postoffice;extended;street;locale;region;postal_code;country" |
|
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" |
|
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" |
|
One call returns the entire value as a string that has newline characters wherever a semicolon appeared in the input: |
|
One call returns the entire value as a string that has newline characters wherever a comma appeared in the input: |
|
Same as |
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.
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 88, "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 callPdiWriteBeginObject
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 thePdiWritePropertyValue
function to write the property's value. - Call
PdiWriteEndObject
to write the vObject End property. For example, if you are writing vCards, you callPdiWriteEndObject
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 88, "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 89, "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. ThePrvTransferPdiLoadLibrary
function is almost exactly the same as theLoadPdiLibrary
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 theBEGIN: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 untilPdiReadProperty
reads theEND: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 thekPdiPRN_N
name property,AddrImportVCard
callsPdiReadPropertyField
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. TheLoadPdiLibrary
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 themedia
parameter. - Calls the
PdiWriteBeginObject
function to write theBEGIN:VCAL
property to the output stream. - Calls the
PdiWriteProperty
function to write theVERSION
property, and then calls thePdiWritePropertyValue
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 theEND: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 theBEGIN: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 theEND: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.