Next: , Previous: Manipulating Data Packet Fields, Up: Manipulating Data Packet Fields


4.4.1 Field Information

Unlike header fields, which always use a name and index combination to access field information, there are two methods of accessing data packet fields. If a single data packet is being read or written, and the same memory is used for all packets, and all that is required is a pointer to the data in the data packet, then the simplest approach is to use bpipe_dpktf_datap. Note that bpipe_dpktf_datap must be called after the core image is mapped (via bpipe_map or bpipe_map_alloc).

Here's an approach if you only need to look at one field in a data packet:

     BPipe *bpipe;
     DVector3 *pos;
     void *core;
     
     /* create bpipe, set input stream */
     ...
     
     /* map data packet images */
     if ( NULL == ( core = bpipe_map_alloc( bpipe, 1, NULL ) ) )
     {
       (error handling code)
     }
     
     /* get pointer to position field in data packet */
     if ( NULL ==
          ( pos = (DVector3 *) bpipe_dpktf_datap( bpipe, core, "position",
                                                  BPDType_DVector3 ) ) )
     {
       (error handling code)
     }

This usually gets unwieldy if there is more than one data field that is being accessed. Here's a way around that:

     DVector3 *pos;
     DVector3 *dir;
     
     pos = (DVector3 *) dpktf_data( bpipe, core, "position", BPDType_DVector3 );
     dir = (DVector3 *) dpktf_data( bpipe, core, "direction", BPDType_DVector3 );
     
     ...
     
     void *
     dpktf_data( BPipe *bpipe, char *name, void *core_image, BPDataType *type )
     {
       void *data = bpipe_dpktf_datap( bpipe, core_image, name, type );
     
       if ( NULL == data )
       {
         (error handling code)
       }
     
       return data;
     }

Note that in these examples, space for a single data packet is allocated and used for each data packet, so the addresses of the data packet fields are constant. This is typical of most applications. In this situation all data offsets should be determined before reading in the data.

However, if multiple data packets are processed at once (e.g., several are read in at a time), it is necessary to redetermine the positions of the fields for each data packet processed. Since bpipe_dpktf_datap is a function, this can be expensive. The solution to this is to use a different access mechanism, via data packet field handles. Because one can obtaining a pointer to the field in the data packet directly from the handle (via a C preprocessor macro, rather than a function) this is a much more efficient way of accessing data from within a loop, especially if processing several data packets at once.

A data packet field handle is first retrieved via bpipe_dpktf. (This routine can also be used to determine if a data packet field already exists.) After mapping of the images, the offset of the data field in the core image is available, and can be retrieved with bpipe_dpktf_offset. Pointers into the core image of the data packet are available from bpipe_dpktf_arr and bpipe_dpktf_data. Field data is available only after a data packet has been read in via bpipe_read_dpkts. At that point the data can be retrieved with bpipe_dpktf_val or bpipe_dpktf_valn.

The following example illustrates a few ways of getting at the data in this situation.

     BPipe *bpipe;
     DpktField *dpktf;
     DVector3 *pos;
     void *core_image;
     size_t core_image_size, n_pkts, pos_offset;
     
     /* create bpipe, set input stream */
     ...
     
     /* map data packet images */
     if ( NULL == ( core_image = bpipe_map_alloc( bpipe, NPKTS, &core_image_size ) ) )
     {
       (error handling code)
     }
     
     if ( NULL == ( dpktf = bpipe_dpktf( bpipe, "position" ) )
     {
       (error handling code)
     }
     
     pos = (DVector3 *) bpipe_dpktf_data(dpktf, core_image);
     pos_offset = bpipe_dpktf_offset( dpktf );
     
     bpipe_errno = BPNOERROR;
     while ( (n_pkts = bpipe_read_dpkts( bpipe, core_image, NPKTS)) > 0 )
     {
        DVector3 *tpos = pos;        /* location of the "position" data */
        void *pkt = core_image;
        void *pkt_lim = core_image + n_pkts;
     
        /* tpos will point at the location of the "position" data in the
           current data packet.  this algorithm uses the fact that the
           data in a succeeding packet are always core_image_size bytes
           from those in the preceeding packet */
        for (; pkt < pkt_lim ;
               pkt += core_image_size, tpos += core_image_size )
        {
          double dist2;
     
          /* tpos may be calculated as above, or directly calculated
             here as follows */
          tpos = (DVector3 *) ((char *) pkt + pos_offset);
     
          dist2 = tpos->x * tpos->x + tpos->y * tpos->y + tpos->z * tpos->z;
        }
     }
     
     if ( bpipe_errno != BPNOERR )
     {
       (error handling code)
     }
     

Retrieval of all other field information requires a data packet field handle as well.

If the program needs to go through the list of fields sequentially, repeated calls to bpipe_dpktf_next will step through the the fields, retrieving handles for each field.

Some information is available before the mapping of data packet images by bpipe_map or bpipe_map_alloc. This includes a field's matrix (bpipe_dpktf_matrix), type (bpipe_dpktf_type). and name (bpipe_dpktf_name). The latter is useful when stepping through the list of fields via bpipe_dpktf_next. For an interesting application of this, see bpipe_dump.