Drawings SDK Developer Guide > Working with .dwg Files > Working with Databases > Working with Tagged Data > Example of Working with the Sequence of Tagged Data
Example of Working with the Sequence of Tagged Data

This example demonstrates working with a sequence of tagged data implemented using a resbuf-instance for adding, inserting, modifying, deleting, clearing, and printing data. This example uses a console menu for the following operations: printing the sequence of resbuf-instances [P], creating and adding a new resbuf-instance to the sequence [A], inserting a new resbuf-instance into the sequence [I], modifying an existing resbuf-instance [M], deleting a resbuf-instance [D], and clearing the sequence [C].

The example implements three specific functions:

  • PrintRbSequence() — Printing a sequence of resbuf-instances.
  • ClearRbSequence() — Deleting all resbuf-instances from a sequence.
  • ModifyRbSequence() — Modifying a sequence and resbuf-instances in the sequence.

The PrintRbSequence() function prints the tagged data for all resbuf-instances of the passed sequence. This function does not return a value and requires a smart pointer to an existing sequence of resbuf-instances as the first argument and the pointer to the user-defined function for displaying the tagged data of one resbuf-instance (AboutData) as the second argument. The PrintRbSequence() function checks whether the passed pointer refers to a sequence. When the passed pointer is NULL, the function displays a message about an empty sequence. When the sequence is not empty, the function organizes the loop in which it traverses through resbuf-instances using the next() method and displays information about each resbuf-instance using the pointer to the AboutData user-defined function obtained as the second argument. The AboutData user-defined function returns the information about the group code, data type, and data value as a value of the OdString type. The user-defined function requires a pointer to the resbuf-instance, whose properties are being displayed, and the sign which defines whether the information is whole or short. Implementation of the AboutData user-defined function depends on the tagged data technology being used (XData, XRecord, DXF).

The PrintRbSequence() function has the following implementation:


void PrintRbSequence(OdResBufPtr pData, OdString (*AboutData)(OdResBuf*,bool))
{
  if(pData.isNull())
    wcout << L"\nResbuf-sequence is empty\n";
  else
  {
    wcout << L"\nResbuf-sequence contains:\n";
    while(!pData.isNull())
    {
      wcout << AboutData(pData.get(), false) << L"\n";
      pData = pData->next();
    }
  }
}

The ClearRbSequence() function deletes all resbuf-instances and clears the sequence. This function does not return a value and requires a reference to the smart pointer which refers to the sequence of resbuf-instances to be cleared as an argument. The function organizes the loop in which it copies the pointer to next resbuf-instance into a pointer passed as an argument and assigns NULL for the pointer to the current resbuf-instance excluded from the sequence. When the pointer to a resbuf-instance gets NULL, it decreases the reference counter by one. When the resbuf-object loses all references itself, its reference counter becomes zero and the release() method deletes it automatically. The loop excludes a resbuf-instance from the sequence using the next() method and deletes it using the assignment to NULL until the pointer to the passed sequence becomes NULL.

The ClearRbSequence() function has the following implementation:


void ClearRbSequence(OdResBufPtr& pData)
{
  OdResBufPtr pRb;
  while(!pData.isNull())
  {
    pRb = pData;
    pData = pData->next();
    pRb = NULL;
  }
}

The ModifyRbSequence() function modifies the sequence of resbuf-instances and properties of each instance. The function implements a console menu for the listed operations. The function declares two variables as smart pointers to the resbuf-object for operations with the sequence and a variable as an integer value for an index. The function organizes the loop in which it inquires about the operation and uses the switch statement to select whether the case must be performed. The function processes user actions in the loop until the user selects the [Q] operation. The ModifyRbSequence() function does not return a value and requires four arguments:

  • First argument — reference to the smart pointer which refers to the sequence of resbuf-instances to be modified. The function returns the modified sequence through the first argument. The smart pointer must have the OdResBufPtr type and must exist in the calling function. The smart pointer can be NULL.
  • Second argument — pointer to the user-defined function which returns information about the passed resbuf-instance as a value of the OdString type. This user-defined function, named AboutData, requires a pointer to an existing resbuf-object about which the function displays information as the first argument and a Boolean value which defines whether the information is whole (True) or short (False).
  • Third argument — pointer to the user-defined function which enters the group code and data value or modifies the data value for the specified resbuf-instance and returns True when the resbuf-instance is modified, or False when the user cancels entry. This user-defined function, named EntryData, requires a pointer to the existing resbuf-object to be modified as the first argument and a Boolean value that defines whether the function modifies the group code and data value (True) or only the data value (False). The user-defined function organizes a loop in which it enters the tagged data.
  • Fourth argument — pointer to the user-defined function that checks whether the resbuf-instance is the specific marker of the sequence that cannot be modified or deleted. This user-defined function, named IsMarker, requires a pointer to an existing resbuf-instance and returns True when the group code of the resbuf-instance is the specific marker or False when the group code of the resbuf-instance is ordinary.

Implementations of the AboutData, EntryData, and IsMarker user-defined functions depend on the tagged data technology being used (XData, XRecord, DXF).

When the user selects [P], the ModifyRbSequence() function prints the sequence of resbuf-instances. The function checks whether the pointer refers to the current sequence. When the pointer is NULL, the sequence is empty, and the function displays a message about the empty sequence. When the sequence contains tagged data, the function organizes the loop in which it traverses through the sequence of resbuf-instances using the next() method until the pointer is NULL and displays information about each resbuf-instance using the pointer to the AboutData() user-defined function obtained as the second argument. In the AboutData() user-defined function, The ModifyRbSequence() function passes a pointer to the currently traversed resbuf-instance as the first argument and True as the second argument for displaying group code, data type, and data value. Additionally, the function displays the index of each resbuf-instance in the sequence beginning with one.

When the user selects [A], the ModifyRbSequence() function creates a new resbuf-instance using the newRb() method that is the static pseudo-constructor of the resbuf-object. Then the function requests the group code and data value for the new resbuf-instance using the pointer to the EntryData() user-defined function obtained as the third argument. In the EntryData() user-defined function, the ModifyRbSequence() function passes a pointer to the created resbuf-instance as the first argument and True as the second argument for selecting a group code and entering a data value. If the EntryData() user-defined function returns False (the user cancels entry), the ModifyRbSequence() function deletes the resbuf-instance using the assignment to NULL. The release() method of the resbuf-object automatically deletes the instance when the reference counter becomes zero. If the EntryData() user-defined function returns True (the instance is modified successfully), the ModifyRbSequence() function adds it in the sequence. Then, when the sequence is empty, the function assigns the pointer of the created resbuf-instance to the pointer of the sequence. When the sequence has resbuf-instances, the function moves to the end of the sequence using the last() method and assigns the pointer of the created resbuf-instance to the pointer of the last resbuf-instance using the setNext() method.

When the user selects [I], the ModifyRbSequence() function checks whether the sequence is empty because insertion is possible only when a sequence has resbuf-instances. If the sequence is empty, the function displays an error message and breaks to the console menu. If the sequence has resbuf-instances, the function requests the index of the resbuf-instance after which a new resbuf-instance must be inserted. After entering an index, the function organizes a loop for traversing through resbuf-instances from the beginning to the end of the sequence. The function moves the pointer to the current resbuf-instance using the next() method and decrements the index until it is more than one and the pointer is not NULL. When the traverse is completed, the function checks the pointer. If the pointer is NULL, the specified index is absent from the sequence and the function displays an error message and breaks to the console menu. If the pointer is not NULL, it refers to the resbuf-instance corresponding to the specified index. The following actions are the same as the [A] operation, that is, the function creates a new resbuf-instance using the newRb() method and enters a group code and data value using the pointer to the EntryData() user-defined function obtained as the third argument. If entry is successful, the ModifyRbSequence() function inserts the new resbuf-instance in the sequence using the insert() method. If entry is incorrect (the specified index is out of scope or the user cancels entry), the function displays an error message and breaks to the console menu.

When the user selects [M], the ModifyRbSequence() function requests the index of the resbuf-instance to be modified. The function checks the entered index in the same way as the [I] operation, that is, the function organizes a loop for traversing through resbuf-instances, moves the pointer using the next() method, and decrements the index until it is more than one and the pointer is not NULL. When the traverse is completed, the function checks the pointer. If the pointer is not NULL, it refers to the resbuf-instance specified by the index and the function checks whether its group code is the specific marker using the pointer to the IsMarker() user-defined function obtained as the fourth argument. When the specified resbuf-instance is the marker, the function displays an error message and breaks to the console menu. When the specified resbuf-instance does not contain a specific marker, the function modifies the group code and data value if the key is 'M', or modifies only the data value if the key is 'm'. To modify the tagged data, the function uses the pointer to the EntryData() user-defined function obtained as the third argument. The function passes a pointer to the found resbuf-instance as the first argument and True when the key is 'M' or False when the key is 'm' as the second argument. After entry, the ModifyRbSequence() function displays information about the modified resbuf-instance using the pointer to the AboutData() user-defined function obtained as the second argument. When entry is incorrect (the specified index is out of scope, the group code is a marker, or the user cancels entry), the function displays an error message and breaks to the console menu.

