📄 generator.java
字号:
/* $Id: Generator.java,v 1.4 2001/06/30 01:56:55 raif Exp $
*
* Copyright (C) 1997-2001 The Cryptix Foundation Limited. All rights reserved.
*
* Use, modification, copying and distribution of this software is subject to
* the terms and conditions of the Cryptix General Licence. You should have
* received a copy of the Cryptix General Licence along with this library; if
* not, you can download a copy from http://www.cryptix.org/
*/
package cryptix.asn1.tool;
import cryptix.asn1.analysis.DepthFirstAdapter;
import cryptix.asn1.lang.NodeInfo;
import cryptix.asn1.node.*;
import org.apache.log4j.Category;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.Date;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;
/**
* A class to interpret ASN.1 specifications and generate Java source code.
*
* @version $Revision: 1.4 $
* @author Raif S. Naffah
*/
public class Generator extends DepthFirstAdapter {
// Constants and vars
// -------------------------------------------------------------------------
private static Category cat = Category.getInstance(Generator.class);
private static final int NOT_GENERATING = 0;
private static final int GENERATING = 1;
private static final int REFERENCE_ONLY = 2;
/** The output stream where code is generated. */
private PrintWriter pw;
Interpreter ast;
int indent = 0;
int state;
String moduleName; // name of the package wehere class belongs
String pkgName; // name (dotted string) of mapped package wehere class belongs
String className; // name of the class we're generating
LinkedList data; // vector of element data objects
String lower; // sequence/set element name
String type; // sequence/set element type
String tag; // tag constructor for a sequence/set element
// Constructor(s)
// -------------------------------------------------------------------------
/**
* Constructs a code generator for a designated language operating on the
* designated AST.
*
* @param ast the parsed AST of the ASN.1 definitions as a
* <tt>cryptix.asn1.tools.Interpreter</tt>.
* @param languageID the constant defining a programming language in which
* to generate the source objects that will map to the ASN.1 constructs.
*/
public Generator(Interpreter ast) {
this.ast = ast;
data = new LinkedList();
}
// Class methods
// -------------------------------------------------------------------------
public static final String toJava(String name) {
cat.debug("==> toJava("+String.valueOf(name)+")");
if (name != null) {
// 1. replace multiple hyphens with 1 hyphen
int i = name.indexOf("--");
while (i > -1) {
name = name.substring(0, i) + name.substring(i+1);
i = name.indexOf("--");
}
// 2. replace hyphen-character with uppercase character
i = name.indexOf("-");
while (i > -1) {
name = name.substring(0, i) + toProper(name.substring(i+1));
i = name.indexOf("-");
}
}
cat.debug("<== toJava() --> "+String.valueOf(name));
return name;
}
private static final String toProper(String name) {
if (name.equals(""))
return name;
return name.substring(0, 1).toUpperCase() + name.substring(1);
}
// Instance methods
// -------------------------------------------------------------------------
/**
* Generates Java code for all components in all modules interpreted so
* far by the underlying Interpreter.<p>
*
* Gets all modules from the underlying Interpreter, and repeatedly invokes
* the method with same name and 3 arguments.
*
* @param destination the directory where generated files will be stored.
* @param dict a <tt>java.util.Map</tt> that maps package names to ASN.1
* module names. If a module name is not found in this map, then the same
* name string will be used as the name of its enclosing package.
* @exception IOException if an I/O error occurs during (a) the creation of
* a new file (that will contain generated code) or its parent directory,
* (b) the construction of a FileWriter object wrapping a new file, or
* (c) the process of generating the code per-se.
*/
public void generate(File destination, Map dict)
throws IOException {
Map modules = ast.getModules();
Set keys = modules.keySet();
Object[] moduleNames = keys.toArray();
int limit = moduleNames.length;
for (int i = 0; i < limit; i++)
generate(destination, (String) moduleNames[i], dict);
}
/**
* Generates code for all constructs of a designated ASN.1 module, including
* a convenience <tt>Module</tt> Java interface which shall group all OIDs
* defined in that designated ASN.1 module.<p>
*
* If any file at the same path location as any one that should be
* generated already exists, it is over-written.
*
* @param destination the directory where generated files will be stored.
* @param module the name of the ASN.1 module, which will become the name of
* the package containg the new classes.
* @param dict a <tt>java.util.Map</tt> that maps package names to ASN.1
* module names. If a module name is not found in this map, then the same
* name string will be used as the name of its enclosing package.
* @exception IOException if an I/O error occurs during (a) the creation of
* a new file (that will contain generated code) or its parent directory,
* (b) the construction of a FileWriter object wrapping a new file, or
* (c) the process of generating the code per-se.
*/
public void generate(File destination, String module, Map dict)
throws IOException {
Map moduleTypes = ast.getComponents(module);
Set types = moduleTypes.keySet();
cat.debug("Types defined in module "+String.valueOf(module)+":\n"+String.valueOf(moduleTypes));
Object[] typeNames = types.toArray();
for (int i = 0, limit = typeNames.length; i < limit; i++) {
String type = (String) typeNames[i];
if (isPermissibleType(type)) {
Node n = (Node) moduleTypes.get(type);
generate(destination, module, dict, toJava(type), n);
}
}
generateModule(destination, module, dict);
}
/**
* Generates code for a designated ASN.1 construct.<p>
*
* If a file at the same path location as the one that should be generated
* already exists, it is over-written.
*
* @param destination the directory where generated files will be stored.
* @param module the name of the ASN.1 module, which will become the name of
* the package containg the new class.
* @param type the name of the defined ASN.1 type within the designated
* module, which will become the name of the Java Class (or other language
* equivalent) --defined within the designated package-- to generate.
* @param dict a <tt>java.util.Map</tt> that maps package names to ASN.1
* module names. If a module name is not found in this map, then the same
* name string will be used as the name of its enclosing package.
* @exception IOException if an I/O error occurs during (a) the creation of
* the new file (that will contain the generated code) or its parent
* directory, (b) the construction of a FileWriter object wrapping this new
* file, or (c) the process of generating the code per-se.
* @exception IllegalArgumentException if the type string does not start with
* an uppercase, or contains a dot.
*/
public void generate(File destination, String module, String type, Map dict)
throws IOException {
if (!isPermissibleType(type))
throw new IllegalArgumentException();
Node n = ast.getComponent(module, type);
generate(destination, module, dict, type, n);
}
// Overriden DepthFirstAdapter methods
// -------------------------------------------------------------------------
public void defaultIn(Node node) {
indent++;
String indentation = "";
for (int i = 0; i < indent; i++)
indentation += " ";
cat.debug(indentation+"--> "+node.getClass().getName());
}
public void defaultOut(Node node) {
String indentation = "";
for (int i = 0; i < indent; i++)
indentation += " ";
cat.debug(indentation+"<-- "+node.getClass().getName()+": "+node);
indent--;
}
public void inAIntegerBuiltInType(AIntegerBuiltInType node) {
defaultIn(node);
switch (state) {
case GENERATING:
boolean isPublic = ast.isPublic(moduleName, className);
outBuiltInClass(isPublic, className, "INTEGER");
state = REFERENCE_ONLY;
break;
}
}
public void outAIntegerBuiltInType(AIntegerBuiltInType node) {
defaultOut(node);
switch (state) {
case GENERATING:
break;
case REFERENCE_ONLY:
type = "INTEGER";
break;
}
}
public void outANamedNumber(ANamedNumber node) {
defaultOut(node);
switch (state) {
case GENERATING:
break;
case REFERENCE_ONLY:
String var = node.getLower().getText().trim();
Node n = node.getAuxNamedNum();
StringBuffer args = new StringBuffer("new ASNInteger(");
args.append("\"").append(className).append(".").append(var).append("\", ");
if (n instanceof APositiveAuxNamedNum) {
APositiveAuxNamedNum pann = (APositiveAuxNamedNum) n;
args.append("\"")
.append(pann.getNumber().getText().trim())
.append("\"");
} else if (n instanceof ANegativeAuxNamedNum) {
ANegativeAuxNamedNum nann = (ANegativeAuxNamedNum) n;
args.append("\"-")
.append(nann.getNumber().getText().trim())
.append("\"");
} else if (n instanceof ALowerAuxNamedNum) {
ALowerAuxNamedNum lann = (ALowerAuxNamedNum) n;
args.append(lann.getLower().getText().trim());
} else if (n instanceof AUpperAuxNamedNum) {
AUpperAuxNamedNum uann = (AUpperAuxNamedNum) n;
args.append(uann.getUpper().getText().trim())
.append(".")
.append(uann.getLower().getText().trim());
}
args.append(")");
outAttribute(className, var, args.toString());
break;
}
}
public void outANullType(ANullType node) {
defaultOut(node);
switch (state) {
case GENERATING:
break;
case REFERENCE_ONLY:
type = "NULL";
break;
}
}
public void inABooleanBuiltInType(ABooleanBuiltInType node) {
defaultIn(node);
switch (state) {
case GENERATING:
boolean isPublic = ast.isPublic(moduleName, className);
outBuiltInClass(isPublic, className, "BOOLEAN");
state = REFERENCE_ONLY;
break;
}
}
public void outABooleanBuiltInType(ABooleanBuiltInType node) {
defaultOut(node);
switch (state) {
case GENERATING:
break;
case REFERENCE_ONLY:
type = "BOOLEAN";
break;
}
}
public void inABitBuiltInType(ABitBuiltInType node) {
defaultIn(node);
switch (state) {
case GENERATING:
boolean isPublic = ast.isPublic(moduleName, className);
outBuiltInClass(isPublic, className, "BIT_STRING");
state = REFERENCE_ONLY;
break;
}
}
public void outABitBuiltInType(ABitBuiltInType node) {
defaultOut(node);
switch (state) {
case GENERATING:
break;
case REFERENCE_ONLY:
type = "BIT_STRING";
break;
}
}
public void inAOctetBuiltInType(AOctetBuiltInType node) {
defaultIn(node);
switch (state) {
case GENERATING:
boolean isPublic = ast.isPublic(moduleName, className);
outBuiltInClass(isPublic, className, "OCTET_STRING");
state = REFERENCE_ONLY;
break;
}
}
public void outAOctetBuiltInType(AOctetBuiltInType node) {
defaultOut(node);
switch (state) {
case GENERATING:
break;
case REFERENCE_ONLY:
type = "OCTET_STRING";
break;
}
}
public void inAAnyBuiltInType(AAnyBuiltInType node) {
defaultIn(node);
switch (state) {
case GENERATING:
boolean isPublic = ast.isPublic(moduleName, className);
outBuiltInClass(isPublic, className, "ANY");
state = REFERENCE_ONLY;
break;
}
}
public void outAAnyBuiltInType(AAnyBuiltInType node) {
defaultOut(node);
switch (state) {
case GENERATING:
break;
case REFERENCE_ONLY:
type = "ANY";
break;
}
}
public void inAOidBuiltInType(AOidBuiltInType node) {
defaultIn(node);
switch (state) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -