Initial work

This commit is contained in:
Simon Fels 2016-05-26 22:38:57 +02:00 • committed by Simon Fels
commit 3222551702
374 changed files with 40290 additions and 0 deletions

View file

@ -0,0 +1 @@
add_subdirectory(emugen)

View file

@ -0,0 +1,31 @@
# Determine if the emugen build needs to be builts from
# sources.
LOCAL_PATH:=$(call my-dir)
$(call emugl-begin-host-executable,emugen)
LOCAL_SRC_FILES := \
ApiGen.cpp \
EntryPoint.cpp \
main.cpp \
Parser.cpp \
strUtils.cpp \
TypeFactory.cpp \
LOCAL_HOST_BUILD := true
LOCAL_INSTALL := false
$(call emugl-end-module)
# The location of the emugen host tool that is used to generate wire
# protocol encoders/ decoders. This variable is used by other emugl modules.
EMUGL_EMUGEN := $(LOCAL_BUILT_MODULE)
$(call emugl-begin-host-executable,emugen_unittests)
LOCAL_SRC_FILES := \
Parser.cpp \
Parser_unittest.cpp
LOCAL_HOST_BUILD := true
LOCAL_INSTALL := false
$(call emugl-import,libemugl_gtest_host)
$(call emugl-end-module)

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,97 @@
/*
* 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.
*/
#ifndef __API_GEN_H_
#define __API_GEN_H_
#include <vector>
#include <string.h>
#include "EntryPoint.h"
class ApiGen : public std::vector<EntryPoint> {
public:
typedef std::vector<std::string> StringVec;
typedef enum { CLIENT_SIDE, SERVER_SIDE, WRAPPER_SIDE } SideType;
ApiGen(const std::string & basename) :
m_basename(basename),
m_maxEntryPointsParams(0),
m_baseOpcode(0)
{ }
virtual ~ApiGen() {}
int readSpec(const std::string & filename);
int readAttributes(const std::string & attribFilename);
size_t maxEntryPointsParams() { return m_maxEntryPointsParams; }
void updateMaxEntryPointsParams(size_t val) {
if (m_maxEntryPointsParams == 0 || val > m_maxEntryPointsParams) m_maxEntryPointsParams = val;
}
int baseOpcode() { return m_baseOpcode; }
void setBaseOpcode(int base) { m_baseOpcode = base; }
const char *sideString(SideType side) {
const char *retval;
switch(side) {
case CLIENT_SIDE:
retval = "client";
break;
case SERVER_SIDE:
retval = "server";
break;
case WRAPPER_SIDE:
retval = "wrapper";
break;
default:
retval = "unknown";
}
return retval;
}
StringVec & clientContextHeaders() { return m_clientContextHeaders; }
StringVec & encoderHeaders() { return m_encoderHeaders; }
StringVec & serverContextHeaders() { return m_serverContextHeaders; }
StringVec & decoderHeaders() { return m_decoderHeaders; }
EntryPoint * findEntryByName(const std::string & name);
int genOpcodes(const std::string &filename);
int genAttributesTemplate(const std::string &filename);
int genProcTypes(const std::string &filename, SideType side);
int genFuncTable(const std::string &filename, SideType side);
int genContext(const std::string &filename, SideType side);
int genContextImpl(const std::string &filename, SideType side);
int genEntryPoints(const std::string &filename, SideType side);
int genEncoderHeader(const std::string &filename);
int genEncoderImpl(const std::string &filename);
int genDecoderHeader(const std::string &filename);
int genDecoderImpl(const std::string &filename);
protected:
virtual void printHeader(FILE *fp) const;
std::string m_basename;
StringVec m_clientContextHeaders;
StringVec m_encoderHeaders;
StringVec m_serverContextHeaders;
StringVec m_decoderHeaders;
size_t m_maxEntryPointsParams; // record the maximum number of parameters in the entry points;
int m_baseOpcode;
int setGlobalAttribute(const std::string & line, size_t lc);
};
#endif

View file

@ -0,0 +1,9 @@
set(SOURCES
ApiGen.cpp
EntryPoint.cpp
main.cpp
Parser.cpp
strUtils.cpp
TypeFactory.cpp)
add_executable(emugen ${SOURCES})

View file

@ -0,0 +1,349 @@
/*
* 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.
*/
#include "EntryPoint.h"
#include "Parser.h"
#include "TypeFactory.h"
#include "strUtils.h"
#include <sstream>
#include <string>
#include <stdio.h>
EntryPoint::EntryPoint()
{
reset();
}
EntryPoint::~EntryPoint()
{
}
void EntryPoint::reset()
{
m_unsupported = false;
m_customDecoder = false;
m_notApi = false;
m_flushOnEncode = false;
m_vars.empty();
}
// return true for valid line (need to get into the entry points list)
bool EntryPoint::parse(unsigned int lc, const std::string & str)
{
size_t pos, last;
std::string field;
reset();
std::string linestr = trim(str);
if (linestr.size() == 0) return false;
if (linestr.at(0) == '#') return false;
// skip PREFIX
field = getNextToken(linestr, 0, &last, "(");
pos = last + 1;
// return type
field = getNextToken(linestr, pos, &last, ",)");
std::string error;
std::string retTypeName;
if (!parseTypeDeclaration(field, &retTypeName, &error)) {
fprintf(stderr,
"line: %d: Parsing error in field <%s>: %s\n",
lc,
field.c_str(),
error.c_str());
return false;
}
pos = last + 1;
const VarType *theType = TypeFactory::instance()->getVarTypeByName(retTypeName);
if (theType->name() == "UNKNOWN") {
fprintf(stderr, "UNKNOWN retval: %s\n", linestr.c_str());
}
m_retval.init(std::string(""),
theType,
std::string(""),
Var::POINTER_OUT,
std::string(""),
std::string(""));
// function name
m_name = getNextToken(linestr, pos, &last, ",)");
pos = last + 1;
// parameters;
int nvars = 0;
while (pos < linestr.size() - 1) {
field = getNextToken(linestr, pos, &last, ",)");
if (field == "void") {
// 'void' is used as a special case for functions that don't take
// parameters at all.
break;
}
std::string vartype, varname;
if (!parseParameterDeclaration(field, &vartype, &varname, &error)) {
fprintf(stderr,
"line: %d: Parsing error in field <%s>\n",
lc,
field.c_str(),
error.c_str());
return false;
}
nvars++;
const VarType *v = TypeFactory::instance()->getVarTypeByName(vartype);
if (v->id() == 0) {
fprintf(stderr, "%d: Unknown type: %s\n", lc, vartype.c_str());
} else {
if (varname == "" &&
!(v->name() == "void" && !v->isPointer())) {
std::ostringstream oss;
oss << "var" << nvars;
varname = oss.str();
}
m_vars.push_back(Var(varname, v, std::string(""), Var::POINTER_IN, "", ""));
}
pos = last + 1;
}
return true;
}
void EntryPoint::print(FILE *fp, bool newline,
const std::string & name_suffix,
const std::string & name_prefix,
const std::string & ctx_param ) const
{
fprintf(fp, "%s %s%s%s(",
m_retval.type()->name().c_str(),
name_prefix.c_str(),
m_name.c_str(),
name_suffix.c_str());
if (ctx_param != "") fprintf(fp, "%s ", ctx_param.c_str());
for (size_t i = 0; i < m_vars.size(); i++) {
if (m_vars[i].isVoid()) continue;
if (i != 0 || ctx_param != "") fprintf(fp, ", ");
fprintf(fp, "%s %s", m_vars[i].type()->name().c_str(),
m_vars[i].name().c_str());
}
fprintf(fp, ")%s", newline? "\n" : "");
}
Var * EntryPoint::var(const std::string & name)
{
Var *v = NULL;
for (size_t i = 0; i < m_vars.size(); i++) {
if (m_vars[i].name() == name) {
v = &m_vars[i];
break;
}
}
return v;
}
bool EntryPoint::hasPointers()
{
bool pointers = false;
if (m_retval.isPointer()) pointers = true;
if (!pointers) {
for (size_t i = 0; i < m_vars.size(); i++) {
if (m_vars[i].isPointer()) {
pointers = true;
break;
}
}
}
return pointers;
}
int EntryPoint::setAttribute(const std::string &line, size_t lc)
{
size_t pos = 0;
size_t last;
std::string token = getNextToken(line, 0, &last, WHITESPACE);
if (token == "len") {
pos = last;
std::string varname = getNextToken(line, pos, &last, WHITESPACE);
if (varname.size() == 0) {
fprintf(stderr, "ERROR: %u: Missing variable name in 'len' attribute\n", (unsigned int)lc);
return -1;
}
Var * v = var(varname);
if (v == NULL) {
fprintf(stderr, "ERROR: %u: variable %s is not a parameter of %s\n",
(unsigned int)lc, varname.c_str(), name().c_str());
return -2;
}
// set the size expression into var
pos = last;
v->setLenExpression(line.substr(pos));
} else if (token == "param_check") {
pos = last;
std::string varname = getNextToken(line, pos, &last, WHITESPACE);
if (varname.size() == 0) {
fprintf(stderr, "ERROR: %u: Missing variable name in 'param_check' attribute\n", (unsigned int)lc);
return -1;
}
Var * v = var(varname);
if (v == NULL) {
fprintf(stderr, "ERROR: %u: variable %s is not a parameter of %s\n",
(unsigned int)lc, varname.c_str(), name().c_str());
return -2;
}
// set the size expression into var
pos = last;
v->setParamCheckExpression(line.substr(pos));
} else if (token == "dir") {
pos = last;
std::string varname = getNextToken(line, pos, &last, WHITESPACE);
if (varname.size() == 0) {
fprintf(stderr, "ERROR: %u: Missing variable name in 'dir' attribute\n", (unsigned int)lc);
return -1;
}
Var * v = var(varname);
if (v == NULL) {
fprintf(stderr, "ERROR: %u: variable %s is not a parameter of %s\n",
(unsigned int)lc, varname.c_str(), name().c_str());
return -2;
}
pos = last;
std::string pointerDirStr = getNextToken(line, pos, &last, WHITESPACE);
if (pointerDirStr.size() == 0) {
fprintf(stderr, "ERROR: %u: missing pointer directions\n", (unsigned int)lc);
return -3;
}
if (pointerDirStr == "out") {
v->setPointerDir(Var::POINTER_OUT);
} else if (pointerDirStr == "inout") {
v->setPointerDir(Var::POINTER_INOUT);
} else if (pointerDirStr == "in") {
v->setPointerDir(Var::POINTER_IN);
} else {
fprintf(stderr, "ERROR: %u: unknow pointer direction %s\n", (unsigned int)lc, pointerDirStr.c_str());
}
} else if (token == "var_flag") {
pos = last;
std::string varname = getNextToken(line, pos, &last, WHITESPACE);
if (varname.size() == 0) {
fprintf(stderr, "ERROR: %u: Missing variable name in 'var_flag' attribute\n", (unsigned int)lc);
return -1;
}
Var * v = var(varname);
if (v == NULL) {
fprintf(stderr, "ERROR: %u: variable %s is not a parameter of %s\n",
(unsigned int)lc, varname.c_str(), name().c_str());
return -2;
}
int count = 0;
for (;;) {
pos = last;
std::string flag = getNextToken(line, pos, &last, WHITESPACE);
if (flag.size() == 0) {
if (count == 0) {
fprintf(stderr, "ERROR: %u: missing flag\n", (unsigned int) lc);
return -3;
}
break;
}
count++;
if (flag == "nullAllowed") {
if (v->isPointer()) {
v->setNullAllowed(true);
} else {
fprintf(stderr, "WARNING: %u: setting nullAllowed for non-pointer variable %s\n",
(unsigned int) lc, v->name().c_str());
}
} else if (flag == "isLarge") {
if (v->isPointer()) {
v->setIsLarge(true);
} else {
fprintf(stderr, "WARNING: %u: setting isLarge flag for a non-pointer variable %s\n",
(unsigned int) lc, v->name().c_str());
}
} else {
fprintf(stderr, "WARNING: %u: unknow flag %s\n", (unsigned int)lc, flag.c_str());
}
}
} else if (token == "custom_pack") {
pos = last;
std::string varname = getNextToken(line, pos, &last, WHITESPACE);
if (varname.size() == 0) {
fprintf(stderr, "ERROR: %u: Missing variable name in 'custom_pack' attribute\n", (unsigned int)lc);
return -1;
}
Var * v = var(varname);
if (v == NULL) {
fprintf(stderr, "ERROR: %u: variable %s is not a parameter of %s\n",
(unsigned int)lc, varname.c_str(), name().c_str());
return -2;
}
// set the size expression into var
pos = last;
v->setPackExpression(line.substr(pos));
} else if (token == "custom_write") {
pos = last;
std::string varname = getNextToken(line, pos, &last, WHITESPACE);
if (varname.size() == 0) {
fprintf(stderr, "ERROR: %u: Missing variable name in 'custom_write' attribute\n", (unsigned int)lc);
return -1;
}
Var * v = var(varname);
if (v == NULL) {
fprintf(stderr, "ERROR: %u: variable %s is not a parameter of %s\n",
(unsigned int)lc, varname.c_str(), name().c_str());
return -2;
}
// set the size expression into var
pos = last;
v->setWriteExpression(line.substr(pos));
} else if (token == "flag") {
pos = last;
std::string flag = getNextToken(line, pos, &last, WHITESPACE);
if (flag.size() == 0) {
fprintf(stderr, "ERROR: %u: missing flag\n", (unsigned int) lc);
return -4;
}
if (flag == "unsupported") {
setUnsupported(true);
} else if (flag == "custom_decoder") {
setCustomDecoder(true);
} else if (flag == "not_api") {
setNotApi(true);
} else if (flag == "flushOnEncode") {
setFlushOnEncode(true);
} else {
fprintf(stderr, "WARNING: %u: unknown flag %s\n", (unsigned int)lc, flag.c_str());
}
} else {
fprintf(stderr, "WARNING: %u: unknown attribute %s\n", (unsigned int)lc, token.c_str());
}
return 0;
}

View file

@ -0,0 +1,70 @@
/*
* 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.
*/
#ifndef __EntryPoint__H__
#define __EntryPoint__H__
#include <string>
#include <vector>
#include <stdio.h>
#include "Var.h"
//---------------------------------------------------
typedef std::vector<Var> VarsArray;
class EntryPoint {
public:
EntryPoint();
virtual ~EntryPoint();
bool parse(unsigned int lc, const std::string & str);
void reset(); // reset the class to empty;
void print(FILE *fp = stdout, bool newline = true,
const std::string & name_suffix = std::string(""),
const std::string & name_prefix = std::string(""),
const std::string & ctx_param = std::string("")) const;
const std::string & name() const { return m_name; }
VarsArray & vars() { return m_vars; }
Var & retval() { return m_retval; }
Var * var(const std::string & name);
bool hasPointers();
bool unsupported() const { return m_unsupported; }
void setUnsupported(bool state) { m_unsupported = state; }
bool customDecoder() { return m_customDecoder; }
void setCustomDecoder(bool state) { m_customDecoder = state; }
bool notApi() const { return m_notApi; }
void setNotApi(bool state) { m_notApi = state; }
bool flushOnEncode() const { return m_flushOnEncode; }
void setFlushOnEncode(bool state) { m_flushOnEncode = state; }
int setAttribute(const std::string &line, size_t lc);
private:
enum { PR_RETVAL = 0, PR_NAME, PR_VARS, PR_DONE } prState;
std::string m_name;
Var m_retval;
VarsArray m_vars;
bool m_unsupported;
bool m_customDecoder;
bool m_notApi;
bool m_flushOnEncode;
void err(unsigned int lc, const char *msg) {
fprintf(stderr, "line %d: %s\n", lc, msg);
}
};
#endif

View file

@ -0,0 +1,191 @@
/*
* Copyright 2014 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.
*/
#include "Parser.h"
#include <vector>
#define WHITESPACE " \t\n"
// Parse the |input| string as a list of type-specific tokens.
// This tokenizes the input, using whitespace as separators and '*' as
// a single token too. On success, return true and sets |*out| to the
// list of tokens. On failure, return false.
//
// Example: 'const char**foo' -> ['const', 'char', '*', '*', 'foo']
//
static bool parseTypeTokens(const std::string& input,
std::vector<std::string>* out,
std::string* error) {
out->clear();
size_t pos = 0U;
// Parse all tokens in the input, treat '*' as a single token.
// I.e.
for (;;) {
// skip leading whitespace.
pos = input.find_first_not_of(WHITESPACE, pos);
if (pos == std::string::npos) {
break; // end of parse.
}
// If this is a star, ensure it follows a type name.
// otherwise treat it as part of the final type.
if (input[pos] == '*') {
out->push_back(std::string("*"));
pos += 1U;
continue;
}
// find end of type/token.
size_t end = input.find_first_of(WHITESPACE "*", pos);
if (end == std::string::npos) {
end = input.size();
}
std::string str = input.substr(pos, end - pos);
if (str.size() == 0) {
// Sanity check: should not happen.
if (error != NULL) {
*error = "Unexpected empty token !?";
}
return false;
}
out->push_back(str);
pos = end;
}
if (error != NULL) {
// Sanity check: require non-empty input
if (out->empty()) {
*error = "Empty parameter declaration!";
return false;
}
// Sanity check: There must be base type name before any '*'
for (size_t n = 0; n < out->size(); ++n) {
std::string& token = (*out)[n];
if (token == "*") {
*error = "Unexpected '*' before type name";
return false;
} else if (token != "const") {
break;
}
}
}
return true;
}
// Given |tokens|, an input vector of strings, join the first |count| items
// into a normalized type string, and return it.
static std::string buildTypeString(const std::vector<std::string>& tokens,
size_t count) {
std::string result;
for (size_t n = 0; n < count; ++n) {
const std::string& token = tokens[n];
if (n > 0 && token != "*") {
result.append(" ");
}
result.append(token);
}
return result;
}
std::string normalizeTypeDeclaration(const std::string& input) {
std::vector<std::string> tokens;
if (!parseTypeTokens(input, &tokens, NULL)) {
return "";
}
return buildTypeString(tokens, tokens.size());
}
bool parseTypeDeclaration(const std::string& input,
std::string* typeName,
std::string* error) {
// The type name can be made of several tokens, e.g. 'unsigned int'
// use an array to store them, and a count variable. Each item can be
// one of '*', 'const' or a type name component (e.g. 'struct', 'unsigned')
std::vector<std::string> tokens;
if (!parseTypeTokens(input, &tokens, error)) {
return false;
}
// Sanity check, there must be a least one non-special tokens.
size_t nonSpecialCount = 0;
for (size_t n = 0; n < tokens.size(); ++n) {
if (tokens[n] != "*" && tokens[n] != "const") {
nonSpecialCount++;
}
}
if (nonSpecialCount == 0) {
*error = "Missing type name";
return false;
}
// Build the type name from all tokens before it.
*typeName = buildTypeString(tokens, tokens.size());
return true;
}
bool parseParameterDeclaration(const std::string& param,
std::string* typeName,
std::string* variableName,
std::string* error) {
std::vector<std::string> tokens;
if (!parseTypeTokens(param, &tokens, error)) {
return false;
}
// Sanity check, there must be a least two non-special tokens.
size_t nonSpecialCount = 0;
for (size_t n = 0; n < tokens.size(); ++n) {
if (tokens[n] != "*" && tokens[n] != "const") {
nonSpecialCount++;
}
}
if (nonSpecialCount == 0) {
*error = "Missing type name";
return false;
}
if (nonSpecialCount == 1) {
*error = "Missing variable name";
return false;
}
// Sanity check: variable name must not be followed by 'const' or '*'
const std::string& lastToken = tokens[tokens.size() - 1U];
if (lastToken == "*") {
*error = "Extra '*' after variable name";
return false;
}
if (lastToken == "const") {
*error = "Extra 'const' after variable name";
return false;
}
// Extract the variable name as the last token.
if (variableName) {
*variableName = lastToken;
}
// Build the type name from all tokens before it.
*typeName = buildTypeString(tokens, tokens.size() - 1U);
return true;
}

View file

@ -0,0 +1,68 @@
/*
* Copyright 2014 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.
*/
#ifndef PARSER_H
#define PARSER_H
#include <string>
// Normalize a type declaration. This gets rid of leading/trailing whitespace
// as well as ensure there is a single space separating all input tokens,
// with the exception of '*' which is treated specially by never being
// prepended with a space.
// |input| is the input type declaration. Return normalized form.
// Note that this doesn't try to validate the input.
std::string normalizeTypeDeclaration(const std::string& input);
// Parse a return type declaration. |input| is the type declaration
// (e.g. 'const char**'). On success return true and sets |*typeName| to
// the appropriate normalized type string. On failure, return false and
// sets |*error| with a human-friendly message explaining the reason for
// failure.
//
// Note that the returned type string is normalized, see comment for
// parseParameterDeclaration() for examples.
//
// NOTE: This does not support declarations of arrays or functions!
//
bool parseTypeDeclaration(const std::string& input,
std::string* typeName,
std::string* error);
// Parse a function parameter declaration and extract the type and variable
// name from it. |param| is the individual parameter declaration from the
// function's signature (e.g. 'const char *items')
//
// On success, returns true and sets |*vartype| and |*varname| to the
// appropriate type name and variable name. |varname| can be NULL if the caller
// isn't interested in the variable name.
//
// On failure, return false and sets |*error| to a human-friendly message
// explaining the reason for failure.
//
// Note that the returned type name is normalized with regards to whitespace
// and star location, e.g.:
//
// const void *items -> 'const void*'
// char* *items -> 'char**'
// const void * const * items -> 'const void* const*'
// unsigned int *const data -> 'unsigned int* const'
//
bool parseParameterDeclaration(const std::string& param,
std::string* typeName,
std::string* variableName,
std::string* error);
#endif // PARSER_H