When the user selects [D], the ModifyRbSequence() function requests the index of the resbuf-instance to be deleted. The function checks the entered index in the same way as the [M] operation, that is, the function organizes a loop for traversing through resbuf-instances, moves the pointer using the next() method, decrements the index until it is more than one and the pointer is not NULL, and checks the pointer on NULL when the traverse is completed. The function does not traverse the pointer when the index is one and assigns the pointer to the beginning of the sequence. If the pointer refers to the resbuf-instance specified by an index, the function checks whether its group code is a marker using the pointer to the IsMarker() user-defined function obtained as the fourth argument. When the specified resbuf-instance does not contain a marker, the function excludes it from the sequence and deletes it using the assignment to NULL. If the specified index is one, that is, the resbuf-instance is the beginning of the sequence, the function assigns the pointer of the next resbuf-instance to the pointer which refers to the beginning of the sequence using the next() method and excludes the resbuf-instance from the sequence. If the resbuf-instance is placed within the sequence, the function uses two smart pointers to two adjacent resbuf-instances starting with second resbuf-instance in the sequence for traversing. When the index is found, the function assigns the pointer of the next resbuf-instance to the pointer of the previous resbuf-instance excluding the current resbuf-instance from the sequence. When the specified index is out of the scope or the group code is a marker, the function displays an error message and breaks to the console menu. After deleting, the function goes to the [P] operation for displaying the sequence.

When the user selects [C], the ModifyRbSequence() function clears all resbuf-instances of the sequence except specific markers. The function checks whether the sequence is empty before this operation. The function excludes a resbuf-instance from the sequence in the same way as the [D] operation. If the resbuf-instance is a marker, the function remains in the sequence. If the resbuf-instance is ordinary, the function deletes it. The function deletes the resbuf-instance from the beginning of the sequence using the assignment of the pointer of the next resbuf-instance to the pointer of the beginning of the sequence. The function deletes a resbuf-instance from the sequence using the assignment of two adjacent instances in the same way as the [D] operation. After deleting, the function goes to the [P] operation for displaying the sequence.

When the user selects [Q], the function ends the loop and returns to the calling function.

The ModifyRbSequence() function has the following implementation:


void ModifyRbSequence(OdResBufPtr& pData, OdString (*AboutData)(OdResBuf*,bool), 
                      bool (*EntryData)(OdResBuf*,bool), bool (*IsMarker)(OdResBuf*))
{
  wchar_t ch = L'P';
  int idx;
  OdResBufPtr pRb, qRb;

  wcout << L"\nStart modifying of the resbuf-sequence\n";

  do {
    switch(ch)
    {
      case L'C':          // Clear whole tagged data except the specific makers
      case L'c':
        while(!pData.isNull())
        {
          if(IsMarker(pData)) 
          {
            for(qRb = pData, pRb = pData->next() ; !pRb.isNull() ; pRb = pRb->next())
              if(IsMarker(pRb))
                qRb = pRb;
              else
                qRb->setNext(pRb->next());
            break;
          }
          else pData = pData->next();
        }


      case L'P':          // Print all tagged data
      case L'p':
        if(pData.isNull())
          wcout << L"\nResbuf-sequence is empty\n";
        else
        {
          wcout << L"\nResbuf-sequence contains:\n";

          for(idx = 1, pRb = pData ; !pRb.isNull() ; pRb = pRb->next(), idx++)
            wcout << idx << L". " << AboutData(pRb.get(), true) << L"\n";
        }
        break;


      case L'A':          // Add a new tagged data
      case L'a':
        pRb = OdResBuf::newRb();
        if(!EntryData(pRb.get(), true)) pRb = NULL;
        else if(pData.isNull())
               pData = pRb;
             else
               pData->last()->setNext(pRb);
        break;


      case L'I':          // Insert a new tagged data
      case L'i':
        if(pData.isNull())
        {
          wcout << L"\nError: Tagged data can not be inserted in an empty sequence\n";
          break;
        }
        wcout << L"\nSpecify the index to be inserted:>";
        wcin >> idx;

        if(!wcin.fail() && wcin.peek() == 10)
        {
          if(idx > 0)
          {
            for(pRb = pData ; !pRb.isNull() && idx > 1 ; pRb = pRb->next(), idx--);
            if(!pRb.isNull())
            {
              qRb = OdResBuf::newRb();
              if(!EntryData(qRb.get(), true)) qRb = NULL;
              else pRb->insert(qRb);
              break;
            }
          }
          wcout << L"Error: The specified index outs the scope\n";
        }
        else {  wcin.sync();  wcin.clear();  wcout << L"Error: Invalid entered index";  }
        break;


      case L'M':          // Modify the existing tagged data
      case L'm':
        wcout << L"\nSpecify the index to be modified:>";
        wcin >> idx;

        if(!wcin.fail() && wcin.peek() == 10)
        {
          if(idx > 0)
          {
            for(pRb = pData ; !pRb.isNull() && idx > 1 ; pRb = pRb->next(), idx--);
            if(!pRb.isNull())
              if(IsMarker(pRb))
              {
                wcout << L"Error: Group code is the marker that can not be modified\n";
                break;
              }
              else
              {
                wcout << L"Tagged data: " << AboutData(pRb, false) << L"\n";
                EntryData(pRb.get(), (ch == L'M'));
                wcout << L"Tagged data is set to: " << AboutData(pRb.get(), false) << L"\n";
                break;
              }
          }
          wcout << L"Error: The specified index outs the scope\n";
        }
        else {  wcin.sync();  wcin.clear();  wcout << L"Error: Invalid entered index";  }
        break;


      case L'D':          // Delete the existing tagged data
      case L'd':
        wcout << L"\nSpecify the index to be deleted:>";
        wcin >> idx;

        if(!wcin.fail() && wcin.peek() == 10)
        {
          if(idx == 1)
            if(IsMarker(pData))
            {
              wcout << L"Error: Group code is the marker that can not be deleted\n";
              break;
            }
            else
            {
              pRb = pData;
              pData = pData->next();
              pRb = NULL;
              ch = L'P';
              continue;
            }

          if(idx > 0)
          {
            for(qRb = pData, pRb = pData->next() ; !pRb.isNull() && idx > 2 ; 
                qRb = pRb, pRb = pRb->next(), idx--);
         
            if(!pRb.isNull())
              if(IsMarker(pRb))
              {
                wcout << L"Error: Group code is the marker that can not be deleted\n";
                break;
              }
              else
              {
                qRb->setNext(pRb->next());
                pRb = NULL;
                ch = L'P';
                continue;
              }
          }
          wcout << L"Error: The specified index outs the scope\n";
        }
        else {  wcin.sync();  wcin.clear();  wcout << L"Error: Invalid entered index";  }
        break;


      case L'\0':         // Skip an action
        break;

      default:
        wcout << L"Error: Incorrect operation\n";
    }
    wcout << L"\nP. Print all tagged data";
    wcout << L"\nA. Add a new tagged data";
    wcout << L"\nI. Insert new tagged data";
    wcout << L"\nD. Delete the tagged data";
    wcout << L"\nM. Modify the tagged data";
    wcout << L"\nm. Modify only data value";
    wcout << L"\nC. Clear whole tagged data";
    wcout << L"\nQ. Quit";
    wcout << L"\nSelect operation:>";
    wcin >> ch;
  }
  while(ch != L'Q' && ch != L'q');

  wcout << L"\nStop modifying of the resbuf-sequence\n";
}

The DemoBase() function requires a pointer to the database object. The function declares the pData variable of the OdResBufPtr type that is the smart pointer to the current editable sequence of resbuf-instances, creates the testing sequence, initializes this sequence, and calls the ModifyRbSequence() function for modification. The function passes the smart pointer to the sequence as the first argument, pointer to the AboutRbData() function as the second argument, pointer to the EntryRbData() function as the third argument, and pointer to the IsRbMarker() function as the forth argument. The AboutRbData() function requires a pointer to the resbuf-object and returns information about it as a string value. The EntryRbData() function requires a pointer to the resbuf-object and either enters the data type and data value, or only enters the data value for the specified resbuf-instance subject to the value of the second argument. The IsRbMarker() function checks whether the specified resbuf-instance is a specific marker that cannot be modified or deleted when the sequence is being edited.

The DemoBase() function has the following implementation:


#include "..\Common\DemoMain.h"
#include "DemoRb.h"
#include <iostream>
using namespace std;

void DemoBase(OdDbDatabase* pDb)
{
  OdResBufPtr pData;

  pData = OdResBuf::newRb(OdResBuf::kDxfStart, L"SubSequenceOne");
  pData->setNext( OdResBuf::newRb(OdResBuf::kDxfHandle, pDb->getRegAppAcadId()) );
  pData->last()->setNext( OdResBuf::newRb(OdResBuf::kDxfStart, L"SubSequenceTwo") );
  pData->last()->setNext( OdResBuf::newRb(OdResBuf::kDxfAngle, 1.5) );
  pData->last()->setNext( OdResBuf::newRb(OdResBuf::kDxfStart, L"SubSequenceThree") );
  pData->last()->setNext( OdResBuf::newRb(OdResBuf::kDxfBool, false) );

  ModifyRbSequence(pData, AboutRbData, EntryRbData, IsRbMarker);
}

