private static void renderExpression(
      final BinExport2 proto,
      final BinExport2.Operand operand,
      int index,
      ImmutableMap<Integer, String> operandComments,
      final StringBuilder output) {
    // Note: Keep this code in sync with the versions in binexport/instruction.cc and
    //       binexport/tools/binexport2dump.cc.
    final int expressionIndex = operand.getExpressionIndex(index);
    final BinExport2.Expression expression = proto.getExpression(expressionIndex);
    final String expressionSymbol =
        operandComments.containsKey(index) ? operandComments.get(index) : expression.getSymbol();
    final boolean longMode = proto.getMetaInformation().getArchitectureName().endsWith("64");
    switch (expression.getType()) {
      case OPERATOR:
        {
          List<Integer> children = new ArrayList<>(4 /* Default maximum on x86 */);
          for (int i = index + 1;
              i < operand.getExpressionIndexCount()
                  && proto.getExpression(operand.getExpressionIndex(i)).getParentIndex()
                      == operand.getExpressionIndex(index);
              i++) {
            children.add(i);
          }
          int numChildren = children.size();
          if ("{".equals(expressionSymbol)) { // ARM Register lists
            output.append("{");
            for (int i = 0; i < numChildren; i++) {
              renderExpression(proto, operand, children.get(i), operandComments, output);
              if (i != numChildren - 1) {
                output.append(highlightChar(EInstructionHighlighting.TYPE_NEWOPERAND_COMMA));
                output.append(",");
              }
            }
            output.append("}");
          } else if (numChildren == 1) {
            // Only a single child, treat expression as prefix operator (like 'ss:').
            output.append(highlightChar(EInstructionHighlighting.TYPE_OPERATOR));
            output.append(expressionSymbol);
            renderExpression(proto, operand, children.get(0), operandComments, output);
          } else if (numChildren > 1) {
            // Multiple children, treat expression as infix operator ('+' or '*').
            for (int i = 0; i < numChildren; i++) {
              renderExpression(proto, operand, children.get(i), operandComments, output);
              if (i != numChildren - 1) {
                final BinExport2.Expression childExpression =
                    proto.getExpression(operand.getExpressionIndex(children.get(i + 1)));
                final BinExport2.Expression.Type childType = childExpression.getType();
                if ("+".equals(expressionSymbol)
                    && (childType == Expression.Type.IMMEDIATE_INT
                        || childType == Expression.Type.IMMEDIATE_FLOAT)) {
                  final long childImmediate =
                      longMode
                          ? childExpression.getImmediate()
                          : (int) childExpression.getImmediate();
                  if (childImmediate < 0 && childExpression.getSymbol().isEmpty()) {
                    continue; // Don't render anything or we'll get: eax+-12
                  }
                  if (childImmediate == 0) {
                    i++; // Skip "+0"
                    continue;
                  }
                }
                output.append(expressionSymbol);
              }
            }
          }
          break;
        }
      case SYMBOL:
        output.append(highlightChar(EInstructionHighlighting.TYPE_SYMBOL));
        output.append(expressionSymbol);
        break;
      case REGISTER:
        output.append(highlightChar(EInstructionHighlighting.TYPE_REGISTER));
        output.append(expressionSymbol);
        break;
      case SIZE_PREFIX:
        if ((longMode && !"b8".equals(expressionSymbol))
            || (!longMode && !"b4".equals(expressionSymbol))) {
          output.append(highlightChar(EInstructionHighlighting.TYPE_SIZEPREFIX));
          output.append(expressionSymbol);
          output.append(" ");
        }
        renderExpression(proto, operand, index + 1, operandComments, output);
        break;
      case DEREFERENCE:
        output.append(highlightChar(EInstructionHighlighting.TYPE_DEREFERENCE));
        output.append("[");
        if (index + 1 < operand.getExpressionIndexCount()) {
          renderExpression(proto, operand, index + 1, operandComments, output);
        }
        output.append(highlightChar(EInstructionHighlighting.TYPE_DEREFERENCE));
        output.append("]");
        break;
      case IMMEDIATE_INT:
      case IMMEDIATE_FLOAT:
        if (expressionSymbol.isEmpty()) {
          final long expressionImmediate =
              longMode ? expression.getImmediate() : (int) expression.getImmediate();
          output.append(highlightChar(EInstructionHighlighting.TYPE_IMMEDIATE));
          if (expressionImmediate <= 9) {
            output.append(String.format("%d", expressionImmediate));
          } else {
            output.append(String.format("0x%X", expressionImmediate));
          }
        } else {
          output.append(highlightChar(EInstructionHighlighting.TYPE_SYMBOL));
          output.append(expressionSymbol);
        }
        break;
      default:
        throw new IllegalStateException("Invalid expression type");
    }
  }
Reads data from BinExport2 files and renders disassemblies.
java/ui/src/main/java/com/google/security/zynamics/bindiff/io/BinExport2Reader.java