View file

@ -0,0 +1,120 @@
/*
* Copyright 2014 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.
*/
#include "Parser.h"
#include <gtest/gtest.h>
#define ARRAYLEN(x) (sizeof(x) / sizeof(x[0]))
TEST(ParserTest, normalizeTypeDeclaration) {
static const struct {
const char* expected;
const char* input;
} kData[] = {
{ "char", "char" },
{ "const unsigned int", " const unsigned\tint\n" },
{ "char* const**", "char *const* *" },
};
const size_t kDataSize = ARRAYLEN(kData);
for (size_t n = 0; n < kDataSize; ++n) {
std::string result;
std::string text = "When parsing '";
text += kData[n].input;
text += "'";
result = normalizeTypeDeclaration(kData[n].input);
EXPECT_STREQ(kData[n].expected, result.c_str()) << text;
}
}
TEST(ParserTest, parseTypeDeclaration) {
static const struct {
const char* input;
bool expected;
const char* expectedType;
const char* expectedError;
} kData[] = {
{ "const", false, NULL, "Missing type name" },
{ "const const", false, NULL, "Missing type name" },
{ "foo", true, "foo", NULL },
{ "void", true, "void", NULL },
{ "const foo", true, "const foo", NULL },
{ "foo *", true, "foo*", NULL },
{ "char foo", true, "char foo", NULL },
{ "\tunsigned \t int\n", true, "unsigned int", NULL },
{ "const * char", false, NULL, "Unexpected '*' before type name" },
{ "const char * ", true, "const char*", NULL },
{ "const void*const * *", true, "const void* const**", NULL },
};
const size_t kDataSize = ARRAYLEN(kData);
for (size_t n = 0; n < kDataSize; ++n) {
std::string varname, vartype, error;
std::string text = "When parsing '";
text += kData[n].input;
text += "'";
EXPECT_EQ(kData[n].expected,
parseTypeDeclaration(kData[n].input,
&vartype,
&error)) << text;
if (kData[n].expected) {
EXPECT_STREQ(kData[n].expectedType, vartype.c_str()) << text;
} else {
EXPECT_STREQ(kData[n].expectedError, error.c_str()) << text;
}
}
}
TEST(ParserTest, parseParameterDeclaration) {
static const struct {
const char* input;
bool expected;
const char* expectedType;
const char* expectedVariable;
const char* expectedError;
} kData[] = {
{ "foo", false, NULL, NULL, "Missing variable name" },
{ "const", false, NULL, NULL, "Missing type name" },
{ "const foo", false, NULL, NULL, "Missing variable name" },
{ "const const", false, NULL, NULL, "Missing type name" },
{ "char foo", true, "char", "foo", NULL },
{ "unsigned int\t bar\n", true, "unsigned int", "bar", NULL },
{ "const * char foo", false, NULL, NULL, "Unexpected '*' before type name" },
{ "const char * foo", true, "const char*", "foo", NULL },
{ "const void*const *data", true, "const void* const*", "data", NULL },
{ "char foo const", false, NULL, NULL, "Extra 'const' after variable name" },
{ "int bar*", false, NULL, NULL, "Extra '*' after variable name" },
};
const size_t kDataSize = ARRAYLEN(kData);
for (size_t n = 0; n < kDataSize; ++n) {
std::string varname, vartype, error;
std::string text = "When parsing '";
text += kData[n].input;
text += "'";
EXPECT_EQ(kData[n].expected,
parseParameterDeclaration(kData[n].input,
&vartype,
&varname,
&error)) << text;
if (kData[n].expected) {
EXPECT_STREQ(kData[n].expectedType, vartype.c_str()) << text;
EXPECT_STREQ(kData[n].expectedVariable, varname.c_str()) << text;
} else {
EXPECT_STREQ(kData[n].expectedError, error.c_str()) << text;
}
}
}

View file