Testing gives the following results:


Start modifying of the resbuf-sequence

Resbuf-sequence contains:
1. [0,String] = "SubSequenceOne"
2. [5,Handle] = 12
3. [0,String] = "SubSequenceTwo"
4. [50,Double] = 1.5
5. [0,String] = "SubSequenceThree"
6. [290,Bool] = false

P. Print all tagged data
A. Add a new tagged data
I. Insert new tagged data
D. Delete the tagged data
M. Modify the tagged data
m. Modify only data value
C. Clear whole tagged data
Q. Quit
Select operation:>

When the operation is D-"Delete tagged data":


Specify the index to be deleted:>6

Resbuf-sequence contains:
1. [0,String] = "SubSequenceOne"
2. [5,Handle] = 12
3. [0,String] = "SubSequenceTwo"
4. [50,Double] = 1.5
5. [0,String] = "SubSequenceThree"

When the operation is D-"Delete tagged data" and the group code is a marker:


Specify the index to be deleted:>5
Error: Group code is the marker that can not be deleted

When the operation is A-"Add new tagged data":


Entry group code [or 0-Quit]:>290
[T]-true or [F]-false:>T

Entry group code [or 0-Quit]:>90
32-bit integer value:>12543678

Entry group code [or 0-Quit]:>300
String:>Text Data

Entry group code [or 0-Quit]:>40
Double value:>12.89

Entry group code [or 0-Quit]:>10
Entry X-coordinate:>3.4
Entry Y-coordinate:>1.2
Entry Z-coordinate:>5.6

When the operation is I-"Insert new tagged data":


Specify the index to be inserted:>4
Entry group code [or 0-Quit]:>280
8-bit integer value:>26

Specify the index to be inserted:>2
Entry group code [or 0-Quit]:>7
String:>Standard

Specify the index to be inserted:>1
Entry group code [or 0-Quit]:>70
16-bit integer value:>26134

When the operation is P-"Print all tagged data":


Resbuf-sequence contains:
1. [0,String] = "SubSequenceOne"
2. [70,Short] = 26134
3. [5,Handle] = 12
4. [7,Name] = "Standard"
5. [0,String] = "SubSequenceTwo"
6. [50,Double] = 1.5
7. [280,Byte] = 1A
8. [0,String] = "SubSequenceThree"
9. [290,Bool] = true
10. [90,Long] = 12543678
11. [300,String] = "Text Data"
12. [40,Double] = 12.89
13. [10,3DPoint] = (3.4,1.2,5.6)

When the operation is M-"Modify tagged data":


Specify the index to be modified:>100
Error: The specified index outs the scope

Specify the index to be modified:>6
Tagged data: [50,Double] = 1.5

Entry group code [or 0-Quit]:>10000
Error: Unknown code

Entry group code [or 0-Quit]:>A1E
Error: Incorrect entered code

Entry group code [or 0-Quit]:>70
16-bit integer value:>1234567
Error: Invalid entered value

Entry group code [or 0-Quit]:>210
Entry X-coordinate:>0.3
Entry Y-coordinate:>0.8
Entry Z-coordinate:>0.1
Tagged data is set to: [210,3DPoint] = (0.3,0.8,0.1)

When the operation is m-"Modify only data value":


Specify the index to be modified:>3
Tagged data: [5,Handle] = 12

Handle:>1F
Tagged data is set to: [5,Handle] = 1F

When the operation is P-"Print all tagged data":


Resbuf-sequence contains:
1. [0,String] = "SubSequenceOne"
2. [70,Short] = 26134
3. [5,Handle] = 1F
4. [7,Name] = "Standard"
5. [0,String] = "SubSequenceTwo"
6. [210,3DPoint] = (0.3,0.8,0.1)
7. [280,Byte] = 1A
8. [0,String] = "SubSequenceThree"
9. [290,Bool] = true
10. [90,Long] = 12543678
11. [300,String] = "Text Data"
12. [40,Double] = 12.89
13. [10,3DPoint] = (3.4,1.2,5.6)

When the operation is C-"Clear whole tagged data":


Resbuf-sequence contains:
1. [0,String] = "SubSequenceOne"
2. [0,String] = "SubSequenceTwo"
3. [0,String] = "SubSequenceThree"

Use the Q-"Quit" operation to exit:


Stop modifying of the resbuf-sequence

See Also

Working with Tagged Data

Example of Entering and Displaying Tagged Data

Copyright © 2002 – 2021. Open Design Alliance. All rights reserved.