Multi-Project Commit: Move of filterfw out of system/media (2 of 7)

This is part of the multi-project commit to move the filter-framework
from system/media/mca to frameworks/base/media/mca.

Note that the filter-framework will soon be replaced with a refactored
version currently under API review (also to go under frameworks/base).
This move is done now to unblock the PDK efforts.

Change-Id: I9f42be5a12a9e8157512be11f04e38e4548970be
diff --git a/media/mca/structgen.py b/media/mca/structgen.py
new file mode 100644
index 0000000..437326c
--- /dev/null
+++ b/media/mca/structgen.py
@@ -0,0 +1,367 @@
+#!/usr/bin/env python
+
+#
+# Copyright (C) 2011 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+import os
+import sys
+
+hFileTemplate = """/**
+ * This file is auto-generated by platform/system/media/mca/structgen.py! Do NOT modify!
+ **/
+
+#ifndef %s
+#define %s
+
+%s
+
+#endif // %s
+"""
+
+jniFileTemplate = """/**
+ * This file is auto-generated by platform/system/media/mca/structgen.py! Do NOT modify!
+ **/
+
+#include <stdint.h>
+#include "native/%s.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "jni.h"
+
+// Helper functions ////////////////////////////////////////////////////////////////////////////////
+%s* Get%sAtIndex(JNIEnv* env, jobject buffer, int index) {
+  jclass base_class = (*env)->FindClass(env, "android/filterfw/core/NativeBuffer");
+  jfieldID ptr_field = (*env)->GetFieldID(env, base_class, "mDataPointer", "J");
+  uintptr_t data_ptr = (*env)->GetLongField(env, buffer, ptr_field);
+  %s* array = (%s*)data_ptr;
+  (*env)->DeleteLocalRef(env, base_class);
+  return &array[index];
+}
+
+// Declarations ////////////////////////////////////////////////////////////////////////////////////
+JNIEXPORT jint JNICALL
+Java_%s_getElementSize(JNIEnv* env, jobject thiz);
+
+%s
+
+#ifdef __cplusplus
+}
+#endif
+
+// Implementation //////////////////////////////////////////////////////////////////////////////////
+jint Java_%s_getElementSize(JNIEnv* env, jobject thiz) {
+  return sizeof(%s);
+}
+
+%s
+"""
+
+javaFileTemplate = """/**
+ * This file is auto-generated by platform/system/media/mca/structgen.py! Do NOT modify!
+ **/
+
+package %s;
+
+import android.filterfw.core.NativeBuffer;
+
+%s
+"""
+
+
+def ToJavaName(cname, start_upper_at = 1):
+  lower = cname.split("_")
+  upper = [c.title() for c in lower]
+  return "".join(lower[:start_upper_at] + upper[start_upper_at:])
+
+def ToJNIPackage(package, jclassname):
+  return "%s_%s" % (package.replace(".", "_"), jclassname)
+
+def ToMacroDefName(cname, pname):
+  return "%s_%s" % (pname.replace(".", "_").upper(), cname.upper())
+
+class ParseError:
+  def __init__(self, lineno, message):
+    self.lineno = lineno
+    self.message = message
+
+  def __str__(self):
+    return "On line %d: %s" % (self.lineno, self.message)
+
+class FieldType_BasePOD:
+  def __init__(self, name, structname, jclassname, package, javatype, ctype, jtype, defval):
+    self.name = name
+    self.structname = structname
+    self.jclassname = jclassname
+    self.package = package
+    self.javatype = javatype
+    self.ctype = ctype
+    self.jtype = jtype
+    self.defval = defval
+
+  def cString(self):
+    return "  %s %s;" % (self.ctype, self.name)
+
+  def javaGetter(self):
+    return "    public %s get%s(int index) {\n"\
+           "        assertReadable();\n"\
+           "        return nativeGet%s(index);\n"\
+           "    }" % (self.javatype, ToJavaName(self.name, 0), ToJavaName(self.name, 0))
+
+  def javaSetter(self):
+    return "    public void set%s(int index, %s value) {\n"\
+           "        assertWritable();\n"\
+           "        nativeSet%s(index, value);\n"\
+           "    }" % (ToJavaName(self.name, 0), self.javatype, ToJavaName(self.name, 0))
+
+  def javaNativeGetter(self):
+    return "    private native %s nativeGet%s(int index);"\
+           % (self.javatype, ToJavaName(self.name, 0))
+
+  def javaNativeSetter(self):
+    return "    private native boolean nativeSet%s(int index, %s value);"\
+           % (ToJavaName(self.name, 0), self.javatype)
+
+  def jniGetterDefString(self):
+    return "JNIEXPORT %s JNICALL\n" \
+           "Java_%s_nativeGet%s(JNIEnv* env, jobject thiz, jint index);" \
+           % (self.jtype, ToJNIPackage(self.package, self.jclassname), ToJavaName(self.name, 0))
+
+  def jniGetterImplString(self):
+    return \
+      "%s Java_%s_nativeGet%s(JNIEnv* env, jobject thiz, jint index) {\n"\
+      "  %s* instance = Get%sAtIndex(env, thiz, index);\n"\
+      "  return instance ? instance->%s : %s;\n"\
+      "}\n" % (self.jtype, ToJNIPackage(self.package, self.jclassname), ToJavaName(self.name, 0),\
+               self.structname, self.structname, self.name, self.defval)
+
+  def jniSetterDefString(self):
+    return "JNIEXPORT jboolean JNICALL\n" \
+           "Java_%s_nativeSet%s(JNIEnv* env, jobject thiz, jint index, %s value);" \
+           % (ToJNIPackage(self.package, self.jclassname), ToJavaName(self.name, 0), self.jtype)
+
+  def jniSetterImplString(self):
+    return \
+      "jboolean Java_%s_nativeSet%s(JNIEnv* env, jobject thiz, jint index, %s value) {\n"\
+      "  %s* instance = Get%sAtIndex(env, thiz, index);\n"\
+      "  if (instance) {\n"\
+      "    instance->%s = value;\n"\
+      "    return JNI_TRUE;\n"\
+      "  }\n"\
+      "  return JNI_FALSE;\n"\
+      "}\n" % (ToJNIPackage(self.package, self.jclassname), ToJavaName(self.name, 0),\
+               self.jtype, self.structname, self.structname, self.name)
+
+class FieldType_Float(FieldType_BasePOD):
+  def __init__(self, name, structname, jclassname, package):
+    FieldType_BasePOD.__init__(self, name, structname, jclassname, package, "float", "float", "jfloat", "0.0")
+
+class FieldType_Int(FieldType_BasePOD):
+  def __init__(self, name, structname, jclassname, package):
+    FieldType_BasePOD.__init__(self, name, structname, jclassname, package, "int", "int", "jint", "0")
+
+class FieldType_Long(FieldType_BasePOD):
+  def __init__(self, name, structname, jclassname, package):
+    FieldType_BasePOD.__init__(self, name, structname, jclassname, package, "long", "long long", "jlong", "0")
+
+class StructSpec:
+
+  def parseTextFile(self, filepath):
+    # Init
+    self.name = None
+    self.package = None
+    self.fields = []
+    self.structname = None
+    self.jclassname = None
+    self.libname = None
+
+    # Open the file
+    txtfile = open(filepath)
+
+    # Parse it line by line
+    lineno = 0
+    for line in txtfile:
+      # Split line into components
+      linecomps = line.split()
+      if len(linecomps) == 0:
+        continue
+
+      # Execute command
+      cmd = linecomps[0]
+      if cmd == "@name":
+        self.commandArgAssert(linecomps, 1, lineno)
+        self.name = linecomps[1]
+        if not self.structname:
+          self.structname = self.name
+        if not self.jclassname:
+          self.jclassname = self.name
+      elif cmd == "@package":
+        self.commandArgAssert(linecomps, 1, lineno)
+        self.package = linecomps[1]
+      elif cmd == "@libname":
+        self.commandArgAssert(linecomps, 1, lineno)
+        self.libname = linecomps[1]
+      elif cmd == "@structname":
+        self.commandArgAssert(linecomps, 1, lineno)
+        self.structname = linecomps[1]
+      elif cmd == "@javaclassname":
+        self.commandArgAssert(linecomps, 1, lineno)
+        self.jclassname = linecomps[1]
+      elif cmd == "@field":
+        self.commandArgAssert(linecomps, 2, lineno)
+        typestr = linecomps[1]
+        if typestr == "int":
+          fieldtype = FieldType_Int(linecomps[2], self.structname, self.jclassname, self.package)
+        elif typestr == "long":
+          fieldtype = FieldType_Long(linecomps[2], self.structname, self.jclassname, self.package)
+        elif typestr == "float":
+          fieldtype = FieldType_Float(linecomps[2], self.structname, self.jclassname, self.package)
+        else:
+          raise ParseError(lineno, "Unknown field type '%s'!" % typestr)
+        self.fields.append(fieldtype)
+      else:
+        raise ParseError(lineno, "Unknown command: '%s'!" % cmd)
+
+      lineno = lineno + 1
+
+    # Make sure we have all required info
+    if not self.name:
+      raise ParseError(lineno, "Required field '@name' missing!")
+    elif not self.package:
+      raise ParseError(lineno, "Required field '@package' missing!")
+    elif not self.libname:
+      raise ParseError(lineno, "Required field '@libname' missing!")
+
+    # Normalize values
+    if self.libname[:3] == "lib":
+      self.libname = self.libname[3:]
+
+  def commandArgAssert(self, linecomps, expectedcount, lineno):
+    foundcount = len(linecomps) - 1
+    if foundcount < expectedcount:
+      raise ParseError(lineno, "Not enough arguments specifed for command '%s'! Expected %d, " \
+                       "but got only %d!" % (linecomps[0], expectedcount, foundcount))
+    elif foundcount > expectedcount + 1:
+      raise ParseError(lineno, "Too many arguments specifed for command '%s'! Expected %d, " \
+                       "but got %d!" % (linecomps[0], expectedcount, foundcount))
+
+
+  def cStructString(self):
+    cfields = [f.cString() for f in self.fields]
+    return "typedef struct Struct%s {\n%s\n} %s;\n" % (self.structname,\
+                                                       "\n".join(cfields),\
+                                                       self.structname)
+
+  def javaClassString(self):
+    jgetters = [f.javaGetter() for f in self.fields]
+    jsetters = [f.javaSetter() for f in self.fields]
+    jnativesetters = [f.javaNativeSetter() for f in self.fields]
+    jnativegetters = [f.javaNativeGetter() for f in self.fields]
+    return "public class %s extends NativeBuffer {\n\n"\
+           "    public %s() {\n"\
+           "        super();\n"\
+           "    }\n"\
+           "\n"\
+           "    public %s(int count) {\n"\
+           "        super(count);\n"\
+           "    }\n"\
+           "\n"\
+           "    public native int getElementSize();\n"\
+           "\n"\
+           "%s\n\n"\
+           "%s\n\n"\
+           "%s\n\n"\
+           "%s\n\n"\
+           "    static {\n"\
+           "        System.loadLibrary(\"%s\");\n"\
+           "    }\n"\
+           "\n"\
+           "};\n" % (self.jclassname,\
+                     self.jclassname,\
+                     self.jclassname,\
+                     "\n\n".join(jgetters),\
+                     "\n\n".join(jsetters),\
+                     "\n\n".join(jnativegetters),\
+                     "\n\n".join(jnativesetters),\
+                     self.libname)
+
+  def jniDeclString(self):
+    jnigetters = [f.jniGetterDefString() for f in self.fields]
+    jnisetters = [f.jniSetterDefString() for f in self.fields]
+    return "\n\n".join(jnigetters + jnisetters)
+
+  def jniImplString(self):
+    jnigetters = [f.jniGetterImplString() for f in self.fields]
+    jnisetters = [f.jniSetterImplString() for f in self.fields]
+    return "\n\n".join(jnigetters + jnisetters)
+
+  def hFileString(self):
+    defname = ToMacroDefName(self.structname, self.package)
+    return hFileTemplate % (defname, defname, self.cStructString(), defname)
+
+  def javaFileString(self):
+    return javaFileTemplate % (self.package, self.javaClassString())
+
+  def jniFileString(self):
+    return jniFileTemplate % (self.structname.lower(),\
+                              self.structname,\
+                              self.structname,\
+                              self.structname,\
+                              self.structname,\
+                              ToJNIPackage(self.package, self.jclassname),\
+                              self.jniDeclString(),\
+                              ToJNIPackage(self.package, self.jclassname),\
+                              self.structname,
+                              self.jniImplString())
+
+def main(argv):
+  if len(argv) != 2:
+    print("Usage: %s <file.struct>" % argv[0])
+    return -1
+
+  filepath = argv[1]
+
+  structspec = StructSpec()
+  structspec.parseTextFile(filepath)
+
+  hfilename = "%s.h" % structspec.structname.lower()
+  javafilename = "%s.java" % structspec.jclassname
+  jnifilename = "jni_%s.c" % structspec.structname.lower()
+
+  javapackagepath = structspec.package.replace('.','/')
+
+  rootdir = os.path.dirname(filepath)
+  hfilepath = "%s/../native/%s" % (rootdir, hfilename)
+  javafilepath = "%s/../java/%s/%s" % (rootdir, javapackagepath, javafilename)
+  jnifilepath = "%s/../jni/%s" % (rootdir, jnifilename)
+
+  hfile = open(hfilepath, 'w')
+  hfile.write(structspec.hFileString())
+  hfile.close()
+
+  javafile = open(javafilepath, 'w')
+  javafile.write(structspec.javaFileString())
+  javafile.close()
+
+  jnifile = open(jnifilepath, 'w')
+  jnifile.write(structspec.jniFileString())
+  jnifile.close()
+
+
+if __name__ == "__main__":
+  sys.exit(main(sys.argv))