public Identifier getTaggedTypeIdentifierInJava(TaggedTypeRef s) {

    Identifier tag = s.getTag();
    if (tag != null) {
      TaggedTypeRef rep = null;
      if (s instanceof Struct) {
        rep = structsByName.get(tag);
      } else if (s instanceof Enum) {
        rep = enumsByName.get(tag);
      }
      if (rep != null) s = rep;
    }

    Identifier name = declarationsConverter.getActualTaggedTypeName(s);
    if (name == null) return null;

    String library = getLibrary(s);
    if (library == null) return null;

    name = name.clone();
    Struct parentStruct = s.findParentOfType(Struct.class);
    if (parentStruct != null && parentStruct != s)
      return ident(getTaggedTypeIdentifierInJava(parentStruct), name);
    else if ((s instanceof Struct)
        && (config.putTopStructsInSeparateFiles || config.runtime == JNAeratorConfig.Runtime.BridJ))
      return ident(getLibraryPackage(library), name);
    else return typeConverter.libMember(getLibraryClassFullName(library), null, name);
  }
  protected void outputConvertedStruct(
      Struct struct,
      Signatures signatures,
      DeclarationsHolder out,
      Identifier callerLibraryClass,
      String callerLibrary,
      boolean onlyFields)
      throws IOException {
    Struct structJavaClass =
        convertStruct(struct, signatures, callerLibraryClass, callerLibrary, onlyFields);
    if (structJavaClass == null) return;

    if (result.config.putTopStructsInSeparateFiles
        && struct.findParentOfType(Struct.class) == null) {
      String library = result.getLibrary(struct);
      Identifier javaPackage = result.getLibraryPackage(library);
      Identifier fullClassName = ident(javaPackage, structJavaClass.getTag().clone());

      if (result.config.runtime == JNAeratorConfig.Runtime.BridJ)
        structJavaClass.addAnnotation(new Annotation(org.bridj.ann.Library.class, expr(library)));
      structJavaClass.removeModifiers(ModifierType.Static);
      structJavaClass =
          result.notifyBeforeWritingClass(fullClassName, structJavaClass, signatures, library);
      if (structJavaClass != null) {
        PrintWriter pout = result.classOutputter.getClassSourceWriter(fullClassName.toString());
        result.printJavaClass(javaPackage, structJavaClass, pout);
        pout.close();
      }
    } else out.addDeclaration(decl(structJavaClass));
  }
  public Identifier getActualTaggedTypeName(TaggedTypeRef struct) {
    Identifier structName = null;
    Identifier tag = struct.getTag();
    if (tag == null || tag.isPlain() && tag.toString().startsWith("_")) {
      TypeDef parentDef = as(struct.getParentElement(), TypeDef.class);
      if (parentDef != null) {
        structName =
            new Identifier.SimpleIdentifier(JNAeratorUtils.findBestPlainStorageName(parentDef));
      } else if (tag != null) {
        String better = tag.toString().substring(1);
        Pair<TypeDef, Declarator> pair = result.typeDefs.get(better);
        if (pair != null
            && pair.getFirst().getValueType() != null
            && pair.getSecond() instanceof DirectDeclarator) {
          TypeRef tr = pair.getFirst().getValueType();
          DirectDeclarator dd = (DirectDeclarator) pair.getSecond();

          if (tr instanceof SimpleTypeRef) {
            if (tag.equals(((SimpleTypeRef) tr).getName())) structName = ident(dd.resolveName());
          } else if (tr instanceof TaggedTypeRef) {
            if (tag.equals(((TaggedTypeRef) tr).getTag())) structName = ident(dd.resolveName());
          }
        }
      }
    }
    if (structName == null || structName.toString().equals("")) structName = tag;
    return structName == null ? null : structName.clone();
  }
 public Identifier getUndefinedType(Identifier libraryToUseIfNotDefinedYet, Identifier name) {
   Identifier lib = findUndefinedType(name);
   if (lib != null) return lib;
   name = getUndefinedTypeName(name);
   Set<String> set = undefinedTypesByLibrary.get(libraryToUseIfNotDefinedYet);
   if (set == null)
     undefinedTypesByLibrary.put(
         libraryToUseIfNotDefinedYet.toString(), set = new HashSet<String>());
   set.add(name.toString());
   Identifier id = ident(libraryToUseIfNotDefinedYet, name);
   resolvedUndefinedTypes.add(id);
   return id;
 }
 public Identifier getFakePointer(Identifier libraryToUseIfNotDefinedYet, Identifier name) {
   Identifier lib = findFakePointer(name);
   if (lib != null) return lib;
   name = getFakePointerName(name);
   Set<String> set = fakePointersByLibrary.get(libraryToUseIfNotDefinedYet);
   if (set == null)
     fakePointersByLibrary.put(
         libraryToUseIfNotDefinedYet.toString(), set = new HashSet<String>());
   set.add(name.toString());
   Identifier id = ident(libraryToUseIfNotDefinedYet, name);
   resolvedFakePointers.add(id);
   return id;
 }
  protected String chooseJavaArgName(String name, int iArg, Set<String> names) {
    Identifier jan = result.typeConverter.getValidJavaArgumentName(ident(name));
    String baseArgName = jan == null ? null : jan.toString();
    int i = 1;
    if (baseArgName == null) baseArgName = "arg";

    String argName;
    do {
      argName = baseArgName + (i == 1 ? "" : i + "");
      i++;
    } while (names.contains(argName) || result.typeConverter.isJavaKeyword(argName));
    names.add(argName);
    return argName;
  }
  public Struct notifyBeforeWritingClass(
      Identifier fullClassName, Struct interf, Signatures signatures, String currentLibrary) {
    for (Class<?> c : overwrittenClassesThatNeedToKeepAllTheirMethods) {
      if (fullClassName.equals(c.getName())) {
        declarationsConverter.addMissingMethods(c, signatures, interf);
        break;
      }
    }

    if (fullClassName.resolveLastSimpleIdentifier().equals("char")) return null;

    // if (fullClassName.equals(NSString.class)) {
    /*
    @Override
    public String toString() {
        return Foundation.toString(id());
    }

    public static NSString getGlobalString(String libraryName, String globalVarName) {
        return Rococoa.wrap(ID.getGlobal(libraryName, globalVarName), NSString.class);
    }

    public static NSString getGlobalString(String globalVarName) {
        return getGlobalString("AppKit", globalVarName);
    }*/
    // }

    String runtimeSpecificHelp =
        config.runtime == JNAeratorConfig.Runtime.BridJ
            ? "or <a href=\"http://bridj.googlecode.com/\">BridJ</a> "
            : ", <a href=\"http://rococoa.dev.java.net/\">Rococoa</a>, "
                + "or <a href=\"http://jna.dev.java.net/\">JNA</a>";
    interf.addToCommentBefore(
        "This file was autogenerated by <a href=\"http://jnaerator.googlecode.com/\">JNAerator</a>, ",
        "a tool written by <a href=\"http://ochafik.com/\">Olivier Chafik</a> that <a href=\"http://code.google.com/p/jnaerator/wiki/CreditsAndLicense\">uses a few opensource projects.</a>.",
        "For help, please visit <a href=\"http://nativelibs4java.googlecode.com/\">NativeLibs4Java</a> "
            + runtimeSpecificHelp
            + ".");

    for (ClassWritingNotifiable n : classWritingNotifiables) {
      interf = n.writingClass(fullClassName, interf, signatures, currentLibrary);
      if (interf == null) return null;
    }
    return interf;
  }
 public Identifier findUndefinedType(Identifier name) {
   name = getUndefinedTypeName(name);
   if (name == null) return null;
   String s = name.toString();
   for (Map.Entry<String, Set<String>> e : undefinedTypesByLibrary.entrySet()) {
     if (e.getValue().contains(s)) return ident(ident(e.getKey()), name);
   }
   return null;
 }
 public Identifier findFakePointer(Identifier name) {
   name = getFakePointerName(name);
   if (name == null) return null;
   String s = name.toString();
   for (Map.Entry<String, Set<String>> e : fakePointersByLibrary.entrySet()) {
     if (e.getValue().contains(s)) return ident(ident(e.getKey()), name);
   }
   return null;
 }
  public void printJavaClass(Identifier javaPackage, Struct javaClass, PrintWriter out) {

    if (javaPackage != null) out.println("package " + javaPackage + ";");

    if (config.noAutoImports) out.println(javaClass);
    else
      Printer.printJava(
          javaPackage,
          ident(javaPackage == null ? null : javaPackage.clone(), javaClass.getTag().clone()),
          javaClass,
          out);
    //		out.println("@SuppressWarnings(\"unused\")");
  }
  public Struct convertCallback(
      FunctionSignature functionSignature, Signatures signatures, Identifier callerLibraryName) {
    Identifier name =
        result.typeConverter.inferCallBackName(functionSignature, true, false, callerLibraryName);
    if (name == null) return null;

    name = result.typeConverter.getValidJavaArgumentName(name);

    Function function = functionSignature.getFunction();

    int i = 1;
    Identifier chosenName = name;
    while (!(signatures.addClass(chosenName))) {
      chosenName = ident(name.toString() + (++i));
    }

    Element parent = functionSignature.getParentElement();
    Element comel = parent != null && parent instanceof TypeDef ? parent : functionSignature;

    Struct callbackStruct = new Struct();
    configureCallbackStruct(callbackStruct);
    // callbackStruct.setParents(Arrays.asList(getCallbackType(functionSignature, chosenName)));
    callbackStruct.setTag(ident(chosenName));
    if (!result.config.noComments)
      callbackStruct.addToCommentBefore(
          comel.getCommentBefore(), comel.getCommentAfter(), getFileCommentContent(comel));
    convertFunction(function, new Signatures(), true, callbackStruct, callerLibraryName, -1);
    for (Declaration d : callbackStruct.getDeclarations()) {
      if (d instanceof Function) {
        callbackStruct.addAnnotations(callbackStruct.getAnnotations());
        callbackStruct.setAnnotations(null);
        break;
      }
    }
    return callbackStruct;
  }
  private Identifier getUndefinedTypeName(Identifier name) {

    String nameStr = name == null ? null : name.toString();
    String trimmed = StringUtils.trimUnderscores(nameStr);
    if (trimmed != null && !nameStr.equals(trimmed)) {
      String nicerName = trimmed;
      Pair<TypeDef, Declarator> pair = typeDefs.get(nicerName);
      if (pair != null) {
        String target = pair.getFirst().getValueType().toString();
        if (target.equals(nameStr)) // || target.equals(nameStr+"*"))
        name = ident(nameStr = nicerName);
      }
    }
    return name;
  }
  public void convertFunction(
      Function function,
      Signatures signatures,
      boolean isCallback,
      final DeclarationsHolder out,
      final Identifier libraryClassName,
      int iConstructor) {
    if (result.config.functionsAccepter != null && !result.config.functionsAccepter.adapt(function))
      return;

    // if (function.findParentOfType(Template))
    String library = result.getLibrary(function);
    Identifier functionName = function.getName();
    boolean isMethod = function.getParentElement() instanceof Struct;
    if (functionName == null || isCallback) {
      if (function.getParentElement() instanceof FunctionSignature)
        functionName = ident(result.config.callbackInvokeMethodName);
      else return;
    }
    if (function.getParentElement() instanceof FriendDeclaration) return;

    String n = functionName.toString();
    if (n.contains("<") || n.startsWith("~")) return;

    if (result.config.beautifyNames) functionName = ident(result.typeConverter.beautify(n, false));

    functionName = result.typeConverter.getValidJavaMethodName(functionName);
    if (functionName == null) return;

    // if (functionName.equals("operator"))
    //    functionName

    String sig = function.computeSignature(SignatureType.JavaStyle);

    DeclarationsHolder objOut =
        result.config.reification && !isCallback && !isMethod
            ? new DeclarationsHolder() {

              @Override
              public void addDeclaration(Declaration d) {
                out.addDeclaration(d);
                if (d instanceof Function) {
                  Function f = (Function) d;
                  List<Arg> args = f.getArgs();
                  List<TypeRef> trs = new ArrayList<TypeRef>(2);
                  trs.add(f.getValueType());
                  if (!args.isEmpty()) trs.add(args.get(0).getValueType());

                  for (TypeRef tr : trs) {
                    if (tr instanceof SimpleTypeRef) {
                      Identifier id = ((SimpleTypeRef) tr).getName();
                      if (result.isFakePointer(id)) {
                        result.addFunctionReifiableInFakePointer(id, libraryClassName, f);
                      }
                    }
                  }
                }
              }

              @Override
              public List<Declaration> getDeclarations() {
                return out.getDeclarations();
              }
            }
            : out;

    try {
      convertFunction(
          function,
          signatures,
          isCallback,
          objOut,
          libraryClassName,
          sig,
          functionName,
          library,
          iConstructor);
    } catch (UnsupportedConversionException ex) {
      Declaration d = skipDeclaration(function);
      if (d != null) {
        d.addToCommentBefore(ex.toString());
        out.addDeclaration(d);
      }
    }
  }
 public Struct getObjcCClassOrProtocol(Identifier name) {
   Struct s = getMap(classes, Type.ObjCClass).get(name);
   if (s == null) s = getMap(classes, Type.ObjCProtocol).get(name);
   if (s == null) s = objCCategoriesByName.get(name.toString());
   return s;
 }