private static final void dumpEntryHeader(OMMEntry entry, PrintStream ps, int tabLevel) {
   dumpIndent(ps, tabLevel);
   ps.print(OMMTypes.toString(entry.getType()));
   ps.print(": ");
   if (entry.getType() == OMMTypes.SERIES_ENTRY) ps.println();
   // else array entry value is on same line
 }
 private static final void dumpElementEntryHeader(
     OMMElementEntry entry, PrintStream ps, int tabLevel) {
   dumpIndent(ps, tabLevel);
   ps.print(OMMTypes.toString(entry.getType()));
   ps.print(" ");
   ps.print(entry.getName());
   ps.print(": ");
   if ((entry.getDataType() >= OMMTypes.BASE_FORMAT) || (entry.getDataType() == OMMTypes.ARRAY))
     ps.println();
 }
  /** parse msg and print it in a table-nested format to the provided PrintStream */
  public static final void parseDataDefinition(
      OMMDataDefs datadefs, short dbtype, PrintStream ps, int tabLevel) {
    DataDefDictionary listDefDb = DataDefDictionary.create(dbtype);
    DataDefDictionary.decodeOMMDataDefs(listDefDb, datadefs);

    ps.print("DATA_DEFINITIONS ");
    for (Iterator listDefDbIter = listDefDb.iterator(); listDefDbIter.hasNext(); ) {
      DataDef listdef = (DataDef) listDefDbIter.next();

      ps.print("Count: ");
      ps.print(listdef.getCount());
      ps.print(" DefId: ");
      ps.println(listdef.getDataDefId());

      if (dbtype == OMMTypes.ELEMENT_LIST_DEF_DB) {
        for (Iterator listdefIter = listdef.iterator(); listdefIter.hasNext(); ) {
          ElementEntryDef ommEntry = (ElementEntryDef) listdefIter.next();
          dumpIndent(ps, tabLevel + 1);
          ps.print("ELEMENT_ENTRY_DEF ");
          ps.print("Name: ");
          ps.print(ommEntry.getName());
          ps.print(" Type: ");
          ps.println(OMMTypes.toString(ommEntry.getDataType()));
        }
      } else {
        for (Iterator listdefIter = listdef.iterator(); listdefIter.hasNext(); ) {
          FieldEntryDef ommEntry = (FieldEntryDef) listdefIter.next();
          dumpIndent(ps, tabLevel + 1);
          ps.print("FIELD_ENTRY_DEF ");
          ps.print("FID: ");
          ps.print(ommEntry.getFieldId());
          ps.print(" Type: ");
          ps.println(OMMTypes.toString(ommEntry.getDataType()));
        }
      }
    }
  }
  private static final void dumpVectorEntryHeader(
      OMMVectorEntry entry, PrintStream ps, int tabLevel) {
    dumpIndent(ps, tabLevel);
    ps.print(OMMTypes.toString(entry.getType()));
    ps.print(" ");
    ps.print(entry.getPosition());
    ps.print(" (");
    ps.print(OMMVectorEntry.Action.vectorActionString(entry.getAction()));
    if (entry.has(OMMVectorEntry.HAS_PERMISSION_DATA)) ps.print(", HasPermissionData");
    ps.println(") : ");

    String flagsString = ExampleUtil.vectorEntryFlagsString(entry);
    dumpIndent(ps, tabLevel);
    ps.print("flags: ");
    ps.println(flagsString);
  }
 private static final void dumpFieldEntryHeader(
     OMMFieldEntry entry, FidDef def, PrintStream ps, int tabLevel) {
   dumpIndent(ps, tabLevel);
   ps.print(OMMTypes.toString(entry.getType()));
   ps.print(" ");
   ps.print(entry.getFieldId());
   if (def == null) {
     ps.print(": ");
   } else {
     ps.print("/");
     ps.print(def.getName());
     ps.print(": ");
     if ((def.getOMMType() >= OMMTypes.BASE_FORMAT) || (def.getOMMType() == OMMTypes.ARRAY))
       ps.println();
   }
 }
  private static final void dumpFilterEntryHeader(
      OMMFilterEntry entry, PrintStream ps, int tabLevel) {
    dumpIndent(ps, tabLevel);
    ps.print(OMMTypes.toString(entry.getType()));
    ps.print(" ");
    ps.print(entry.getFilterId());
    ps.print(" (");
    ps.print(OMMFilterEntry.Action.toString(entry.getAction()));
    if (entry.has(OMMFilterEntry.HAS_PERMISSION_DATA)) ps.print(", HasPermissionData");
    if (entry.has(OMMFilterEntry.HAS_DATA_FORMAT)) ps.print(", HasDataFormat");
    ps.println(") : ");

    String flagsString = ExampleUtil.filterEntryFlagsString(entry);
    dumpIndent(ps, tabLevel);
    ps.print("flags: ");
    ps.println(flagsString);
  }
  private static final void dumpMapEntryHeader(OMMMapEntry entry, PrintStream ps, int tabLevel) {
    dumpIndent(ps, tabLevel);
    ps.print(OMMTypes.toString(entry.getType()));
    ps.print(" (");
    ps.print(OMMMapEntry.Action.toString(entry.getAction()));
    if (entry.has(OMMMapEntry.HAS_PERMISSION_DATA)) ps.print(", HasPermissionData");
    ps.println(") : ");

    String flagsString = ExampleUtil.mapEntryFlagsString(entry);
    dumpIndent(ps, tabLevel);
    ps.print("flags: ");
    ps.println(flagsString);

    dumpIndent(ps, tabLevel);
    ps.print("Key: ");
    parseData(entry.getKey(), ps, 0);
    dumpIndent(ps, tabLevel);
    ps.println("Value: ");
  }
  private static final void parseAggregateHeader(OMMData data, PrintStream ps, int tabLevel) {
    dumpIndent(ps, tabLevel);
    short dataType = data.getType();
    ps.println(OMMTypes.toString(dataType));
    switch (dataType) {
      case OMMTypes.FIELD_LIST:
        {
          // set DICTIONARY to the dictId for this field list
          OMMFieldList fieldList = (OMMFieldList) data;
          int dictId = fieldList.getDictId();
          CURRENT_DICTIONARY = getDictionary(dictId);
        }
        break;
      case OMMTypes.SERIES:
        {
          OMMSeries s = (OMMSeries) data;
          if (s.has(OMMSeries.HAS_SUMMARY_DATA)) {
            dumpIndent(ps, tabLevel + 1);
            ps.println("SUMMARY");
            parseData(s.getSummaryData(), ps, tabLevel + 1);
          }
          if (s.has(OMMSeries.HAS_DATA_DEFINITIONS)) {
            dumpIndent(ps, tabLevel + 1);
            short dbtype =
                s.getDataType() == OMMTypes.FIELD_LIST
                    ? OMMTypes.FIELD_LIST_DEF_DB
                    : OMMTypes.ELEMENT_LIST_DEF_DB;
            parseDataDefinition(s.getDataDefs(), dbtype, ps, tabLevel + 1);
          }
        }
        break;
      case OMMTypes.MAP:
        {
          OMMMap s = (OMMMap) data;

          String flagsString = ExampleUtil.mapFlagsString(s);
          dumpIndent(ps, tabLevel);
          ps.print("flags: ");
          ps.println(flagsString);

          if (s.has(OMMMap.HAS_SUMMARY_DATA)) {
            dumpIndent(ps, tabLevel + 1);
            ps.println("SUMMARY");
            parseData(s.getSummaryData(), ps, tabLevel + 1);
          }
        }
        break;
      case OMMTypes.VECTOR:
        {
          OMMVector s = (OMMVector) data;

          String flagsString = ExampleUtil.vectorFlagsString(s);
          dumpIndent(ps, tabLevel);
          ps.print("flags: ");
          ps.println(flagsString);

          if (s.has(OMMVector.HAS_SUMMARY_DATA)) {
            dumpIndent(ps, tabLevel + 1);
            ps.println("SUMMARY");
            parseData(s.getSummaryData(), ps, tabLevel + 1);
          }
        }
        break;
      case OMMTypes.FILTER_LIST:
        {
          OMMFilterList s = (OMMFilterList) data;

          String flagsString = ExampleUtil.filterListFlagsString(s);
          dumpIndent(ps, tabLevel);
          ps.print("flags: ");
          ps.println(flagsString);
        }
        break;
    }
  }
  /** 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));
      }
    }
  }