/** parse data and print it in a table-nested format to the provided PrintStream */
  public static final void parseData(OMMData data, PrintStream ps, int tabLevel) {
    if (data.isBlank()) dumpBlank(ps);
    else if (OMMTypes.isAggregate(data.getType())) parseAggregate(data, ps, tabLevel + 1);
    else if ((data.getType() == OMMTypes.RMTES_STRING)
        && ((OMMDataBuffer) data).hasPartialUpdates()) {
      Iterator iter = ((OMMDataBuffer) data).partialUpdateIterator();
      while (true) {
        OMMDataBuffer partial = (OMMDataBuffer) iter.next();
        ps.print("hpos: ");
        ps.print(partial.horizontalPosition());
        ps.print(", ");
        ps.print(partial.toString());
        if (iter.hasNext()) ps.print("  |  ");
        else break;
      }
      ps.println();
    } else if (data.getType() == OMMTypes.ANSI_PAGE) {
      // process ANSI with com.reuters.rfa.ansipage
      parseAnsiPageData(data, ps, tabLevel);
    } else if (data.getType() == OMMTypes.BUFFER || data.getType() == OMMTypes.OPAQUE_BUFFER) {
      if (data.getEncodedLength() <= 20) {
        dumpIndent(ps, tabLevel + 1);
        // for small strings, print hex and try to print ASCII
        ps.print(HexDump.toHexString(((OMMDataBuffer) data).getBytes(), false));
        ps.print(" | ");
        ps.println(data);
      } else {
        if (INTERNAL_DEBUG) {
          ps.println("Hex Format and Data Bytes: ");
          ps.println(HexDump.hexDump(((OMMDataBuffer) data).getBytes(), 50));

          ps.println("Hex Format: ");
        }

        int lineSize = 32;
        String s = HexDump.toHexString(((OMMDataBuffer) data).getBytes(), false);

        int j = 0;
        while (j < s.length()) {
          if (j != 0) ps.println();

          dumpIndent(ps, 1);

          int end = j + lineSize;
          if (end >= s.length()) end = s.length();

          for (int i = j; i < end; i++) {
            ps.print(s.charAt(i));
          }
          j = j + lineSize;
        }

        ps.println("\nData Bytes: ");
        dumpIndent(ps, 1);
        ps.println(data);
      }
    } else if (data.getType() == OMMTypes.MSG) {
      parseMsg((OMMMsg) data, ps, tabLevel + 1);
    } else {
      try {
        ps.println(data);
      } catch (Exception e) {
        byte[] rawdata = data.getBytes();
        ps.println(HexDump.hexDump(rawdata));
      }
    }
  }