1 /*
2  * Copyright (C) 2011 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.ide.eclipse.gltrace.format;
18 
19 import java.io.BufferedReader;
20 import java.io.IOException;
21 import java.io.InputStream;
22 import java.io.InputStreamReader;
23 import java.util.ArrayList;
24 import java.util.Arrays;
25 import java.util.HashMap;
26 import java.util.List;
27 import java.util.Map;
28 
29 /**
30  * Model a single GL API function call's specification.
31  */
32 public class GLAPISpec {
33     private static final String GL_SPECS_FILE = "/entries.in"; //$NON-NLS-1$
34     private static final String GLES2_ENTRIES_HEADER_V1 =
35             "# com.android.ide.eclipse.gltrace.glentries, v1"; //$NON-NLS-1$
36     private static Map<String, GLAPISpec> sApiSpecs;
37 
38     private final String mGLFunction;
39     private final GLDataTypeSpec mReturnType;
40     private final List<GLDataTypeSpec> mArgs;
41 
GLAPISpec(String glFunction, GLDataTypeSpec returnType, List<GLDataTypeSpec> args)42     private GLAPISpec(String glFunction, GLDataTypeSpec returnType, List<GLDataTypeSpec> args) {
43         mGLFunction = glFunction;
44         mReturnType = returnType;
45         mArgs = args;
46     }
47 
getFunction()48     public String getFunction() {
49         return mGLFunction;
50     }
51 
getReturnValue()52     public GLDataTypeSpec getReturnValue() {
53         return mReturnType;
54     }
55 
getArgs()56     public List<GLDataTypeSpec> getArgs() {
57         return mArgs;
58     }
59 
getSpecs()60     public static Map<String, GLAPISpec> getSpecs() {
61         if (sApiSpecs == null) {
62             sApiSpecs = parseApiSpecs(GLAPISpec.class.getResourceAsStream(GL_SPECS_FILE));
63         }
64 
65         return sApiSpecs;
66     }
67 
parseApiSpecs(InputStream specFile)68     private static Map<String, GLAPISpec> parseApiSpecs(InputStream specFile) {
69         BufferedReader reader = new BufferedReader(new InputStreamReader(specFile));
70         Map<String, GLAPISpec> specs = new HashMap<String, GLAPISpec>(400);
71 
72         try{
73             String header = reader.readLine().trim();
74             assert header.equals(GLES2_ENTRIES_HEADER_V1);
75 
76             String line;
77             while ((line = reader.readLine()) != null) {
78                 // strip away the comments
79                 int commentPos = line.indexOf('#');
80                 if (commentPos != -1) {
81                     line = line.substring(0, commentPos);
82                 }
83                 line = line.trim();
84 
85                 // parse non empty lines
86                 if (line.length() > 0) {
87                     GLAPISpec spec = parseLine(line);
88                     specs.put(spec.getFunction(), spec);
89                 }
90             }
91 
92             specFile.close();
93         } catch (IOException e) {
94             // this is unlikely to happen as the file is present within this .jar file.
95             // Even if it does happen, we just return whatever we've read till now. The net
96             // impact will be that the function calls will not be parsed fully and will just
97             // display the function name.
98         }
99 
100         return specs;
101     }
102 
103     /**
104      * Parse a GL API Specification entry from "/entries.in". Each line is of the format:
105      * {@code returnType, funcName, arg*}. This method is package private for testing.
106      */
parseLine(String line)107     static GLAPISpec parseLine(String line) {
108         List<String> words = Arrays.asList(line.split(","));
109 
110         String retType = words.get(0).trim();
111         String func = words.get(1).trim();
112         List<String> argDefinitions = words.subList(2, words.size());
113 
114         List<GLDataTypeSpec> glArgs = new ArrayList<GLDataTypeSpec>(argDefinitions.size()/2);
115         for (String argDefn: argDefinitions) {
116             // an argDefn is something like: "const GLvoid* data"
117             argDefn = argDefn.trim();
118             int lastSeparator = argDefn.lastIndexOf(' ');
119             if (lastSeparator == -1) {
120                 // no space => a void type with no argument name
121                 glArgs.add(new GLDataTypeSpec(argDefn, null));
122             } else {
123                 // everything upto the last space is the type
124                 String type = argDefn.substring(0, lastSeparator);
125 
126                 // and the last word is the variable name
127                 String name = argDefn.substring(lastSeparator + 1);
128                 glArgs.add(new GLDataTypeSpec(type, name));
129             }
130         }
131 
132         return new GLAPISpec(func, new GLDataTypeSpec(retType, null), glArgs);
133     }
134 }
135