@ -0,0 +1,332 @@
Introduction:
-------------
The emugen tool is a tool to generate a wire protocol implementation
based on provided API. The tool generates c++ encoder code that takes
API calls and encodes them into the wire and decoder code that decodes
the wire stream and calls server matching API.
The emugen tool includes additional functionality that enables to
generate an wrapper library. The wrapper library provides entry points
for the specified API, where each entry routes the call via a dispatch
table. The dispatch table may be initialized as required by a specific application.
The following paragraphs includes the following:
* Wire Protocol Description
* Input files description & format
* Generated code description.
Note: In this document, the caller is referred to as Encoder or Client
and the callee is referred to as the Decoder or Server. These terms
are used interchangeably by the context.
Wire Protocol packet structure:
-------------------------------
A general Encoder->Decoder packet is structured as following:
struct Packet {
unsigned int opcode;
unsigned int packet_len;
… parameter 1
… parameter 2
};
A general Decoder->Encoder reply is expected to be received in the
context of the ‘call’ that triggered it, thus it includes the reply
data only, with no context headers. In precise term terms, a reply
packet will look like:
struct {
...// reply data
};
consider the following function call:
int foo(int p1, short s1)
will be encoded into :
{
101, // foo opcode
14, // sizeof(opcode) + sizeof(packet_len) + sizeof(int) + sizeof(short)
p1, // 4 bytes
s1 // 2 bytes
}
Since ‘foo’ returns value, the caller is expected to read back the return packet from the server->client stream. The return value in this example is in thus the return packet is:
{
int retval;
}
Pointer decoding:
----------------
The wire protocol also allows exchanging of pointer data
(arrays). Pointers are defined with directions:
in : Data is sent from the caller to the calle
out: Data is sent from the callee to the caller
in_out: data is sent from the caller and return in place.
‘in’ and ‘in_out’ encoded with their len:
{
unsinged int pointer_data_len;
unsigned char data[pointer_data_len];… // pointer data
}
‘out’ pointers are encoded by data length only:
{
unsigned int pointer_data_len;
}
‘out’ and ‘in_out’ pointer’s data is returned in the return
packet. For example, consider the following call:
int foo(int n, int *ptr); // assume that ‘data’ is in_out pointer which contains ‘n’ ints
The caller packet will have the following form:
{
101, // foo opcode
xx, sizeof(opcode) + sizeof(datalen) + sizeof(int) + sizeof(unsigned int) + n * sizeof(int);
n, // the n parameter
n * sizeof(int), // size of the data in ptr
… // n* sizeof(int) bytes
}
The return packet is;
{
…. // n * sizeof(int) bytes of data return in ptr
retval // sizeof(int) - the return value of the function;
}
Endianess
---------
The Wire protocol is designed to impose minimum overhead on the client
side. Thus, the data endianness that is sent across the wire is
determined by the ‘client’ side. It is up to the server side to
determine the client endianess and marshal the packets as required.
Emugen input files - protocol specification
-------------------------------------------
The protocol generated by emugen consists of two input files:
1. basename.in - A sepcification of the protocol RPC procedures. This
part of the specification is expected to be generated automatically
from c/c++ header files or similar.
‘basename’ is the basename for the protocol and will be used to prefix
the files that are generated for this protocol. A line in the .in
file has the following format:
[prefix](retvalType, FuncName, <param type> [param name],...)
where
retvalType - The function return value type
FuncName - function name
<param type> mandatory parameter type
[param name] - optional parameter name
Examples:
GL_ENTRY(void, glVertex1f, float v)
XXX(int *, foo, int n, float, short)
XXX(void, glFlush, void)
Note: Empty lines in the file are ignored. A line starts with # is a comment
2. basename.attrib - Attributes information of the API.
This file includes additional flags, pointers datalen information and
global attributes of the protocol. For uptodate format of the file,
please refer to the specification file in the project source
tree. The format of the .attrib file is described below.
3. basename.types - Types information
This files describes the types that are described by the API. A type
is defined as follows:
<type name> <size in bits> <print format string> <is a pointer? true|false>
where:
<type name> is the name of the type as described in the API
<size in bits> 0, 8, 16, 32 sizes are accepted
<print format string> a string to format the value of the type, as
acceted by printf(3)
<is pointer?> true or false string species whether the type should be
treated as a pointer.
example:
GLint 32 %d false
GLint* 32 %p true
GLptr 32 %p true
Encoder generated code files
----------------------------
In order to generate the encoder files, one should run the ‘emugen’
tool as follows:
emugen -i <input directory> -E <encoder files output directory> <basename>
where:
<input directory> containes the api specification files (basename.in + basename.attrib)
<encoder directory> - a directory name to generate the encoder output files
basename - The basename for the api.
Assuming the basename is ‘api’, The following files are generated:
api_opcodes.h - defines the protocol opcodes. The first opcode value
is 0, unless defined otherwise in the .attrib file
api_entry.cpp - defines entry points for the functions that are
defined by the protocol. this File also includes a function call
‘setContextAccessor(void *(*f)()). This function should be used to
provide a callback function that is used by the functions to access
the encoder context. For example, such callback could fetch the
context from a Thread Local Storage (TLS) location.
api_client_proc.h - type defintions for the protocol procedures.
api_client_context.h - defines the client side dispatch table data
structure that stores the encoding functions. This data structure also
includes ‘accessors’ methods such that library user can override
default entries for special case handling.
api_client_context.cpp - defines an initialization function for
dispatch table
api_enc.h - This header file defines the encoder data strcuture. The
encoder data structure inherits its functionality from the
‘client_context’ class above and adds encoding and streaming
functionality.
api_enc.cpp - Encoder implementation.
Decoder generated files
-----------------------
In order to generate the decoder files, one should run the ‘emugen’
tool as follows:
emugen -i <input directory> -D <decoder files output directory> basename
where:
<input directory> containes the api specification files (basename.in + basename.attrib)
<decoder directory> - a directory name to generate the decoder output files
basename - The basename for the api.
With resepct to the example above, Emugen will generate the following
files:
api_opcodes.h - Protocol opcodes
api_server_proc.h - type definitions for the server side procedures
api_server_context.h - dispatch table the decoder functions
api_server_context.cpp - dispatch table initialization function
api_dec.h - Decoder header file
api_dec.cpp - Decoder implementation. In addtion, this file includes
an intiailization function that uses a user provided callback to
initialize the API server implementation. An example for such
initialization is loading a set of functions from a shared library
module.
Wrapper generated files
-----------------------
In order to generate a wrapper library files, one should run the
'emugen' tool as follows:
emugen -i <input directory> -W <wrapper files output directory> basename
where:
<input directory> containes the api specification files (basename.in + basename.attrib)
<wrapper directory> - a directory name to generate the wrapper output files
basename - The basename for the api.
With resepct to the example above, Emugen will generate the following
files:
api_wrapper_proc.h - type definitions for the wrapper procedures
api_wrapper_context.h - dispatch table the wrapper functions
api_wrapper_context.cpp - dispatch table initialization function
api_wrapper_entry.cpp - entry points for the API
.attrib file format description:
-------------------------------
The .attrib file is an input file to emugen and is used to provide
additional information that is required for the code generation.
The file format is as follows:
a line that starts with # is ignored (comment)
a empty line just whitespace of (" " "\t" "\n") is ignored.
The file is divided into 'sections', each describes a specific API
function call. A section starts with the name of the function in
column 0.
A section that starts with the reserved word 'GLOBAL' provides global
attributes.
below are few sections examples:
GLOBAL
encoder_headers string.h kuku.h
glVertex3fv
len data (size)
glTexImage2D
len pixels (pixels == NULL? 0 : (format_pixel_size(internalformat) * width * height * type_size(type)))
Global section flags description:
base_opcode
set the base opcode value for this api
format: base_opcode 100
encoder_headers
a list of headers that will be included in the encoder header file
format: encoder_headers <stdio.h> "kuku.h"
client_context_headers
a list of headers that will be included in the client context header file
format: client_context_headers <stdio.h> "kuku.h"
decoder_headers
a list of headers that will be included in the decoder header file
format: decoder_headers <stdio.h> "kuku.h"
server_context_headers
a list of headers that will be included in the server context header file
format: server_context_headers <stdio.h> "kuku.h"
Entry point flags description:
len
desciption : provide an expression to calcualte an expression data len
format: len <var name> <c expression that calcluates the data len>
custom_pack
description: provide an expression to pack data into the stream.
format: custom_pack <var name> <c++ expression that pack data from var into the stream>
The stream is represented by a (unsigned char *)ptr. The expression may also refer
to other function parameters. In addition, the expression may refer to 'void *self' which
is the encoding context as provided by the caller.
dir
description : set a pointer direction (in - for data that goes
to the codec, out from data that returns from the codec.
format: dir <varname> <[in | out | inout]>
var_flag
description : set variable flags
format: var_flag <varname> < nullAllowed | isLarge | ... >
nullAllowed -> for pointer variables, indicates that NULL is a valid value
isLarge -> for pointer variables, indicates that the data should be sent without an intermediate copy
flag
description: set entry point flag;
format: flag < unsupported | ... >
supported flags are:
unsupported - The encoder side implementation is pointed to "unsuppored reporting function".
custom_decoder - The decoder is expected to be provided with
custom implementation. The call to the
deocder function includes a pointer to the
context
not_api - the function is not native gl api

View file

@ -0,0 +1,157 @@
/*
* 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.
*/
#include "TypeFactory.h"
#include "Parser.h"
#include "VarType.h"
#include "strUtils.h"
#include <map>
#include <string>
#include <stdio.h>
#include <stdlib.h>
TypeFactory * TypeFactory::m_instance = NULL;
typedef std::map<std::string, VarType> TypeMap;
static TypeMap g_varMap;
static bool g_initialized = false;
static int g_typeId = 0;
#define ADD_TYPE(name, size, printformat,ispointer) \
g_varMap.insert(std::pair<std::string, VarType>(name, VarType(g_typeId++, name, (size + 7) >> 3, printformat , ispointer)));
void TypeFactory::initBaseTypes()
{
g_initialized = true;
ADD_TYPE("UNKNOWN", 0, "0x%x", false);
ADD_TYPE("void", 0, "0x%x", false);
ADD_TYPE("char", 8, "%c", false);
ADD_TYPE("int", 32, "%d", false);
ADD_TYPE("float", 32, "%d", false);
ADD_TYPE("short", 16, "%d", false);
}
int TypeFactory::initFromFile(const std::string &filename)
{
if (!g_initialized) {
initBaseTypes();
}
FILE *fp = fopen(filename.c_str(), "rt");
if (fp == NULL) {
perror(filename.c_str());
return -1;
}
char line[1000];
int lc = 0;
while(fgets(line, sizeof(line), fp) != NULL) {
lc++;
std::string str = trim(line);
if (str.size() == 0 || str.at(0) == '#') {
continue;
}
size_t pos = 0, last;
std::string name;
name = getNextToken(str, pos, &last, WHITESPACE);
name = normalizeTypeDeclaration(name);
if (name.size() == 0) {
fprintf(stderr, "Error: %d : missing type name\n", lc);
return -2;
}
pos = last + 1;
std::string size;
size = getNextToken(str, pos, &last, WHITESPACE);
if (size.size() == 0) {
fprintf(stderr, "Error: %d : missing type width\n", lc);
return -2;
}
pos = last + 1;
std::string printString;
printString = getNextToken(str, pos, &last, WHITESPACE);
if (printString.size() == 0) {
fprintf(stderr, "Error: %d : missing print-string\n", lc);
return -2;
}
// The ispointer definition is optional since we can just
// look at the type name, and determine it is a pointer if
// it ends with '*'.
bool isPointer = (name[name.size() - 1U] == '*');
pos = last + 1;
std::string pointerDef;
pointerDef = getNextToken(str, pos, &last, WHITESPACE);
if (pointerDef.size() != 0) {
// Just a little sanity check.
if (std::string("true")==pointerDef) {
if (!isPointer) {
fprintf(stderr, "Error: %d: invalid isPointer definition: 'true' but name does not end with '*'!\n", lc);
return -2;
}
} else if (std::string("false")==pointerDef) {
if (isPointer) {
fprintf(stderr, "Error: %d: invalid isPointer definition: 'false' but name does end with '*'!\n", lc);
return -2;
}
} else {
fprintf(stderr, "Error: %d : invalid isPointer definition, must be either \"true\" or \"false\"\n", lc);
return -2;
}
}
size_t bitSize = atoi(size.c_str());
size_t byteSize = (bitSize + 7) >> 3;
if (getVarTypeByName(name)->id() != 0) {
fprintf(stderr,
"Warining: %d : type %s is already known, definition in line %d is taken\n",
lc, name.c_str(), lc);
}
g_varMap.insert(std::pair<std::string, VarType>(
name, VarType(g_typeId++,
name,
byteSize,
printString,
isPointer)));
std::string constName = "const " + name;
g_varMap.insert(std::pair<std::string, VarType>(
constName, VarType(g_typeId++,
constName,
byteSize,
printString,
isPointer))); //add a const type
}
g_initialized = true;
return 0;
}
const VarType * TypeFactory::getVarTypeByName(const std::string & type)
{
if (!g_initialized) {
initBaseTypes();
}
TypeMap::iterator i = g_varMap.find(type);
if (i == g_varMap.end()) {
i = g_varMap.find("UNKNOWN");
}
return &(i->second);
}

View file

@ -0,0 +1,37 @@
/*
* 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.
*/
#ifndef __TYPE__FACTORY__H__
#define __TYPE__FACTORY__H__
#include <string>
#include "VarType.h"
class TypeFactory {
public:
static TypeFactory *instance() {
if (m_instance == NULL) {
m_instance = new TypeFactory;
}
return m_instance;
}
const VarType * getVarTypeByName(const std::string &type);
int initFromFile(const std::string &filename);
private:
static TypeFactory *m_instance;
void initBaseTypes();
TypeFactory() {}
};
#endif

View file

@ -0,0 +1,110 @@
/*
* 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.
*/
#ifndef __VAR__H__
#define __VAR__H__
#include "VarType.h"
#include <string>
#include <stdio.h>
class Var {
public:
// pointer data direction - from the client point of view.
typedef enum { POINTER_OUT = 0x1, POINTER_IN = 0x2, POINTER_INOUT = 0x3 } PointerDir;
Var() :
m_name(""),
m_type(NULL),
m_lenExpression(""),
m_pointerDir(POINTER_IN),
m_nullAllowed(false),
m_isLarge(false),
m_packExpression(""),
m_writeExpression(""),
m_paramCheckExpression("")
{
}
Var(const std::string & name,
const VarType * vartype,
const std::string & lenExpression,
PointerDir dir,
const std::string &packExpression,
const std::string &writeExpression) :
m_name(name),
m_type(const_cast<VarType *>(vartype)),
m_lenExpression(lenExpression),
m_pointerDir(dir),
m_nullAllowed(false),
m_isLarge(false),
m_packExpression(packExpression),
m_writeExpression(writeExpression),
m_paramCheckExpression("")
{
}
void init(const std::string name, const VarType * vartype,
std::string lenExpression,
PointerDir dir,
std::string packExpression,
std::string writeExpression) {
m_name = name;
m_type = vartype;
m_lenExpression = lenExpression;
m_packExpression = packExpression;
m_writeExpression = writeExpression;
m_pointerDir = dir;
m_nullAllowed = false;
m_isLarge = false;
}
const std::string & name() const { return m_name; }
const VarType * type() const { return m_type; }
bool isPointer() const { return m_type->isPointer(); }
bool isVoid() const { return ((m_type->bytes() == 0) && (!m_type->isPointer())); }
const std::string & lenExpression() const { return m_lenExpression; }
const std::string & packExpression() const { return(m_packExpression); }
const std::string & writeExpression() const { return(m_writeExpression); }
const std::string & paramCheckExpression() const { return m_paramCheckExpression; }
void setLenExpression(const std::string & lenExpression) { m_lenExpression = lenExpression; }
void setPackExpression(const std::string & packExpression) { m_packExpression = packExpression; }
void setWriteExpression(const std::string & writeExpression) { m_writeExpression = writeExpression; }
void setParamCheckExpression(const std::string & paramCheckExpression) { m_paramCheckExpression = paramCheckExpression; }
void setPointerDir(PointerDir dir) { m_pointerDir = dir; }
PointerDir pointerDir() { return m_pointerDir; }
void setNullAllowed(bool state) { m_nullAllowed = state; }
void setIsLarge(bool state) { m_isLarge = state; }
bool nullAllowed() const { return m_nullAllowed; }
bool isLarge() const { return m_isLarge; }
void printType(FILE *fp) { fprintf(fp, "%s", m_type->name().c_str()); }
void printTypeName(FILE *fp) { printType(fp); fprintf(fp, " %s", m_name.c_str()); }
private:
std::string m_name;
const VarType * m_type;
bool m_pointer; // is this variable a pointer;
std::string m_lenExpression; // an expression to calcualte a pointer data size
PointerDir m_pointerDir;
bool m_nullAllowed;
bool m_isLarge;
std::string m_packExpression; // an expression to pack data into the stream
std::string m_writeExpression; // an expression to write data into the stream
std::string m_paramCheckExpression; //an expression to check parameter value
};
#endif

View file

@ -0,0 +1,62 @@
/*
* 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.
*/
#ifndef __VARTYPE__H__
#define __VARTYPE__H__
#include <string>
// VarType models the types of values used on the wire protocol by
// both encoders and decoders. Each type is identified by a unique id,
// and a name, and provides a size in bytes for the values, a printf-like
// formatter string, and a flag telling if the value corresponds to a
// pointer.
class VarType {
public:
VarType() :
m_id(0),
m_name("default_constructed"),
m_byteSize(0),
m_printFormat("0x%x"),
m_isPointer(false) {}
VarType(size_t id,
const std::string& name,
size_t byteSize,
const std::string& printFormat,
bool isPointer) :
m_id(id),
m_name(name),
m_byteSize(byteSize),
m_printFormat(printFormat),
m_isPointer(isPointer) {}
~VarType() {}
size_t id() const { return m_id; }
const std::string& name() const { return m_name; }
size_t bytes() const { return m_byteSize; }
const std::string& printFormat() const { return m_printFormat; }
bool isPointer() const { return m_isPointer; }
private:
size_t m_id;
std::string m_name;
size_t m_byteSize;
std::string m_printFormat;
bool m_isPointer;
};
#endif

View file

@ -0,0 +1,24 @@
/*
* 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.
*/
#ifndef _ERRORS_H_
#define _ERRORS_H_
#define BAD_USAGE -1
#define BAD_SPEC_FILE -2
#define BAD_TYPES_FILE -3
#define BAD_ATTRIBUTES_FILE -4
#endif

View file

@ -0,0 +1,76 @@
#include "getopt.h"
#include <stdio.h>
#include <string.h>
#define _getprogname() nargv[0]
int opterr = 1;
int optind = 1;
int optopt = 0;
char* optarg;
int getopt(int argc, char* const argv[], const char* ostr) {
static const char kEmpty[] = "";
static const char* place = kEmpty;
if (!*place) {
if (optind >= argc)
return -1;
const char* arg = argv[optind];
if (arg[0] != '-') {
// Not an option.
return -1;
}
if (arg[1] == '-' && !arg[2]) {
// '--' -> end of options.
return -1;
}
if (!arg[1]) {
// Single '-', If the program wants it, treat it as an option.
// Otherwise, it's the end of options.
if (!strchr(ostr, '-')) {
return -1;
}
optopt = '-';
place = arg + 1;
} else {
optopt = arg[1];
place = arg + 2;
}
};
char* oindex = strchr(ostr, optopt);
if (!oindex) {
// Unsupported option.
(void)fprintf(stderr, "%s: illegal option -- %c\n", argv[0]);
return '?';
}
if (oindex[1] != ':') {
// No argument needed.
optarg = NULL;
if (!*place)
optind++;
return optopt;
}
// This option needs an argument. Either after the option character,
// or the argument that follows.
if (*place) {
optarg = (char *)place;
} else if (argc > ++optind) {
optarg = (char *)argv[optind];
} else if (oindex[2] == ':') {
// Optional argument is missing.
place = kEmpty;
optarg = NULL;
return optopt;
} else {
// Missing argument.
place = kEmpty;
(void)fprintf(stderr, "%s: option requires an argument --%c\n",
argv[0], optopt);
return ':';
}
return optopt;
}

View file

@ -0,0 +1,18 @@
#ifndef GETOPT_H
#define GETOPT_H
#ifdef __cplusplus
extern "C" {
#endif
extern int optind;
extern char* optarg;
extern int optopt;
int getopt(int argc, char* const argv[], const char* ostr);
#ifdef __cplusplus
}
#endif
#endif // GETOPT_H

View file

@ -0,0 +1,164 @@
/*
* 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.
*/
#include <stdio.h>
#include <stdlib.h>
#include "errors.h"
#include "EntryPoint.h"
#include "strUtils.h"
#include "ApiGen.h"
#include "TypeFactory.h"
#include "getopt.h"
const std::string SPEC_EXTENSION = std::string(".in");
const std::string ATTRIB_EXTENSION = std::string(".attrib");
const std::string TYPES_EXTENTION = std::string(".types");
void usage(const char *filename)
{
fprintf(stderr, "Usage: %s [options] <base name>\n", filename);
fprintf(stderr, "\t-h: This message\n");
fprintf(stderr, "\t-E <dir>: generate encoder into dir\n");
fprintf(stderr, "\t-D <dir>: generate decoder into dir\n");
fprintf(stderr, "\t-i: input dir, local directory by default\n");
fprintf(stderr, "\t-T : generate attribute template into the input directory\n\t\tno other files are generated\n");
fprintf(stderr, "\t-W : generate wrapper into dir\n");
}
int main(int argc, char *argv[])
{
std::string encoderDir = "";
std::string decoderDir = "";
std::string wrapperDir = "";
std::string inDir = ".";
bool generateAttributesTemplate = false;
int c;
while((c = getopt(argc, argv, "TE:D:i:hW:")) != -1) {
switch(c) {
case 'W':
wrapperDir = std::string(optarg);
break;
case 'T':
generateAttributesTemplate = true;
break;
case 'h':
usage(argv[0]);
exit(0);
break;
case 'E':
encoderDir = std::string(optarg);
break;
case 'D':
decoderDir = std::string(optarg);
break;
case 'i':
inDir = std::string(optarg);
break;
case ':':
fprintf(stderr, "Missing argument !!\n");
// fall through
default:
usage(argv[0]);
exit(0);
}
}
if (optind >= argc) {
fprintf(stderr, "Usage: %s [options] <base name> \n", argv[0]);
return BAD_USAGE;
}
if (encoderDir.size() == 0 &&
decoderDir.size() == 0 &&
generateAttributesTemplate == false &&
wrapperDir.size() == 0) {
fprintf(stderr, "No output specified - aborting\n");
return BAD_USAGE;
}
std::string baseName = std::string(argv[optind]);
ApiGen apiEntries(baseName);
// init types;
std::string typesFilename = inDir + "/" + baseName + TYPES_EXTENTION;
if (TypeFactory::instance()->initFromFile(typesFilename) < 0) {
fprintf(stderr, "missing or error reading types file: %s...ignored\n", typesFilename.c_str());
}
std::string filename = inDir + "/" + baseName + SPEC_EXTENSION;
if (apiEntries.readSpec(filename) < 0) {
perror(filename.c_str());
return BAD_SPEC_FILE;
}
if (generateAttributesTemplate) {
apiEntries.genAttributesTemplate(inDir + "/" + baseName + ATTRIB_EXTENSION);
exit(0);
}
std::string attribFileName = inDir + "/" + baseName + ATTRIB_EXTENSION;
if (apiEntries.readAttributes(attribFileName) < 0) {
perror(attribFileName.c_str());
fprintf(stderr, "failed to parse attributes\n");
exit(1);
}
if (encoderDir.size() != 0) {
apiEntries.genOpcodes(encoderDir + "/" + baseName + "_opcodes.h");
apiEntries.genContext(encoderDir + "/" + baseName + "_client_context.h", ApiGen::CLIENT_SIDE);
apiEntries.genContextImpl(encoderDir + "/" + baseName + "_client_context.cpp", ApiGen::CLIENT_SIDE);
apiEntries.genProcTypes(encoderDir + "/" + baseName + "_client_proc.h", ApiGen::CLIENT_SIDE);
apiEntries.genFuncTable(encoderDir + "/" + baseName + "_ftable.h", ApiGen::CLIENT_SIDE);
apiEntries.genEntryPoints(encoderDir + "/" + baseName + "_entry.cpp", ApiGen::CLIENT_SIDE);
apiEntries.genEncoderHeader(encoderDir + "/" + baseName + "_enc.h");
apiEntries.genEncoderImpl(encoderDir + "/" + baseName + "_enc.cpp");
}
if (decoderDir.size() != 0) {
apiEntries.genOpcodes(decoderDir + "/" + baseName + "_opcodes.h");
apiEntries.genProcTypes(decoderDir + "/" + baseName + "_server_proc.h", ApiGen::SERVER_SIDE);
apiEntries.genContext(decoderDir + "/" + baseName + "_server_context.h", ApiGen::SERVER_SIDE);
apiEntries.genContextImpl(decoderDir + "/" + baseName + "_server_context.cpp", ApiGen::SERVER_SIDE);
apiEntries.genDecoderHeader(decoderDir + "/" + baseName + "_dec.h");
apiEntries.genDecoderImpl(decoderDir + "/" + baseName + "_dec.cpp");
}
if (wrapperDir.size() != 0) {
apiEntries.genProcTypes(wrapperDir + "/" + baseName + "_wrapper_proc.h", ApiGen::WRAPPER_SIDE);
apiEntries.genContext(wrapperDir + "/" + baseName + "_wrapper_context.h", ApiGen::WRAPPER_SIDE);
apiEntries.genContextImpl(wrapperDir + "/" + baseName + "_wrapper_context.cpp", ApiGen::WRAPPER_SIDE);
apiEntries.genEntryPoints(wrapperDir + "/" + baseName + "_wrapper_entry.cpp", ApiGen::WRAPPER_SIDE);
}
#ifdef DEBUG_DUMP
int withPointers = 0;
printf("%d functions found\n", int(apiEntries.size()));
for (int i = 0; i < apiEntries.size(); i++) {
if (apiEntries[i].hasPointers()) {
withPointers++;
apiEntries[i].print();
}
}
fprintf(stdout, "%d entries has poitners\n", withPointers);
#endif
}

View file

@ -0,0 +1,49 @@
/*
* 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.
*/
#include "strUtils.h"
using namespace std;
std::string getNextToken(const std::string & str, size_t pos, size_t * last, const std::string & delim)
{
if (str.size() == 0 || pos >= str.size()) return "";
pos = str.find_first_not_of(WHITESPACE, pos);
if (pos == std::string::npos) return "";
*last = str.find_first_of(delim, pos);
if (*last == std::string::npos) *last = str.size();
std::string retval = str.substr(pos, *last - pos);
retval = trim(retval);
return retval;
}
std::string trim(const string & str)
{
string result;
string::size_type start = str.find_first_not_of(WHITESPACE, 0);
string::size_type end = str.find_last_not_of(WHITESPACE);
if (start == string::npos || end == string::npos) {
result = string("");
} else {
result = str.substr(start, end - start + 1);
}
return result;
}

View file

@ -0,0 +1,33 @@
/*
* 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.
*/
#ifndef STR_UTILS_H_
#define STR_UTILS_H_
#include <string>
#include <sstream>
#define WHITESPACE " \t\n"
std::string trim(const std::string & str);
std::string getNextToken(const std::string & str, size_t pos, size_t * last, const std::string & delim);
template <class T> std::string inline toString(const T& t) {
std::stringstream ss;
ss << t;
return ss.str();
}
#endif

View file

@ -0,0 +1,129 @@
#!/bin/sh
# Copyright 2014 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.
#
set -e
export LANG=C
export LC_ALL=C
PROGDIR=$(dirname "$0")
PROGNAME=$(basename "$0")
fatal () {
echo "ERROR: $@"
exit 1
}
OPT_EMUGEN=
OPT_HELP=
OPT_OUT_DIR=
OPT_TOOL=
for OPT; do
OPTARG=$(expr "x$OPT" : "x[^=]*=\\(.*\\)" || true)
case $OPT in
--help|-h|-?)
OPT_HELP=true
;;
--emugen=*)
OPT_EMUGEN=$OPTARG
;;
--out-dir=*)
OPT_OUT_DIR=$OPTARG
;;
--tool=*)
OPT_TOOL=$OPTARG
;;
-*)
fatal "Invalid option '$OPT', see --help."
;;
*)
fatal "This script doesn't take arguments, see --help."
;;
esac
done
if [ "$OPT_HELP" ]; then
cat <<EOF
Usage: $PROGNAME [options]
Run the emugen test suite. This scripts looks for sub-directories
named t.<number>/input, and uses them as input to 'emugen'. It then
compares the output to t.<number>/expected/ content.
Valid options:
--help|-h|-? Print this help.
--out-dir=<dir> Generate outputs into <dir>.
--emugen=<program> Emugen program path, if not in path.
--tool=<tool> Launch visual diff tool in case of differences.
EOF
exit 0
fi
# Find emugen program
EMUGEN=
if [ "$OPT_EMUGEN" ]; then
EMUGEN=$OPT_EMUGEN
else
EMUGEN=$(which emugen 2>/dev/null || true)
if [ -z "$EMUGEN" ]; then
fatal "Cannot find 'emugen' program in PATH, use --emugen=<program> option."
fi
echo "Auto-config: --emugen=$EMUGEN"
fi
if [ ! -f "$EMUGEN" ]; then
fatal "Emugen program doesn't exist: $EMUGEN"
fi
# Create output directory.
OUT_DIR=
if [ "$OPT_OUT_DIR" ]; then
OUT_DIR=$OPT_OUT_DIR
else
OUT_DIR=/tmp/$USER-emugen-testing
echo "Auto-config: --out-dir=$OUT_DIR"
fi
mkdir -p "$OUT_DIR" && rm -rf "$OUT_DIR/emugen"
OUT_DIR=$OUT_DIR/emugen
# Find test directories
TEST_DIRS=$(cd "$PROGDIR" && find . -name "t.*" | sed -e 's|^\./||')
for TEST_DIR in $TEST_DIRS; do
IN=$PROGDIR/$TEST_DIR/input
PREFIXES=$(cd $IN && find . -name "*.in" | sed -e 's|^\./||g' -e 's|\.in$||g')
OUT=$OUT_DIR/$TEST_DIR
mkdir -p "$OUT/encoder"
mkdir -p "$OUT/decoder"
mkdir -p "$OUT/wrapper"
for PREFIX in $PREFIXES; do
echo "Processing $IN/foo.*"
$EMUGEN -i "$PROGDIR/$TEST_DIR/input" -D "$OUT/decoder" -E "$OUT/encoder" -W "$OUT/wrapper" $PREFIX
done
if ! diff -qr "$PROGDIR/$TEST_DIR/expected" "$OUT"; then
if [ "$OPT_TOOL" ]; then
$OPT_TOOL "$PROGDIR/$TEST_DIR/expected" "$OUT"
else
echo "ERROR: Invalid differences between actual and expected output!"
diff -burN "$PROGDIR/$TEST_DIR/expected" "$OUT"
exit 1
fi
fi
done
echo "All good!"
exit 0

