File indexing completed on 2024-06-16 04:26:01

0001 package mso.generator;
0002 
0003 import java.io.File;
0004 import java.io.FileWriter;
0005 import java.io.IOException;
0006 import java.io.PrintWriter;
0007 import java.util.regex.Matcher;
0008 import java.util.regex.Pattern;
0009 
0010 import org.eclipse.jdt.annotation.Nullable;
0011 
0012 import mso.generator.utils.Choice;
0013 import mso.generator.utils.Limitation;
0014 import mso.generator.utils.MSO;
0015 import mso.generator.utils.Member;
0016 import mso.generator.utils.Option;
0017 import mso.generator.utils.Struct;
0018 import mso.generator.utils.Type;
0019 import mso.generator.utils.TypeRegistry;
0020 
0021 public class QtApiGenerator {
0022 
0023     public class QtApiConfiguration {
0024         @Nullable
0025         public final String namespace;
0026         public final String basename;
0027         public final String outputdir;
0028         public boolean createHeader;
0029 
0030         QtApiConfiguration(@Nullable String namespace, String basename,
0031                 String outputdir) {
0032             this.namespace = namespace;
0033             this.basename = basename;
0034             this.outputdir = outputdir;
0035         }
0036     }
0037 
0038     final public QtApiConfiguration config;
0039 
0040     final private String generatedWarning = "/* This code was generated by msoscheme (http://gitorious.org/msoscheme) */";
0041 
0042     public QtApiGenerator(@Nullable String namespace, String basename,
0043             String outputdir) {
0044         config = new QtApiConfiguration(namespace, basename, outputdir);
0045     }
0046 
0047     void generate(MSO mso) throws IOException {
0048         FileWriter fout;
0049         if (config.createHeader) {
0050             fout = new FileWriter(
0051                     config.outputdir + File.separator + config.basename + ".h");
0052         } else {
0053             fout = new FileWriter(config.outputdir + File.separator
0054                     + config.basename + ".cpp");
0055         }
0056         PrintWriter out = new PrintWriter(fout);
0057         out.println(generatedWarning);
0058         if (config.createHeader) {
0059             out.println("#ifndef " + config.basename.toUpperCase() + "_H");
0060             out.println("#define " + config.basename.toUpperCase() + "_H");
0061         }
0062         out.println("#include \"leinput.h\"");
0063         out.println("namespace " + config.namespace + "{");
0064 
0065         for (Struct s : mso.structs) {
0066             out.println("class " + s.name + ";");
0067         }
0068         for (Struct s : mso.structs) {
0069             printStructureClassDeclaration(out, s);
0070         }
0071 
0072         if (config.createHeader) {
0073             out.println("} // close namespace");
0074             out.println("#endif");
0075             out.close();
0076             fout = new FileWriter(config.outputdir + File.separator
0077                     + config.basename + ".cpp");
0078             out = new PrintWriter(fout);
0079             out.println(generatedWarning);
0080             out.println("#include \"" + config.basename + ".h\"");
0081         }
0082 
0083         for (Struct s : mso.structs) {
0084             printStructureDefinition(out, s);
0085         }
0086 
0087         if (!config.createHeader) {
0088             out.println("}");// close namespace
0089         }
0090         out.close();
0091         fout.close();
0092     }
0093 
0094     private static void printStructureClassDeclaration(PrintWriter out, Struct s) {
0095         if (s.size == -1) {
0096             out.println("class " + s.name + " : public ParsedObject {");
0097         } else {
0098             out.println(
0099                     "class " + s.name + " : public FixedSizeParsedObject {");
0100         }
0101         out.println("private:");
0102         if (s.size == -1) {
0103             out.println("public:");
0104             out.println("    " + s.name + "() {}");
0105             out.println("    explicit " + s.name
0106                     + "(const char* data, const quint32 maxsize);");
0107         } else {
0108             out.println("    static const quint32 _size;");
0109             out.println("public:");
0110             out.println(
0111                     "    static inline quint32 getSize() { return _size; }");
0112             out.println("    " + s.name + "() {}");
0113             out.println("    " + s.name
0114                     + "(const char* data, quint32/*ignored*/ = 0);// "
0115                     + (s.size / 8) + " bytes");
0116         }
0117         for (Member m : s.members) {
0118             printMemberDeclaration(out, m, s.name);
0119         }
0120         out.println("};");
0121     }
0122 
0123     private String definitionPrefix() {
0124         final String namespace = config.namespace;
0125         return (namespace == null || namespace.length() == 0) ? ""
0126                 : config.namespace + "::";
0127     }
0128 
0129     private void printStructureDefinition(PrintWriter out, Struct s) {
0130         // constructor
0131         String c = definitionPrefix() + s.name + "::";
0132         if (s.size == -1) {
0133             out.println(c + s.name + "(const char* _d, quint32 _maxsize) {");
0134         } else {
0135             out.println("const quint32 " + c + "_size = " + (s.size / 8) + ";");
0136             out.println(c + s.name + "(const char* _d, quint32/*ignored*/) {");
0137         }
0138         out.println("    quint32 _position = 0;");
0139         out.println("    quint32 _msize;");
0140         int bytepos = 0;
0141         String sp;
0142         for (Member m : s.members) {
0143             sp = "    ";
0144             int msize = getSize(m);
0145             String condition = m.condition;
0146             if (m.isSimple && condition != null) {
0147                 condition = fixForMemberName(condition);
0148                 out.println(
0149                         sp + "bool _has_" + m.name + " = " + condition + ";");
0150                 condition = "_has_" + m.name;
0151             }
0152             if (condition != null) {
0153                 condition = fixForMemberName(condition);
0154                 out.println(sp + "if (" + condition + ") {");
0155                 sp = "        ";
0156             }
0157             if (msize != -1 && s.size == -1) {
0158                 out.print(sp + "if (_position + " + msize);
0159                 if (m.isOptional) {
0160                     sp += "    ";
0161                     out.println(" <= _maxsize) {");
0162                 } else {
0163                     out.println(" > _maxsize) return;");
0164                 }
0165             }
0166             bytepos = printMemberParser(out, sp, s, m, bytepos);
0167             printLimitationCheck(out, sp, m.name, m);
0168             out.println(sp + "_position += _msize;");
0169             while (sp.length() > 4) {
0170                 sp = sp.substring(sp.length() - 4);
0171                 out.println(sp + "}");
0172             }
0173         }
0174         if (s.size == -1) {
0175             out.println("   ParsedObject::init(_d, _position);");
0176         } else {
0177             out.println("   FixedSizeParsedObject::init(_d);");
0178         }
0179         out.println("}");
0180         // access functions
0181         for (Member m : s.members) {
0182             if (m.isArray && m.isStruct) {
0183                 // printStructArrayAccessor(out, s, m);
0184             } else if (m.isChoice) {
0185                 printChoiceAccessor(out, s, m);
0186             }
0187         }
0188     }
0189 
0190     private static int printMemberParser(PrintWriter out, String sp, Struct s,
0191             Member m, int bytepos) {
0192         if (m.isArray) {
0193             if (m.isSimple) {
0194                 printSimpleArrayMemberParser(out, sp, s, m);
0195             } else {
0196                 printStructArrayMemberParser(out, sp, s, m);
0197             }
0198             if (m.isChoice) {
0199                 throw new Error("There should be no choice in an array.");
0200             }
0201         } else {
0202             if (m.isSimple) {
0203                 return printSimpleMemberParser(out, sp, s, m, bytepos);
0204             } else if (m.isStruct) {
0205                 printStructMemberParser(out, sp, s, m);
0206             } else if (m.isChoice) {
0207                 printChoiceMemberParser(out, sp, s, m);
0208             }
0209         }
0210         return 0;
0211     }
0212 
0213     private static int printSimpleMemberParser(PrintWriter out, String sp, Struct s,
0214             Member m, int bytepos) {
0215         out.println(sp + "m_" + m.name + " = read" + m.type().name
0216                 + ((bytepos > 0) ? "_" + String.valueOf(bytepos) : "")
0217                 + "(_d + _position);");
0218         int size = m.type().size / 8;
0219         if (bytepos != 0 && ((bytepos + m.type().size) % 8) == 0) {
0220             size += 1;
0221         }
0222         bytepos = (bytepos + m.type().size) % 8;
0223         out.println(sp + "_msize = " + size + ";");
0224         return bytepos;
0225     }
0226 
0227     /** return size in bytes **/
0228     private static int getSize(Member m) {
0229         int size = -1;
0230         if (m.count != null && m.isArray && m.type().size != -1) {
0231             try {
0232                 size = m.type().size * Integer.parseInt(m.count) / 8;
0233             } catch (NumberFormatException e) {
0234                 size = -1;
0235             }
0236         } else if (m.size != null) {
0237             try {
0238                 size = Integer.parseInt(m.size);
0239             } catch (NumberFormatException e) {
0240                 size = -1;
0241             }
0242         } else if (!m.isArray) {
0243             return m.type().size / 8;
0244         }
0245         return size;
0246     }
0247 
0248     private static void printSimpleArrayMemberParser(PrintWriter out, String sp,
0249             Struct s, Member m) {
0250         if (m.type().size % 8 != 0) {
0251             throw new Error(
0252                     "only arrays of types with a size of a multiple of 8 bits are allowed.");
0253         }
0254         // get the expression for the size
0255         int size = getSize(m);
0256         String count = String.valueOf(size * 8 / m.type().size);
0257         if (size == -1) {
0258             if (m.count != null) {
0259                 count = m.count;
0260             } else {
0261                 count = "(" + m.size + ")/" + (m.type().size / 8);
0262             }
0263         } else {
0264             if (size % (m.type().size / 8) != 0) {
0265                 throw new Error(
0266                         "array size must be a multiple of the size of the type for "
0267                                 + m.type().name + " and size " + size);
0268             }
0269         }
0270         count = fixForMemberName(count);
0271         String type = getTypeName(m.type());
0272         if ("quint8".equals(type))
0273             type = "char";
0274         out.println(sp + "m_" + m.name + " = MSOCastArray<" + type + ">((const "
0275                 + type + "*)(_d + _position), " + count + ");");
0276         out.println(
0277                 sp + "_msize = (" + count + ")*" + (m.type().size / 8) + ";");
0278     }
0279 
0280     private static void printStructArrayMemberParser(PrintWriter out, String sp,
0281             Struct s, Member m) {
0282         final String mcount = m.count;
0283         if (mcount != null) {
0284             String size = "_maxsize - _position, ";
0285             String count = fixForMemberName(mcount);
0286             if (m.type().size != -1) {
0287                 size = (m.type().size / 8) + " * " + count + ", ";
0288             }
0289             out.println(sp + "m_" + m.name + " = MSOArray<" + m.type().name
0290                     + ">(_d + _position, " + size + count + ");");
0291             out.println(sp + "if (m_" + m.name + ".getCount() != " + count
0292                     + ") return;");
0293         } else if (m.size != null) {
0294             String size = fixForMemberName(m.size);
0295             out.println(
0296                     sp + "if (_maxsize - _position < " + size + ") return;");
0297             out.println(sp + "m_" + m.name + " = MSOArray<" + m.type().name
0298                     + ">(_d + _position, " + size + ");");
0299             out.println(sp + "if (m_" + m.name + ".getSize() != " + size
0300                     + ") return;");
0301         } else {
0302             out.println(sp + "m_" + m.name + " = MSOArray<" + m.type().name
0303                     + ">(_d + _position, _maxsize - _position);");
0304             out.println(sp + "if (!m_" + m.name + ".isValid()) return;");
0305         }
0306         out.println(sp + "_msize = m_" + m.name + ".getSize();");
0307     }
0308 
0309     private static void printStructMemberParser(PrintWriter out, String sp, Struct s,
0310             Member m) {
0311         if (m.type().size == -1) {
0312             out.println(sp + "m_" + m.name + " = " + m.type().name
0313                     + "(_d + _position, _maxsize - _position);");
0314         } else {
0315             out.println(sp + "m_" + m.name + " = " + m.type().name
0316                     + "(_d + _position);");
0317         }
0318         if (m.isOptional) {
0319             out.println(sp + "_msize = (m_" + m.name + ".isPresent()) ?m_"
0320                     + m.name + ".getSize() :0;");
0321         } else if (m.condition != null) {
0322             out.println(sp + "if (!m_" + m.name + ".isPresent()) return;");
0323             out.println(sp + "_msize = m_" + m.name + ".getSize();");
0324         } else {
0325             out.println(sp + "if (!m_" + m.name + ".isValid()) return;");
0326             out.println(sp + "_msize = m_" + m.name + ".getSize();");
0327         }
0328     }
0329 
0330     private static void printChoiceMemberParser(PrintWriter out, String sp, Struct s,
0331             Member m) {
0332         Choice c = (Choice) m.type();
0333         // try all options until one has non-zero size
0334         // String s = "";
0335         boolean first = true;
0336         String sp2 = sp;
0337         for (Option o : c.options) {
0338             Type t = o.type;
0339             if (!first) {
0340                 out.println(sp + "if (_msize == 0) {");
0341             }
0342             String name = "m_" + m.name + "._" + t.name;
0343             if (t.size == -1) {
0344                 out.println(sp2 + name + " = " + t.name
0345                         + "(_d + _position, _maxsize - _position);");
0346                 out.println(sp2 + "_msize = " + name + ".getSize();");
0347             } else {
0348                 out.println(sp2 + name + " = " + t.name + "(_d + _position);");
0349                 out.println(sp2 + "_msize = (" + name + ".isValid()) ?" + t.name
0350                         + "::getSize() : 0;");
0351             }
0352             if (!first) {
0353                 out.println(sp + "}");
0354             } else {
0355                 sp2 = sp + "    ";
0356             }
0357             first = false;
0358         }
0359         if (!m.isOptional) {
0360             out.println(sp + "if (_msize == 0) return;");
0361         }
0362     }
0363 
0364     private static String getTypeName(Type t) {
0365         TypeRegistry r = t.registry;
0366         if (t instanceof Choice) {
0367             return t.name;
0368         } else if (t == r.bit) {
0369             return "bool";
0370         } else if (t == r.uint2 || t == r.uint3 || t == r.uint4 || t == r.uint5
0371                 || t == r.uint6 || t == r.uint7 || t == r.uint8) {
0372             return "quint8";
0373         } else if (t == r.uint9 || t == r.uint12 || t == r.uint13
0374                 || t == r.uint14 || t == r.uint15 || t == r.uint16) {
0375             return "quint16";
0376         } else if (t == r.uint20 || t == r.uint30 || t == r.uint32) {
0377             return "quint32";
0378         } else if (t == r.int16) {
0379             return "qint16";
0380         } else if (t == r.int32) {
0381             return "qint32";
0382         }
0383         return t.name;
0384     }
0385 
0386     private void printChoiceAccessor(PrintWriter out, Type s,
0387             Member m) {
0388         Choice c = (Choice) m.type();
0389         out.println("namespace " + config.namespace + " {");
0390         for (Option o : c.options) {
0391             String t = o.type.name;
0392             out.println("    template <> " + t + " " + s.name + "::C_" + m.name
0393                     + "::get<" + t + ">() const {");
0394             out.println("        return _" + t + ";");
0395 
0396             out.println("    }");
0397             out.println("    template <> bool " + s.name + "::C_" + m.name
0398                     + "::is<" + t + ">() const {");
0399             out.println("        return _" + t + ".isValid();");
0400 
0401             out.println("    }");
0402         }
0403         out.println("}");
0404     }
0405 
0406     private static void printMemberDeclaration(PrintWriter out, Member m,
0407             String className) {
0408         String t = getTypeName(m.type());
0409         if (m.isArray) {
0410             if (m.isSimple) {
0411                 if ("quint8".equals(t))
0412                     t = "char";
0413                 out.println("private:");
0414                 out.println("    MSOCastArray<" + t + "> m_" + m.name + ";");
0415                 out.println("public:");
0416                 out.println("    const MSOCastArray<" + t + ">& " + m.name
0417                         + "() const { return m_" + m.name + "; }");
0418             }
0419             if (m.isStruct || m.isChoice) {
0420                 if (m.type().size == -1) {
0421                     out.println("private:");
0422                     out.println("    MSOArray<" + t + "> m_" + m.name + ";");
0423                     out.println("public:");
0424                     out.println("    inline const MSOArray<" + t + ">& "
0425                             + m.name + "() const { return m_" + m.name + "; }");
0426                 } else {
0427                     out.println("private:");
0428                     out.println("    MSOArray<" + t + "> m_" + m.name + ";");
0429                     out.println("public:");
0430                     out.println("    inline const MSOArray<" + t + ">& "
0431                             + m.name + "() const { return m_" + m.name + "; }");
0432                 }
0433             }
0434         } else if (m.isChoice) {
0435             Choice c = (Choice) m.type();
0436             out.println("public:");
0437             out.println("    class C_" + m.name + " {");
0438             out.println("    friend class " + className + ";");
0439             out.println("    private:");
0440             for (Option o : c.options) {
0441                 Type ct = o.type;
0442                 out.println("        " + ct.name + " _" + ct.name + ";");
0443             }
0444             out.println("    public:");
0445             out.println("        template <typename A> A get() const;");
0446             out.println("        template <typename A> bool is() const;");
0447             out.println("    };");
0448             out.println("private:");
0449             out.println("    C_" + m.name + " m_" + m.name + ";");
0450             out.println("public:");
0451             out.println("    C_" + m.name + " " + m.name
0452                     + "() const { return m_" + m.name + "; }");
0453         } else {
0454             if (m.isOptional || m.condition != null) {
0455                 if (m.isSimple) {
0456                     t = "MSOBasicNullable<" + t + ">";
0457                 } else {
0458                     t = "MSONullable<" + t + ">";
0459                 }
0460             }
0461             out.println("private:");
0462             out.println("    " + t + " m_" + m.name + ";");
0463             out.println("public:");
0464             if (!m.isSimple || (m.isOptional || m.condition != null)) {
0465                 t = "const " + t + "&";
0466             }
0467             out.println("    inline " + t + " " + m.name
0468                     + "() const { return m_" + m.name + "; }");
0469         }
0470     }
0471 
0472     private static void printLimitationCheck(PrintWriter out, String s, String name,
0473             Member m) {
0474         if (m.type() instanceof Choice)
0475             return;
0476         for (Limitation l : m.limitations) {
0477             String mname = l.name;
0478             if (!"".equals(mname)) {
0479                 mname = name + "." + mname;
0480             } else {
0481                 mname = name;
0482             }
0483             if (!m.isStruct) {
0484                 if (m.condition == null) {
0485                     mname = "((" + getTypeName(m.type()) + ")m_" + mname + ")";
0486                 } else {
0487                     mname = "((" + getTypeName(m.type()) + ")*m_" + mname + ")";
0488                 }
0489             }
0490 
0491             String condition = QtParserGenerator.getLimit(mname, l);
0492             if (m.isStruct) {
0493                 condition = fixForMemberName(condition);
0494             }
0495             out.println(s + "if (!(" + condition + ")) {");
0496             out.println(s + "     return;");
0497             out.println(s + "}");
0498         }
0499     }
0500 
0501     private static boolean isNumber(String n) {
0502         boolean isNumber = true;
0503         try {
0504             Integer.decode(n);
0505         } catch (NumberFormatException e) {
0506             isNumber = false;
0507         }
0508         return isNumber;
0509     }
0510 
0511     private final static Pattern pattern1 = Pattern
0512             .compile("(?<=\\W)([a-zA-Z]\\w*)(?=\\W|$)");
0513     private final static Pattern pattern2 = Pattern
0514             .compile("(^[a-zA-Z]\\w*)(?=\\W|$)");
0515 
0516     private static String fix(String condition, Pattern regex) {
0517         Matcher m = regex.matcher(condition);
0518         StringBuffer sb = new StringBuffer();
0519         while (m.find()) {
0520             String var = m.group(1);
0521             if (!isNumber(var)) {
0522                 var = var + "()";
0523             }
0524             m.appendReplacement(sb, var);
0525         }
0526         m.appendTail(sb);
0527         return sb.toString();
0528     }
0529 
0530     private static String fixForMemberName(String condition) {
0531         if (condition.startsWith("_has_")) {
0532             return condition;
0533         }
0534         condition = fix(condition, pattern1);
0535         condition = fix(condition, pattern2);
0536         condition = condition.replaceAll("false\\(\\)", "false");
0537         condition = condition.replaceAll("true\\(\\)", "true");
0538         return condition;
0539     }
0540 }