private static void mapLines(
     TextBuffer code,
     StructLineNumberTableAttribute table,
     BytecodeMappingTracer tracer,
     int startLine) {
   // build line start offsets map
   HashMap<Integer, Set<Integer>> lineStartOffsets = new HashMap<Integer, Set<Integer>>();
   for (Map.Entry<Integer, Integer> entry : tracer.getMapping().entrySet()) {
     Integer lineNumber = entry.getValue() - startLine;
     Set<Integer> curr = lineStartOffsets.get(lineNumber);
     if (curr == null) {
       curr = new TreeSet<Integer>(); // requires natural sorting!
     }
     curr.add(entry.getKey());
     lineStartOffsets.put(lineNumber, curr);
   }
   String lineSeparator = DecompilerContext.getNewLineSeparator();
   StringBuilder text = code.getOriginalText();
   int pos = text.indexOf(lineSeparator);
   int lineNumber = 0;
   while (pos != -1) {
     Set<Integer> startOffsets = lineStartOffsets.get(lineNumber);
     if (startOffsets != null) {
       for (Integer offset : startOffsets) {
         int number = table.findLineNumber(offset);
         if (number >= 0) {
           code.setLineMapping(number, pos);
           break;
         }
       }
     }
     pos = text.indexOf(lineSeparator, pos + 1);
     lineNumber++;
   }
 }
  public static String toValidJavaIdentifier(String name) {
    if (name == null || name.isEmpty()) return name;

    boolean changed = false;
    StringBuilder res = new StringBuilder(name.length());
    for (int i = 0; i < name.length(); i++) {
      char c = name.charAt(i);
      if ((i == 0 && !Character.isJavaIdentifierStart(c))
          || (i > 0 && !Character.isJavaIdentifierPart(c))) {
        changed = true;
        res.append("_");
      } else res.append(c);
    }
    if (!changed) {
      return name;
    }
    return res.append("/* $FF was: ").append(name).append("*/").toString();
  }