View file

@ -0,0 +1,128 @@
// Generated Code - DO NOT EDIT !!
// generated by 'emugen'
#include <string.h>
#include "foo_opcodes.h"
#include "foo_dec.h"
#include "ProtocolUtils.h"
#include "ChecksumCalculatorThreadInfo.h"
#include <stdio.h>
typedef unsigned int tsize_t; // Target "size_t", which is 32-bit for now. It may or may not be the same as host's size_t when emugen is compiled.
#ifdef OPENGL_DEBUG_PRINTOUT
# define DEBUG(...) do { if (emugl_cxt_logger) { emugl_cxt_logger(__VA_ARGS__); } } while(0)
#else
# define DEBUG(...) ((void)0)
#endif
#ifdef CHECK_GLERROR
# define SET_LASTCALL(name) sprintf(lastCall, #name)
#else
# define SET_LASTCALL(name) ((void)0)
#endif
using namespace emugl;
size_t foo_decoder_context_t::decode(void *buf, size_t len, IOStream *stream)
{
size_t pos = 0;
if (len < 8) return pos;
unsigned char *ptr = (unsigned char *)buf;
bool unknownOpcode = false;
#ifdef CHECK_GL_ERROR
char lastCall[256] = {0};
#endif
while ((len - pos >= 8) && !unknownOpcode) {
uint32_t opcode = *(uint32_t *)ptr;
size_t packetLen = *(uint32_t *)(ptr + 4);
if (len - pos < packetLen) return pos;
bool useChecksum = ChecksumCalculatorThreadInfo::getVersion() > 0;
size_t checksumSize = 0;
if (useChecksum) {
checksumSize = ChecksumCalculatorThreadInfo::checksumByteSize();
}
switch(opcode) {
case OP_fooAlphaFunc: {
FooInt var_func = Unpack<FooInt,uint32_t>(ptr + 8);
FooFloat var_ref = Unpack<FooFloat,uint32_t>(ptr + 8 + 4);
if (useChecksum) {
ChecksumCalculatorThreadInfo::validOrDie(ptr, 8 + 4 + 4, ptr + 8 + 4 + 4, checksumSize,
"8 + 4 + 4::decode, OP_foo_decoder_context_t: GL checksumCalculator failure\n");
}
DEBUG("foo(%p): fooAlphaFunc(%d %f )\n", stream,var_func, var_ref);
this->fooAlphaFunc(var_func, var_ref);
SET_LASTCALL("fooAlphaFunc");
break;
}
case OP_fooIsBuffer: {
uint32_t size_stuff __attribute__((unused)) = Unpack<uint32_t,uint32_t>(ptr + 8);
InputBuffer inptr_stuff(ptr + 8 + 4, size_stuff);
if (useChecksum) {
ChecksumCalculatorThreadInfo::validOrDie(ptr, 8 + 4 + size_stuff, ptr + 8 + 4 + size_stuff, checksumSize,
"8 + 4 + size_stuff::decode, OP_foo_decoder_context_t: GL checksumCalculator failure\n");
}
size_t totalTmpSize = sizeof(FooBoolean);
totalTmpSize += checksumSize;
unsigned char *tmpBuf = stream->alloc(totalTmpSize);
DEBUG("foo(%p): fooIsBuffer(%p(%u) )\n", stream,(void*)(inptr_stuff.get()), size_stuff);
*(FooBoolean *)(&tmpBuf[0]) = this->fooIsBuffer((void*)(inptr_stuff.get()));
if (useChecksum) {
ChecksumCalculatorThreadInfo::writeChecksum(&tmpBuf[0], totalTmpSize - checksumSize, &tmpBuf[totalTmpSize - checksumSize], checksumSize);
}
stream->flush();
SET_LASTCALL("fooIsBuffer");
break;
}
case OP_fooUnsupported: {
uint32_t size_params __attribute__((unused)) = Unpack<uint32_t,uint32_t>(ptr + 8);
InputBuffer inptr_params(ptr + 8 + 4, size_params);
if (useChecksum) {
ChecksumCalculatorThreadInfo::validOrDie(ptr, 8 + 4 + size_params, ptr + 8 + 4 + size_params, checksumSize,
"8 + 4 + size_params::decode, OP_foo_decoder_context_t: GL checksumCalculator failure\n");
}
DEBUG("foo(%p): fooUnsupported(%p(%u) )\n", stream,(void*)(inptr_params.get()), size_params);
this->fooUnsupported((void*)(inptr_params.get()));
SET_LASTCALL("fooUnsupported");
break;
}
case OP_fooDoEncoderFlush: {
FooInt var_param = Unpack<FooInt,uint32_t>(ptr + 8);
if (useChecksum) {
ChecksumCalculatorThreadInfo::validOrDie(ptr, 8 + 4, ptr + 8 + 4, checksumSize,
"8 + 4::decode, OP_foo_decoder_context_t: GL checksumCalculator failure\n");
}
DEBUG("foo(%p): fooDoEncoderFlush(%d )\n", stream,var_param);
this->fooDoEncoderFlush(var_param);
SET_LASTCALL("fooDoEncoderFlush");
break;
}
case OP_fooTakeConstVoidPtrConstPtr: {
uint32_t size_param __attribute__((unused)) = Unpack<uint32_t,uint32_t>(ptr + 8);
InputBuffer inptr_param(ptr + 8 + 4, size_param);
if (useChecksum) {
ChecksumCalculatorThreadInfo::validOrDie(ptr, 8 + 4 + size_param, ptr + 8 + 4 + size_param, checksumSize,
"8 + 4 + size_param::decode, OP_foo_decoder_context_t: GL checksumCalculator failure\n");
}
DEBUG("foo(%p): fooTakeConstVoidPtrConstPtr(%p(%u) )\n", stream,(const void* const*)(inptr_param.get()), size_param);
this->fooTakeConstVoidPtrConstPtr((const void* const*)(inptr_param.get()));
SET_LASTCALL("fooTakeConstVoidPtrConstPtr");
break;
}
default:
unknownOpcode = true;
} //switch
if (!unknownOpcode) {
pos += packetLen;
ptr += packetLen;
}
} // while
return pos;
}

View file

@ -0,0 +1,18 @@
// Generated Code - DO NOT EDIT !!
// generated by 'emugen'
#ifndef GUARD_foo_decoder_context_t
#define GUARD_foo_decoder_context_t
#include "IOStream.h"
#include "foo_server_context.h"
struct foo_decoder_context_t : public foo_server_context_t {
size_t decode(void *buf, size_t bufsize, IOStream *stream);
};
#endif // GUARD_foo_decoder_context_t

View file

@ -0,0 +1,14 @@
// Generated Code - DO NOT EDIT !!
// generated by 'emugen'
#ifndef __GUARD_foo_opcodes_h_
#define __GUARD_foo_opcodes_h_
#define OP_fooAlphaFunc 200
#define OP_fooIsBuffer 201
#define OP_fooUnsupported 202
#define OP_fooDoEncoderFlush 203
#define OP_fooTakeConstVoidPtrConstPtr 204
#define OP_last 205
#endif

View file

@ -0,0 +1,20 @@
// Generated Code - DO NOT EDIT !!
// generated by 'emugen'
#include <string.h>
#include "foo_server_context.h"
#include <stdio.h>
int foo_server_context_t::initDispatchByName(void *(*getProc)(const char *, void *userData), void *userData)
{
fooAlphaFunc = (fooAlphaFunc_server_proc_t) getProc("fooAlphaFunc", userData);
fooIsBuffer = (fooIsBuffer_server_proc_t) getProc("fooIsBuffer", userData);
fooUnsupported = (fooUnsupported_server_proc_t) getProc("fooUnsupported", userData);
fooDoEncoderFlush = (fooDoEncoderFlush_server_proc_t) getProc("fooDoEncoderFlush", userData);
fooTakeConstVoidPtrConstPtr = (fooTakeConstVoidPtrConstPtr_server_proc_t) getProc("fooTakeConstVoidPtrConstPtr", userData);
return 0;
}

View file

@ -0,0 +1,22 @@
// Generated Code - DO NOT EDIT !!
// generated by 'emugen'
#ifndef __foo_server_context_t_h
#define __foo_server_context_t_h
#include "foo_server_proc.h"
#include "foo_types.h"
struct foo_server_context_t {
fooAlphaFunc_server_proc_t fooAlphaFunc;
fooIsBuffer_server_proc_t fooIsBuffer;
fooUnsupported_server_proc_t fooUnsupported;
fooDoEncoderFlush_server_proc_t fooDoEncoderFlush;
fooTakeConstVoidPtrConstPtr_server_proc_t fooTakeConstVoidPtrConstPtr;
virtual ~foo_server_context_t() {}
int initDispatchByName( void *(*getProc)(const char *name, void *userData), void *userData);
};
#endif

View file

@ -0,0 +1,21 @@
// Generated Code - DO NOT EDIT !!
// generated by 'emugen'
#ifndef __foo_server_proc_t_h
#define __foo_server_proc_t_h
#include "foo_types.h"
#include "emugl/common/logging.h"
#ifndef foo_APIENTRY
#define foo_APIENTRY
#endif
typedef void (foo_APIENTRY *fooAlphaFunc_server_proc_t) (FooInt, FooFloat);
typedef FooBoolean (foo_APIENTRY *fooIsBuffer_server_proc_t) (void*);
typedef void (foo_APIENTRY *fooUnsupported_server_proc_t) (void*);
typedef void (foo_APIENTRY *fooDoEncoderFlush_server_proc_t) (FooInt);
typedef void (foo_APIENTRY *fooTakeConstVoidPtrConstPtr_server_proc_t) (const void* const*);
#endif

View file

@ -0,0 +1,20 @@
// Generated Code - DO NOT EDIT !!
// generated by 'emugen'
#include <string.h>
#include "foo_client_context.h"
#include <stdio.h>
int foo_client_context_t::initDispatchByName(void *(*getProc)(const char *, void *userData), void *userData)
{
fooAlphaFunc = (fooAlphaFunc_client_proc_t) getProc("fooAlphaFunc", userData);
fooIsBuffer = (fooIsBuffer_client_proc_t) getProc("fooIsBuffer", userData);
fooUnsupported = (fooUnsupported_client_proc_t) getProc("fooUnsupported", userData);
fooDoEncoderFlush = (fooDoEncoderFlush_client_proc_t) getProc("fooDoEncoderFlush", userData);
fooTakeConstVoidPtrConstPtr = (fooTakeConstVoidPtrConstPtr_client_proc_t) getProc("fooTakeConstVoidPtrConstPtr", userData);
return 0;
}

View file

@ -0,0 +1,27 @@
// Generated Code - DO NOT EDIT !!
// generated by 'emugen'
#ifndef __foo_client_context_t_h
#define __foo_client_context_t_h
#include "foo_client_proc.h"
#include "foo_types.h"
struct foo_client_context_t {
fooAlphaFunc_client_proc_t fooAlphaFunc;
fooIsBuffer_client_proc_t fooIsBuffer;
fooUnsupported_client_proc_t fooUnsupported;
fooDoEncoderFlush_client_proc_t fooDoEncoderFlush;
fooTakeConstVoidPtrConstPtr_client_proc_t fooTakeConstVoidPtrConstPtr;
virtual ~foo_client_context_t() {}
typedef foo_client_context_t *CONTEXT_ACCESSOR_TYPE(void);
static void setContextAccessor(CONTEXT_ACCESSOR_TYPE *f);
int initDispatchByName( void *(*getProc)(const char *name, void *userData), void *userData);
virtual void setError(unsigned int error){ (void)error; };
virtual unsigned int getError(){ return 0; };
};
#endif

View file

@ -0,0 +1,21 @@
// Generated Code - DO NOT EDIT !!
// generated by 'emugen'
#ifndef __foo_client_proc_t_h
#define __foo_client_proc_t_h
#include "foo_types.h"
#include "emugl/common/logging.h"
#ifndef foo_APIENTRY
#define foo_APIENTRY
#endif
typedef void (foo_APIENTRY *fooAlphaFunc_client_proc_t) (void * ctx, FooInt, FooFloat);
typedef FooBoolean (foo_APIENTRY *fooIsBuffer_client_proc_t) (void * ctx, void*);
typedef void (foo_APIENTRY *fooUnsupported_client_proc_t) (void * ctx, void*);
typedef void (foo_APIENTRY *fooDoEncoderFlush_client_proc_t) (void * ctx, FooInt);
typedef void (foo_APIENTRY *fooTakeConstVoidPtrConstPtr_client_proc_t) (void * ctx, const void* const*);
#endif

View file

@ -0,0 +1,153 @@
// Generated Code - DO NOT EDIT !!
// generated by 'emugen'
#include <memory>
#include <string.h>
#include "foo_opcodes.h"
#include "foo_enc.h"
#include <stdio.h>
namespace {
void enc_unsupported()
{
ALOGE("Function is unsupported\n");
}
void fooAlphaFunc_enc(void *self , FooInt func, FooFloat ref)
{
foo_encoder_context_t *ctx = (foo_encoder_context_t *)self;
IOStream *stream = ctx->m_stream;
ChecksumCalculator *checksumCalculator = ctx->m_checksumCalculator;
bool useChecksum = checksumCalculator->getVersion() > 0;
unsigned char *ptr;
unsigned char *buf;
const size_t sizeWithoutChecksum = 8 + 4 + 4;
const size_t checksumSize = checksumCalculator->checksumByteSize();
const size_t totalSize = sizeWithoutChecksum + checksumSize;
buf = stream->alloc(totalSize);
ptr = buf;
int tmp = OP_fooAlphaFunc;memcpy(ptr, &tmp, 4); ptr += 4;
memcpy(ptr, &totalSize, 4); ptr += 4;
memcpy(ptr, &func, 4); ptr += 4;
memcpy(ptr, &ref, 4); ptr += 4;
if (useChecksum) checksumCalculator->addBuffer(buf, ptr-buf);
if (useChecksum) checksumCalculator->writeChecksum(ptr, checksumSize); ptr += checksumSize;
}
FooBoolean fooIsBuffer_enc(void *self , void* stuff)
{
foo_encoder_context_t *ctx = (foo_encoder_context_t *)self;
IOStream *stream = ctx->m_stream;
ChecksumCalculator *checksumCalculator = ctx->m_checksumCalculator;
bool useChecksum = checksumCalculator->getVersion() > 0;
const unsigned int __size_stuff = (4 * sizeof(float));
unsigned char *ptr;
unsigned char *buf;
const size_t sizeWithoutChecksum = 8 + __size_stuff + 1*4;
const size_t checksumSize = checksumCalculator->checksumByteSize();
const size_t totalSize = sizeWithoutChecksum + checksumSize;
buf = stream->alloc(totalSize);
ptr = buf;
int tmp = OP_fooIsBuffer;memcpy(ptr, &tmp, 4); ptr += 4;
memcpy(ptr, &totalSize, 4); ptr += 4;
*(unsigned int *)(ptr) = __size_stuff; ptr += 4;
memcpy(ptr, stuff, __size_stuff);ptr += __size_stuff;
if (useChecksum) checksumCalculator->addBuffer(buf, ptr-buf);
if (useChecksum) checksumCalculator->writeChecksum(ptr, checksumSize); ptr += checksumSize;
FooBoolean retval;
stream->readback(&retval, 1);
if (useChecksum) checksumCalculator->addBuffer(&retval, 1);
if (useChecksum) {
std::unique_ptr<unsigned char[]> checksumBuf(new unsigned char[checksumSize]);
stream->readback(checksumBuf.get(), checksumSize);
if (!checksumCalculator->validate(checksumBuf.get(), checksumSize)) {
ALOGE("fooIsBuffer: GL communication error, please report this issue to b.android.com.\n");
abort();
}
}
return retval;
}
void fooDoEncoderFlush_enc(void *self , FooInt param)
{
foo_encoder_context_t *ctx = (foo_encoder_context_t *)self;
IOStream *stream = ctx->m_stream;
ChecksumCalculator *checksumCalculator = ctx->m_checksumCalculator;
bool useChecksum = checksumCalculator->getVersion() > 0;
unsigned char *ptr;
unsigned char *buf;
const size_t sizeWithoutChecksum = 8 + 4;
const size_t checksumSize = checksumCalculator->checksumByteSize();
const size_t totalSize = sizeWithoutChecksum + checksumSize;
buf = stream->alloc(totalSize);
ptr = buf;
int tmp = OP_fooDoEncoderFlush;memcpy(ptr, &tmp, 4); ptr += 4;
memcpy(ptr, &totalSize, 4); ptr += 4;
memcpy(ptr, &param, 4); ptr += 4;
if (useChecksum) checksumCalculator->addBuffer(buf, ptr-buf);
if (useChecksum) checksumCalculator->writeChecksum(ptr, checksumSize); ptr += checksumSize;
stream->flush();
}
void fooTakeConstVoidPtrConstPtr_enc(void *self , const void* const* param)
{
foo_encoder_context_t *ctx = (foo_encoder_context_t *)self;
IOStream *stream = ctx->m_stream;
ChecksumCalculator *checksumCalculator = ctx->m_checksumCalculator;
bool useChecksum = checksumCalculator->getVersion() > 0;
const unsigned int __size_param = ;
unsigned char *ptr;
unsigned char *buf;
const size_t sizeWithoutChecksum = 8 + __size_param + 1*4;
const size_t checksumSize = checksumCalculator->checksumByteSize();
const size_t totalSize = sizeWithoutChecksum + checksumSize;
buf = stream->alloc(totalSize);
ptr = buf;
int tmp = OP_fooTakeConstVoidPtrConstPtr;memcpy(ptr, &tmp, 4); ptr += 4;
memcpy(ptr, &totalSize, 4); ptr += 4;
*(unsigned int *)(ptr) = __size_param; ptr += 4;
memcpy(ptr, param, __size_param);ptr += __size_param;
if (useChecksum) checksumCalculator->addBuffer(buf, ptr-buf);
if (useChecksum) checksumCalculator->writeChecksum(ptr, checksumSize); ptr += checksumSize;
}
} // namespace
foo_encoder_context_t::foo_encoder_context_t(IOStream *stream, ChecksumCalculator *checksumCalculator)
{
m_stream = stream;
m_checksumCalculator = checksumCalculator;
this->fooAlphaFunc = &fooAlphaFunc_enc;
this->fooIsBuffer = &fooIsBuffer_enc;
this->fooUnsupported = (fooUnsupported_client_proc_t) &enc_unsupported;
this->fooDoEncoderFlush = &fooDoEncoderFlush_enc;
this->fooTakeConstVoidPtrConstPtr = &fooTakeConstVoidPtrConstPtr_enc;
}

View file

@ -0,0 +1,23 @@
// Generated Code - DO NOT EDIT !!
// generated by 'emugen'
#ifndef GUARD_foo_encoder_context_t
#define GUARD_foo_encoder_context_t
#include "IOStream.h"
#include "ChecksumCalculator.h"
#include "foo_client_context.h"
#include "fooUtils.h"
#include "fooBase.h"
struct foo_encoder_context_t : public foo_client_context_t {
IOStream *m_stream;
ChecksumCalculator *m_checksumCalculator;
foo_encoder_context_t(IOStream *stream, ChecksumCalculator *checksumCalculator);
};
#endif // GUARD_foo_encoder_context_t

View file

@ -0,0 +1,53 @@
// Generated Code - DO NOT EDIT !!
// generated by 'emugen'
#include <stdio.h>
#include <stdlib.h>
#include "foo_client_context.h"
#ifndef GL_TRUE
extern "C" {
void fooAlphaFunc(FooInt func, FooFloat ref);
FooBoolean fooIsBuffer(void* stuff);
void fooUnsupported(void* params);
void fooDoEncoderFlush(FooInt param);
void fooTakeConstVoidPtrConstPtr(const void* const* param);
};
#endif
#ifndef GET_CONTEXT
static foo_client_context_t::CONTEXT_ACCESSOR_TYPE *getCurrentContext = NULL;
void foo_client_context_t::setContextAccessor(CONTEXT_ACCESSOR_TYPE *f) { getCurrentContext = f; }
#define GET_CONTEXT foo_client_context_t * ctx = getCurrentContext()
#endif
void fooAlphaFunc(FooInt func, FooFloat ref)
{
GET_CONTEXT;
ctx->fooAlphaFunc(ctx, func, ref);
}
FooBoolean fooIsBuffer(void* stuff)
{
GET_CONTEXT;
if (n == NULL) { LOG(ERROR) << "NULL stuff"; return; }
return ctx->fooIsBuffer(ctx, stuff);
}
void fooUnsupported(void* params)
{
GET_CONTEXT;
ctx->fooUnsupported(ctx, params);
}
void fooDoEncoderFlush(FooInt param)
{
GET_CONTEXT;
ctx->fooDoEncoderFlush(ctx, param);
}
void fooTakeConstVoidPtrConstPtr(const void* const* param)
{
GET_CONTEXT;
ctx->fooTakeConstVoidPtrConstPtr(ctx, param);
}

View file

@ -0,0 +1,20 @@
// Generated Code - DO NOT EDIT !!
// generated by 'emugen'
#ifndef __foo_client_ftable_t_h
#define __foo_client_ftable_t_h
static const struct _foo_funcs_by_name {
const char *name;
void *proc;
} foo_funcs_by_name[] = {
{"fooAlphaFunc", (void*)fooAlphaFunc},
{"fooIsBuffer", (void*)fooIsBuffer},
{"fooUnsupported", (void*)fooUnsupported},
{"fooDoEncoderFlush", (void*)fooDoEncoderFlush},
{"fooTakeConstVoidPtrConstPtr", (void*)fooTakeConstVoidPtrConstPtr},
};
static const int foo_num_funcs = sizeof(foo_funcs_by_name) / sizeof(struct _foo_funcs_by_name);
#endif

View file

@ -0,0 +1,14 @@
// Generated Code - DO NOT EDIT !!
// generated by 'emugen'
#ifndef __GUARD_foo_opcodes_h_
#define __GUARD_foo_opcodes_h_
#define OP_fooAlphaFunc 200
#define OP_fooIsBuffer 201
#define OP_fooUnsupported 202
#define OP_fooDoEncoderFlush 203
#define OP_fooTakeConstVoidPtrConstPtr 204
#define OP_last 205
#endif

View file

@ -0,0 +1,20 @@
// Generated Code - DO NOT EDIT !!
// generated by 'emugen'
#include <string.h>
#include "foo_wrapper_context.h"
#include <stdio.h>
int foo_wrapper_context_t::initDispatchByName(void *(*getProc)(const char *, void *userData), void *userData)
{
fooAlphaFunc = (fooAlphaFunc_wrapper_proc_t) getProc("fooAlphaFunc", userData);
fooIsBuffer = (fooIsBuffer_wrapper_proc_t) getProc("fooIsBuffer", userData);
fooUnsupported = (fooUnsupported_wrapper_proc_t) getProc("fooUnsupported", userData);
fooDoEncoderFlush = (fooDoEncoderFlush_wrapper_proc_t) getProc("fooDoEncoderFlush", userData);
fooTakeConstVoidPtrConstPtr = (fooTakeConstVoidPtrConstPtr_wrapper_proc_t) getProc("fooTakeConstVoidPtrConstPtr", userData);
return 0;
}

View file

@ -0,0 +1,25 @@
// Generated Code - DO NOT EDIT !!
// generated by 'emugen'
#ifndef __foo_wrapper_context_t_h
#define __foo_wrapper_context_t_h
#include "foo_server_proc.h"
#include "foo_types.h"
struct foo_wrapper_context_t {
fooAlphaFunc_wrapper_proc_t fooAlphaFunc;
fooIsBuffer_wrapper_proc_t fooIsBuffer;
fooUnsupported_wrapper_proc_t fooUnsupported;
fooDoEncoderFlush_wrapper_proc_t fooDoEncoderFlush;
fooTakeConstVoidPtrConstPtr_wrapper_proc_t fooTakeConstVoidPtrConstPtr;
virtual ~foo_wrapper_context_t() {}
typedef foo_wrapper_context_t *CONTEXT_ACCESSOR_TYPE(void);
static void setContextAccessor(CONTEXT_ACCESSOR_TYPE *f);
int initDispatchByName( void *(*getProc)(const char *name, void *userData), void *userData);
};
#endif

View file

@ -0,0 +1,52 @@
// Generated Code - DO NOT EDIT !!
// generated by 'emugen'
#include <stdio.h>
#include <stdlib.h>
#include "foo_wrapper_context.h"
#ifndef GL_TRUE
extern "C" {
void fooAlphaFunc(FooInt func, FooFloat ref);
FooBoolean fooIsBuffer(void* stuff);
void fooUnsupported(void* params);
void fooDoEncoderFlush(FooInt param);
void fooTakeConstVoidPtrConstPtr(const void* const* param);
};
#endif
#ifndef GET_CONTEXT
static foo_wrapper_context_t::CONTEXT_ACCESSOR_TYPE *getCurrentContext = NULL;
void foo_wrapper_context_t::setContextAccessor(CONTEXT_ACCESSOR_TYPE *f) { getCurrentContext = f; }
#define GET_CONTEXT foo_wrapper_context_t * ctx = getCurrentContext()
#endif
void fooAlphaFunc(FooInt func, FooFloat ref)
{
GET_CONTEXT;
ctx->fooAlphaFunc( func, ref);
}
FooBoolean fooIsBuffer(void* stuff)
{
GET_CONTEXT;
return ctx->fooIsBuffer( stuff);
}
void fooUnsupported(void* params)
{
GET_CONTEXT;
ctx->fooUnsupported( params);
}
void fooDoEncoderFlush(FooInt param)
{
GET_CONTEXT;
ctx->fooDoEncoderFlush( param);
}
void fooTakeConstVoidPtrConstPtr(const void* const* param)
{
GET_CONTEXT;
ctx->fooTakeConstVoidPtrConstPtr( param);
}

View file

@ -0,0 +1,21 @@
// Generated Code - DO NOT EDIT !!
// generated by 'emugen'
#ifndef __foo_wrapper_proc_t_h
#define __foo_wrapper_proc_t_h
#include "foo_types.h"
#include "emugl/common/logging.h"
#ifndef foo_APIENTRY
#define foo_APIENTRY
#endif
typedef void (foo_APIENTRY *fooAlphaFunc_wrapper_proc_t) (FooInt, FooFloat);
typedef FooBoolean (foo_APIENTRY *fooIsBuffer_wrapper_proc_t) (void*);
typedef void (foo_APIENTRY *fooUnsupported_wrapper_proc_t) (void*);
typedef void (foo_APIENTRY *fooDoEncoderFlush_wrapper_proc_t) (FooInt);
typedef void (foo_APIENTRY *fooTakeConstVoidPtrConstPtr_wrapper_proc_t) (const void* const*);
#endif

View file

@ -0,0 +1,15 @@
GLOBAL
base_opcode 200
encoder_headers "fooUtils.h" "fooBase.h"
fooIsBuffer
dir stuff in
len stuff (4 * sizeof(float))
param_check stuff if (n == NULL) { LOG(ERROR) << "NULL stuff"; return; }
fooUnsupported
dir params in
flag unsupported
fooDoEncoderFlush
flag flushOnEncode

View file

@ -0,0 +1,5 @@
FOO_ENTRY(void, fooAlphaFunc, FooInt func, FooFloat ref)
FOO_ENTRY(FooBoolean, fooIsBuffer, void* stuff)
FOO_ENTRY(void, fooUnsupported, void* params)
FOO_ENTRY(void, fooDoEncoderFlush, FooInt param)
FOO_ENTRY(void, fooTakeConstVoidPtrConstPtr, const void* const* param)

View file

@ -0,0 +1,10 @@
FooBoolean 8 %d
FooInt 32 %d
FooShort 16 %d
FooFloat 32 %f
FooEnum 32 %08x
FooVoid 0 %x
FooChar 8 %d
FooChar* 32 0x%08x
void* 32 0x%08x
void*const* 32 0x%08x