| 1 |
package mso.generator; |
| 2 |
|
| 3 |
import java.io.File; |
| 4 |
import java.io.FileWriter; |
| 5 |
import java.io.IOException; |
| 6 |
import java.io.PrintWriter; |
| 7 |
import java.util.regex.Matcher; |
| 8 |
import java.util.regex.Pattern; |
| 9 |
|
| 10 |
import mso.generator.utils.Choice; |
| 11 |
import mso.generator.utils.Limitation; |
| 12 |
import mso.generator.utils.MSO; |
| 13 |
import mso.generator.utils.Member; |
| 14 |
import mso.generator.utils.Option; |
| 15 |
import mso.generator.utils.Stream; |
| 16 |
import mso.generator.utils.Struct; |
| 17 |
import mso.generator.utils.TypeRegistry; |
| 18 |
|
| 19 |
public class QtParserGenerator { |
| 20 |
|
| 21 |
public class QtParserConfiguration { |
| 22 |
public String namespace; |
| 23 |
public String outputdir; |
| 24 |
public String basename; |
| 25 |
public boolean createHeader; |
| 26 |
public boolean enableXml; |
| 27 |
public boolean enableWriting; |
| 28 |
public boolean enableIntrospection; |
| 29 |
public boolean enableToString; |
| 30 |
public boolean enableStyleTextPropAtomFix; |
| 31 |
} |
| 32 |
|
| 33 |
final public QtParserConfiguration config = new QtParserConfiguration(); |
| 34 |
|
| 35 |
final private String generatedWarning = "/* This code was generated by msoscheme (http://gitorious.org/msoscheme) */"; |
| 36 |
|
| 37 |
void generate(MSO mso) throws IOException { |
| 38 |
FileWriter fout; |
| 39 |
if (config.createHeader) { |
| 40 |
fout = new FileWriter(config.outputdir + File.separator |
| 41 |
+ config.basename + ".h"); |
| 42 |
} else { |
| 43 |
fout = new FileWriter(config.outputdir + File.separator |
| 44 |
+ config.basename + ".cpp"); |
| 45 |
} |
| 46 |
PrintWriter out = new PrintWriter(fout); |
| 47 |
out.println(generatedWarning); |
| 48 |
if (config.createHeader) { |
| 49 |
out.println("#ifndef " + config.basename.toUpperCase() + "_H"); |
| 50 |
out.println("#define " + config.basename.toUpperCase() + "_H"); |
| 51 |
} |
| 52 |
out.println("#include <QString>"); |
| 53 |
out.println("#include <QByteArray>"); |
| 54 |
out.println("#include <QVector>"); |
| 55 |
out |
| 56 |
.println("#include <QSharedPointer>// replace with QScopedPointer when switching to Qt 4.6"); |
| 57 |
if (config.enableXml) { |
| 58 |
out.println("#include <QXmlStreamReader>"); |
| 59 |
} |
| 60 |
if (config.enableWriting) { |
| 61 |
out.println("#include \"leoutputstream.h\""); |
| 62 |
} |
| 63 |
if (config.enableIntrospection) { |
| 64 |
out.println("#include \"introspection.h\""); |
| 65 |
} |
| 66 |
out.println("class LEInputStream;"); |
| 67 |
out.println("namespace " + config.namespace + "{"); |
| 68 |
|
| 69 |
if (config.enableXml) { |
| 70 |
out.println("void skipToStartElement(QXmlStreamReader& in) {"); |
| 71 |
out.println(" do {"); |
| 72 |
out.println(" in.readNext();"); |
| 73 |
out.println(" } while (!in.atEnd() && !in.isStartElement());"); |
| 74 |
out.println("}"); |
| 75 |
} |
| 76 |
|
| 77 |
if (!config.enableIntrospection) { |
| 78 |
out.println("class StreamOffset {"); |
| 79 |
out.println("public:"); |
| 80 |
out.println(" virtual ~StreamOffset() {}"); |
| 81 |
out.println(" quint32 streamOffset;"); |
| 82 |
out.println("};"); |
| 83 |
} |
| 84 |
|
| 85 |
for (Struct s : mso.structs) { |
| 86 |
out.println("class " + s.name + ";"); |
| 87 |
out.println("void parse" + s.name + "(LEInputStream& in, " + s.name |
| 88 |
+ "& _s);"); |
| 89 |
if (config.enableXml) { |
| 90 |
out.println("void parse" + s.name + "(QXmlStreamReader& in, " |
| 91 |
+ s.name + "& _s);"); |
| 92 |
} |
| 93 |
if (config.enableWriting) { |
| 94 |
out.println("void write(const " + s.name |
| 95 |
+ "& v, LEOutputStream& out);"); |
| 96 |
} |
| 97 |
} |
| 98 |
|
| 99 |
for (Struct s : mso.structs) { |
| 100 |
printStructureClassDeclaration(out, s); |
| 101 |
} |
| 102 |
|
| 103 |
if (config.createHeader) { |
| 104 |
out.println("} // close namespace"); |
| 105 |
out.println("#endif"); |
| 106 |
out.close(); |
| 107 |
fout = new FileWriter(config.outputdir + File.separator |
| 108 |
+ config.basename + ".cpp"); |
| 109 |
out = new PrintWriter(fout); |
| 110 |
out.println(generatedWarning); |
| 111 |
out.println("#include \"" + config.basename + ".h\""); |
| 112 |
out.println("using namespace " + config.namespace + ";"); |
| 113 |
} |
| 114 |
out.println("#include \"leinputstream.h\""); |
| 115 |
|
| 116 |
if (config.enableIntrospection) { |
| 117 |
for (Struct s : mso.structs) { |
| 118 |
printStructureClassImplementation(out, s); |
| 119 |
} |
| 120 |
} |
| 121 |
|
| 122 |
for (Struct s : mso.structs) { |
| 123 |
printStructureParser(out, s); |
| 124 |
if (config.enableWriting) { |
| 125 |
printStructureWriter(out, s); |
| 126 |
} |
| 127 |
if (config.enableXml) { |
| 128 |
printStructureXmlParser(out, s); |
| 129 |
} |
| 130 |
} |
| 131 |
|
| 132 |
if (!config.createHeader) { |
| 133 |
out.println("}");// close namespace |
| 134 |
} |
| 135 |
|
| 136 |
if (config.enableIntrospection) { |
| 137 |
out |
| 138 |
.println("const Introspectable* parse(const QString& key, LEInputStream& in) {"); |
| 139 |
out.println(" const Introspectable* i = 0;"); |
| 140 |
boolean first = true; |
| 141 |
for (Stream s : mso.streams) { |
| 142 |
out.print(" "); |
| 143 |
if (first) { |
| 144 |
first = false; |
| 145 |
} else { |
| 146 |
out.print("} else "); |
| 147 |
} |
| 148 |
out.println("if (\"" + s.key + "\" == key) {"); // TODO: fix for |
| 149 |
// \001 and \005 |
| 150 |
// prefix |
| 151 |
out.println(" " + s.type + " *_t = new " + s.type |
| 152 |
+ "(0);"); |
| 153 |
out.println(" parse" + s.type + "(in, *_t);"); |
| 154 |
out.println(" i = _t;"); |
| 155 |
} |
| 156 |
out.println(" } else {"); |
| 157 |
out.println(" TODOS* _t = new TODOS(0);"); |
| 158 |
out.println(" parseTODOS(in, *_t);"); |
| 159 |
out.println(" i = _t;"); |
| 160 |
out.println(" }"); |
| 161 |
out.println(" return i;"); |
| 162 |
out.println("}"); |
| 163 |
} |
| 164 |
|
| 165 |
if (config.enableXml) { |
| 166 |
out |
| 167 |
.println("const QMap<QString,QSharedPointer<const Introspectable> > parse(QXmlStreamReader& in) {"); |
| 168 |
out |
| 169 |
.println(" QMap<QString,QSharedPointer<const Introspectable> > streams;"); |
| 170 |
out.println(" // skip until first element"); |
| 171 |
out.println(" while (!in.atEnd() && !in.isStartElement()) {"); |
| 172 |
out.println(" in.readNext();"); |
| 173 |
out.println(" }"); |
| 174 |
out.println(" if (!in.isStartElement()) {"); |
| 175 |
out.println(" return streams;"); |
| 176 |
out.println(" }"); |
| 177 |
out.println(" do {"); |
| 178 |
out.println(" in.readNext();"); |
| 179 |
out.println(" } while (!in.atEnd() && !in.isStartElement());"); |
| 180 |
out.println(" if (!in.isStartElement()) {"); |
| 181 |
out.println(" return streams;"); |
| 182 |
out.println(" }"); |
| 183 |
out.println(" do {"); |
| 184 |
out.println(" QString name = in.name().toString();"); |
| 185 |
out.println(" if (streams.contains(name)) {"); |
| 186 |
out.println(" streams.clear();"); |
| 187 |
out.println(" return streams;"); |
| 188 |
out.println(" }"); |
| 189 |
boolean first = true; |
| 190 |
for (Stream s : mso.streams) { |
| 191 |
out.print(" "); |
| 192 |
if (first) { |
| 193 |
first = false; |
| 194 |
} else { |
| 195 |
out.print("} else "); |
| 196 |
} |
| 197 |
out.println("if (\"" + s.key + "\" == name) {"); |
| 198 |
out |
| 199 |
.println(" QSharedPointer<Introspectable> _t(new " |
| 200 |
+ s.type + "(0));"); |
| 201 |
out.println(" parse" + s.type + "(in, *static_cast<" |
| 202 |
+ s.type + "*>(_t.data()));"); |
| 203 |
// out.println(" QSharedPointer<Introspectable> _t(new PowerPointStructs());"); |
| 204 |
// out.println(" parsePowerPointStructs(in, *static_cast<PowerPointStructs*>(_t.data()));"); |
| 205 |
out.println(" streams[name] = _t;"); |
| 206 |
} |
| 207 |
out.println(" } else { // unknown stream should be binary"); |
| 208 |
out |
| 209 |
.println(" QSharedPointer<Introspectable> _t(new TODOS(0));"); |
| 210 |
out |
| 211 |
.println(" parseTODOS(in, *static_cast<TODOS*>(_t.data()));"); |
| 212 |
out.println(" streams[name] = _t;"); |
| 213 |
out.println(" }"); |
| 214 |
out.println(" do {"); |
| 215 |
out.println(" in.readNext();"); |
| 216 |
out.println(" } while (in.isWhitespace());"); |
| 217 |
out.println(" } while (in.isStartElement());"); |
| 218 |
out.println(" qDebug() << in.tokenType();"); |
| 219 |
out.println(" if (!in.isEndElement()) {"); |
| 220 |
out |
| 221 |
.println(" qDebug() << \"parsing error: not at end of an element\";"); |
| 222 |
out.println(" streams.clear();"); |
| 223 |
out.println(" }"); |
| 224 |
out.println(" in.readNext();"); |
| 225 |
out.println(" if (!in.isEndDocument()) {"); |
| 226 |
out |
| 227 |
.println(" qDebug() << \"parsing error: not at end of xml\";"); |
| 228 |
out.println(" streams.clear();"); |
| 229 |
out.println(" }"); |
| 230 |
out.println(" return streams;"); |
| 231 |
out.println("}"); |
| 232 |
|
| 233 |
out |
| 234 |
.println("void serialize(const Introspectable* i, const QString& key, LEOutputStream& out) {"); |
| 235 |
first = true; |
| 236 |
for (Stream s : mso.streams) { |
| 237 |
out.print(" "); |
| 238 |
if (first) { |
| 239 |
first = false; |
| 240 |
} else { |
| 241 |
out.print("} else "); |
| 242 |
} |
| 243 |
out.println("if (\"" + s.key + "\" == key) {"); // TODO: fix for |
| 244 |
// \001 and \005 |
| 245 |
// prefix |
| 246 |
out.println(" write(*static_cast<const " + s.type |
| 247 |
+ "*>(i), out);"); |
| 248 |
} |
| 249 |
out.println(" } else {"); |
| 250 |
out.println(" write(*static_cast<const TODOS*>(i), out);"); |
| 251 |
out.println(" }"); |
| 252 |
out.println("}"); |
| 253 |
} |
| 254 |
out.close(); |
| 255 |
fout.close(); |
| 256 |
} |
| 257 |
|
| 258 |
private void printStructureParser(PrintWriter out, Struct s) { |
| 259 |
out.print("void "); |
| 260 |
if (config.namespace != null && config.namespace.length() > 0) { |
| 261 |
out.print(config.namespace + "::"); |
| 262 |
} |
| 263 |
out.println("parse" + s.name + "(LEInputStream& in, " + s.name |
| 264 |
+ "& _s) {"); |
| 265 |
out.println(" _s.streamOffset = in.getPosition();"); |
| 266 |
if (s.containsKnownLengthArrayMember) { |
| 267 |
out.println(" int _c;"); |
| 268 |
} |
| 269 |
if (s.containsArrayMember || s.containsOptionalMember |
| 270 |
|| s.containsChoice) { |
| 271 |
out.println(" LEInputStream::Mark _m;"); |
| 272 |
} |
| 273 |
if (s.containsOptionalMember) { |
| 274 |
out.println(" bool _possiblyPresent;"); |
| 275 |
} |
| 276 |
if (s.containsUnknownLengthArrayMember) { |
| 277 |
out.println(" bool _atend;"); |
| 278 |
} |
| 279 |
for (Member m : s.members) { |
| 280 |
if (config.enableStyleTextPropAtomFix |
| 281 |
&& s.name.equals("StyleTextPropAtom") |
| 282 |
&& m.name.equals("todo")) { |
| 283 |
break; |
| 284 |
} |
| 285 |
printStructureMemberParser(out, s.name, m); |
| 286 |
if (m.type().name.contains("RecordHeader")) { |
| 287 |
// out.println("qDebug() << in.getPosition()<<\" \"<<\"" + |
| 288 |
// s.name |
| 289 |
// + "\"<<_s.rh.toString();"); |
| 290 |
} |
| 291 |
if (config.enableStyleTextPropAtomFix |
| 292 |
&& s.name.equals("TextContainer") && m.name.equals("style")) { |
| 293 |
styleTextPropAtomFix2(out); |
| 294 |
} |
| 295 |
} |
| 296 |
out.println("}"); |
| 297 |
} |
| 298 |
|
| 299 |
private void printStructureXmlParser(PrintWriter out, Struct s) { |
| 300 |
out.println("void parse" + s.name + "(QXmlStreamReader& in, " + s.name |
| 301 |
+ "& _s) {"); |
| 302 |
out.println(" in.readNext();"); |
| 303 |
for (Member m : s.members) { |
| 304 |
printStructureMemberXmlParser(out, m); |
| 305 |
} |
| 306 |
/* |
| 307 |
* out.println(" int depth = 0;"); |
| 308 |
* out.println(" while (!in.atEnd()) {"); |
| 309 |
* out.println(" if (type == QXmlStreamReader::StartElement) {"); |
| 310 |
* out.println(" depth++;"); |
| 311 |
* out.println(" } else if (type == QXmlStreamReader::EndElement " |
| 312 |
* + "&& --depth < 0) {"); out.println(" return;"); |
| 313 |
* out.println(" }"); |
| 314 |
* out.println(" type = in.readNext();"); out.println(" }"); |
| 315 |
*/ |
| 316 |
out.println("}"); |
| 317 |
|
| 318 |
} |
| 319 |
|
| 320 |
static private String prependStructureToExpression(String expression, |
| 321 |
String structureName) { |
| 322 |
if (expression.length() > 0) { |
| 323 |
Pattern p = Pattern.compile("([^.\\w])([.a-zA-Z])"); |
| 324 |
Matcher m = p.matcher(expression); |
| 325 |
expression = m.replaceAll("$1" + structureName + ".$2"); |
| 326 |
p = Pattern.compile("^([a-zA-Z])"); |
| 327 |
m = p.matcher(expression); |
| 328 |
expression = m.replaceAll(structureName + ".$1"); |
| 329 |
} |
| 330 |
return expression; |
| 331 |
} |
| 332 |
|
| 333 |
private void printStructureMemberParser(PrintWriter out, String structure, |
| 334 |
Member m) { |
| 335 |
String s = " "; |
| 336 |
String index = (m.count == null) ? "" : "[_i]"; |
| 337 |
if (m.condition != null) { |
| 338 |
String condition = prependStructureToExpression(m.condition, "_s"); |
| 339 |
if (!m.isStruct) { |
| 340 |
out.println(s + "_s._has_" + m.name + " = " + condition + ";"); |
| 341 |
out.println(s + "if (_s._has_" + m.name + ") {"); |
| 342 |
} else { |
| 343 |
out.println(s + "if (" + condition + ") {"); |
| 344 |
} |
| 345 |
s = s + " "; |
| 346 |
if (m.isStruct) { |
| 347 |
out.println(s + "_s." + m.name + " = QSharedPointer<" |
| 348 |
+ m.type().name + ">(new " + m.type().name + "(&_s));"); |
| 349 |
index = ".data()"; |
| 350 |
} |
| 351 |
} |
| 352 |
String parse; |
| 353 |
if (m.isStruct) { |
| 354 |
String star = (m.condition == null) ? "" : "*"; |
| 355 |
parse = "parse" + m.type().name + "(in, " + star + "_s." + m.name |
| 356 |
+ index + ");"; |
| 357 |
} else { |
| 358 |
parse = "_s." + m.name + index + " = in.read" + m.type().name |
| 359 |
+ "();"; |
| 360 |
} |
| 361 |
if (m.isChoice) { |
| 362 |
printChoiceParser(out, s, structure, m); |
| 363 |
return; |
| 364 |
} |
| 365 |
if (m.isArray && m.count == null) { |
| 366 |
if (m.size != null) { |
| 367 |
printFixedSizeArrayParser(out, s, m); |
| 368 |
} else { |
| 369 |
// array for which no size is given: parse items until one fails |
| 370 |
printVariableArrayParser(out, s, m); |
| 371 |
} |
| 372 |
return; |
| 373 |
} |
| 374 |
if (m.isOptional) { |
| 375 |
printOptionalMemberParser(out, s, m); |
| 376 |
return; |
| 377 |
} |
| 378 |
if (m.count != null) { |
| 379 |
String count = prependStructureToExpression(m.count, "_s"); |
| 380 |
out.println(s + "_c = " + count + ";"); |
| 381 |
} |
| 382 |
if (m.count != null) { |
| 383 |
if (!m.isStruct) { |
| 384 |
out.println(s + "_s." + m.name + ".resize(_c);"); |
| 385 |
} |
| 386 |
if (m.type() == m.registry.uint8) { // special case for |
| 387 |
// reading bytearrays quickly |
| 388 |
out.println(s + "in.readBytes(_s." + m.name + ");"); |
| 389 |
} else { |
| 390 |
out.println(s + "for (int _i=0; _i<_c; ++_i) {"); |
| 391 |
if (m.isStruct) { |
| 392 |
out.println(s + " _s." + m.name + ".append(" |
| 393 |
+ m.type().name + "(&_s));"); |
| 394 |
} |
| 395 |
out.println(s + " " + parse); |
| 396 |
printLimitationCheck(out, " ", "_s." + m.name + "[_i]", |
| 397 |
m); |
| 398 |
out.println(s + "}"); |
| 399 |
} |
| 400 |
} else { |
| 401 |
out.println(s + parse); |
| 402 |
printLimitationCheck(out, s, "_s." + m.name, m); |
| 403 |
} |
| 404 |
if (m.condition != null) { |
| 405 |
out.println(" }"); |
| 406 |
} |
| 407 |
} |
| 408 |
|
| 409 |
private void printStructureMemberXmlParser(PrintWriter out, Member m) { |
| 410 |
String s = " "; |
| 411 |
|
| 412 |
out.println(s + "if (!in.isStartElement()) {"); |
| 413 |
out.println(s + " qDebug() << \"not startelement in " |
| 414 |
+ m.type().name + " \" << in.lineNumber();"); |
| 415 |
out.println(s + " return;"); |
| 416 |
out.println(s + "}"); |
| 417 |
if (!m.isOptional && !m.isArray) { |
| 418 |
out.println(s + "if (in.name() != \"" + m.name + "\") {"); |
| 419 |
out.println(s + " qDebug() << \"not startelement in " + m.name |
| 420 |
+ " \" << in.lineNumber();"); |
| 421 |
out.println(s + " return;"); |
| 422 |
out.println(s + "}"); |
| 423 |
} |
| 424 |
if (m.isOptional) { |
| 425 |
out.println(s + "if (in.name() == \"" + m.name + "\") {"); |
| 426 |
s = s + " "; |
| 427 |
} |
| 428 |
if (!m.isStruct) { |
| 429 |
out.println(s + "in.readElementText();"); |
| 430 |
} else { |
| 431 |
out.println(s + "skipToStartElement(in);"); |
| 432 |
// out.println(s + "parse" + m.type + "(in, _s." + m.name + ");"); |
| 433 |
} |
| 434 |
// out.println(s + "if (in.name() == \"" + m.name + "\") {"); |
| 435 |
if (m.isOptional) { |
| 436 |
out.println(" }"); |
| 437 |
} |
| 438 |
} |
| 439 |
|
| 440 |
private void printStructureWriter(PrintWriter out, Struct s) { |
| 441 |
out.println("void write(const " + s.name |
| 442 |
+ "& _s, LEOutputStream& out) {"); |
| 443 |
for (Member m : s.members) { |
| 444 |
printStructureMemberWriter(out, m); |
| 445 |
} |
| 446 |
out.println("}"); |
| 447 |
} |
| 448 |
|
| 449 |
private void printStructureMemberWriter(PrintWriter out, Member m) { |
| 450 |
String s = " "; |
| 451 |
if (m.condition != null) { |
| 452 |
out.println(" if (" + getExpression("_s", m.condition) + ") {"); |
| 453 |
s = s + " "; |
| 454 |
} |
| 455 |
if (m.isChoice) { |
| 456 |
boolean first = true; |
| 457 |
for (String t : ((Choice) m.type()).getChoiceNames()) { |
| 458 |
out.print(s); |
| 459 |
if (!first) { |
| 460 |
out.print("} else "); |
| 461 |
} |
| 462 |
first = false; |
| 463 |
out.println("if (_s." + m.name + ".is<" + t + ">()) {"); |
| 464 |
out.println(s + " write(*_s." + m.name + ".get<" + t |
| 465 |
+ ">(), out);"); |
| 466 |
} |
| 467 |
out.println(s + "}"); |
| 468 |
} else if (m.isArray) { |
| 469 |
if (m.type() == m.registry.uint8) { |
| 470 |
out.println(s + "out.writeBytes(_s." + m.name + ");"); |
| 471 |
} else { |
| 472 |
String t = getTypeName(m.type()); |
| 473 |
out.println(s + "foreach (" + t + " _i, _s." + m.name + ") {"); |
| 474 |
if (m.isStruct) { |
| 475 |
out.println(s + " write(_i, out);"); |
| 476 |
} else { |
| 477 |
out.println(s + " out.write" + m.type().name + "(_i);"); |
| 478 |
} |
| 479 |
out.println(s + "}"); |
| 480 |
} |
| 481 |
} else if (m.isStruct) { |
| 482 |
out.print(s); |
| 483 |
if (m.isOptional || m.condition != null) { |
| 484 |
out.print("if (_s." + m.name + ") write(*"); |
| 485 |
} else { |
| 486 |
out.print("write("); |
| 487 |
} |
| 488 |
out.println("_s." + m.name + ", out);"); |
| 489 |
} else { |
| 490 |
out.println(s + "out.write" + m.type().name + "(_s." + m.name |
| 491 |
+ ");"); |
| 492 |
} |
| 493 |
if (m.condition != null) { |
| 494 |
out.println(" }"); |
| 495 |
} |
| 496 |
} |
| 497 |
|
| 498 |
private String getTypeName(TypeRegistry.Type t) { |
| 499 |
TypeRegistry r = t.registry; |
| 500 |
if (t instanceof Choice) { |
| 501 |
return createChoiceClass(t.name, (Choice) t); |
| 502 |
} else if (t == r.bit) { |
| 503 |
return "bool"; |
| 504 |
} else if (t == r.uint2 || t == r.uint3 || t == r.uint4 || t == r.uint5 |
| 505 |
|| t == r.uint6 || t == r.uint7 || t == r.uint8) { |
| 506 |
return "quint8"; |
| 507 |
} else if (t == r.uint9 || t == r.uint12 || t == r.uint13 |
| 508 |
|| t == r.uint14 || t == r.uint15 |
| 509 |
|| t == r.uint16) { |
| 510 |
return "quint16"; |
| 511 |
} else if (t == r.uint20 || t == r.uint30 || t == r.uint32) { |
| 512 |
return "quint32"; |
| 513 |
} else if (t == r.int16) { |
| 514 |
return "qint16"; |
| 515 |
} else if (t == r.int32) { |
| 516 |
return "qint32"; |
| 517 |
} |
| 518 |
return t.name; |
| 519 |
} |
| 520 |
|
| 521 |
private String createChoiceClass(String name, Choice c) { |
| 522 |
String base = "StreamOffset"; |
| 523 |
if (config.enableIntrospection) { |
| 524 |
base = "Introspectable"; |
| 525 |
} |
| 526 |
String choice = "class " + name + " : public QSharedPointer<" + base |
| 527 |
+ "> {\n"; |
| 528 |
choice += " public:\n"; |
| 529 |
choice += " " + name + "() {}\n"; |
| 530 |
for (String s : c.getChoiceNames()) { |
| 531 |
choice += " explicit " + name + "(" + s |
| 532 |
+ "* a) :QSharedPointer<" + base + ">(a) {}\n"; |
| 533 |
} |
| 534 |
choice += " template <typename T> T*get() { return dynamic_cast<T*>(this->data()); }\n"; |
| 535 |
choice += " template <typename T> const T*get() const { return dynamic_cast<const T*>(this->data()); }\n"; |
| 536 |
choice += " template <typename T> bool is() const { return get<T>(); }\n"; |
| 537 |
choice += " };\n"; |
| 538 |
choice += " " + name; |
| 539 |
return choice; |
| 540 |
} |
| 541 |
|
| 542 |
private String getMemberDeclaration(Member m) { |
| 543 |
String t = getTypeName(m.type()); |
| 544 |
if (m.isArray) { |
| 545 |
if (m.isStruct) { |
| 546 |
return "QList<" + m.type().name + "> " + m.name; |
| 547 |
} else { |
| 548 |
if ("quint8".equals(t)) { |
| 549 |
return "QByteArray " + m.name; |
| 550 |
} else { |
| 551 |
return "QVector<" + t + "> " + m.name; |
| 552 |
} |
| 553 |
} |
| 554 |
} else if (m.isStruct && (m.isOptional || m.condition != null)) { |
| 555 |
return "QSharedPointer<" + t + "> " + m.name; |
| 556 |
} |
| 557 |
return t + " " + m.name; |
| 558 |
} |
| 559 |
|
| 560 |
private String memberToString(Member m, String prefix) { |
| 561 |
String s; |
| 562 |
String mn = prefix + m.name; |
| 563 |
if (m.isArray) { |
| 564 |
s = "\"[array of " + mn + "]\""; |
| 565 |
} else { |
| 566 |
if (m.isInteger) { |
| 567 |
s = "QString::number(" + mn + ") + \"(\" + QString::number(" |
| 568 |
+ mn + ",16).toUpper() + \")\""; |
| 569 |
} else if (m.type() == m.type().registry.bit) { |
| 570 |
s = "QString::number(" + mn + ")"; |
| 571 |
} else if (m.isChoice) { |
| 572 |
s = "\"<choice>\""; |
| 573 |
} else if (m.isOptional || m.condition != null) { |
| 574 |
s = "((" + mn + ")?" + mn + "->toString() :\"null\")"; |
| 575 |
} else { |
| 576 |
s = mn + ".toString()"; |
| 577 |
} |
| 578 |
} |
| 579 |
return s; |
| 580 |
} |
| 581 |
|
| 582 |
private void styleTextPropAtomFix(PrintWriter out) { |
| 583 |
out.println(" RecordHeader rh;"); |
| 584 |
out.println(" QList<TextPFRun> rgTextPFRun;"); |
| 585 |
out.println(" QList<TextCFRun> rgTextCFRun;"); |
| 586 |
} |
| 587 |
|
| 588 |
private void styleTextPropAtomFix2(PrintWriter out) { |
| 589 |
out.println(" if (_s.style) {"); |
| 590 |
out.println(" quint32 count = 0;"); |
| 591 |
out.println(" if (_s.text.is<TextCharsAtom>()) {"); |
| 592 |
out |
| 593 |
.println(" count = _s.text.get<TextCharsAtom>()->textChars.size();"); |
| 594 |
out.println(" }"); |
| 595 |
out.println(" if (_s.text.is<TextBytesAtom>()) {"); |
| 596 |
out |
| 597 |
.println(" count = _s.text.get<TextBytesAtom>()->textChars.size();"); |
| 598 |
out.println(" }"); |
| 599 |
out.println(" quint32 sum = 0;"); |
| 600 |
out.println(" do {"); |
| 601 |
out |
| 602 |
.println(" _s.style->rgTextPFRun.append(TextPFRun(_s.style.data()));"); |
| 603 |
out |
| 604 |
.println(" parseTextPFRun(in, _s.style->rgTextPFRun.last());"); |
| 605 |
out.println(" sum += _s.style->rgTextPFRun.last().count;"); |
| 606 |
out.println(" } while (sum <= count);"); |
| 607 |
out.println(" sum = 0;"); |
| 608 |
out.println(" do {"); |
| 609 |
out |
| 610 |
.println(" _s.style->rgTextCFRun.append(TextCFRun(_s.style.data()));"); |
| 611 |
out |
| 612 |
.println(" parseTextCFRun(in, _s.style->rgTextCFRun.last());"); |
| 613 |
out.println(" sum += _s.style->rgTextCFRun.last().count;"); |
| 614 |
out.println(" } while (sum <= count);"); |
| 615 |
out.println(" }"); |
| 616 |
} |
| 617 |
|
| 618 |
private void printStructureClassDeclaration(PrintWriter out, Struct s) { |
| 619 |
out.print("class " + s.name); |
| 620 |
if (config.enableIntrospection) { |
| 621 |
out.println(" : public Introspectable {"); |
| 622 |
out.println("private:"); |
| 623 |
out.println(" class _Introspection;"); |
| 624 |
} else { |
| 625 |
out.println(" : public StreamOffset {"); |
| 626 |
|
| 627 |
} |
| 628 |
out.println("public:"); |
| 629 |
if (config.enableIntrospection) { |
| 630 |
out.println(" static const Introspection _introspection;"); |
| 631 |
} |
| 632 |
for (Member m : s.members) { |
| 633 |
if (!m.isStruct && m.condition != null) { |
| 634 |
out.println(" bool _has_" + m.name + ";"); |
| 635 |
} |
| 636 |
} |
| 637 |
if (config.enableStyleTextPropAtomFix |
| 638 |
&& s.name.equals("StyleTextPropAtom")) { |
| 639 |
styleTextPropAtomFix(out); |
| 640 |
} else { |
| 641 |
for (Member m : s.members) { |
| 642 |
String d = getMemberDeclaration(m); |
| 643 |
out.println(" " + d + ";"); |
| 644 |
} |
| 645 |
} |
| 646 |
boolean first = true; |
| 647 |
if (config.enableIntrospection) { |
| 648 |
out.print(" explicit " + s.name |
| 649 |
+ "(const Introspectable* parent)"); |
| 650 |
out.print("\n :Introspectable(parent)"); |
| 651 |
first = false; |
| 652 |
for (Member m : s.members) { |
| 653 |
if (m.isStruct && !m.isArray && !m.isOptional && !(m.isChoice) |
| 654 |
&& m.condition == null) { |
| 655 |
if (first) { |
| 656 |
out.print("\n :"); |
| 657 |
first = false; |
| 658 |
} else { |
| 659 |
out.print(",\n "); |
| 660 |
} |
| 661 |
out.print(m.name + "(this)"); |
| 662 |
} |
| 663 |
} |
| 664 |
out.println(" {}"); |
| 665 |
} else { |
| 666 |
out.println(" " + s.name + "(void* /*dummy*/ = 0) {}"); |
| 667 |
} |
| 668 |
|
| 669 |
// function toString |
| 670 |
if (config.enableToString) { |
| 671 |
out.println(" QString toString() {"); |
| 672 |
out.println(" QString _s = \"" + s.name + ":\";"); |
| 673 |
for (Member m : s.members) { |
| 674 |
out.print(" _s = _s + \"" + m.name + ": \" + "); |
| 675 |
out.print(memberToString(m, "")); |
| 676 |
out.println(" + \", \";"); |
| 677 |
} |
| 678 |
out.println(" return _s;"); |
| 679 |
out.println(" }"); |
| 680 |
} |
| 681 |
if (config.enableIntrospection) { |
| 682 |
out |
| 683 |
.println(" const Introspection* getIntrospection() const { return &_introspection; }"); |
| 684 |
} |
| 685 |
out.println("};"); |
| 686 |
|
| 687 |
} |
| 688 |
|
| 689 |
private void printStructureClassImplementation(PrintWriter out, Struct s) { |
| 690 |
final int nm = s.members.size(); |
| 691 |
final String ns = s.name + "::_Introspection"; |
| 692 |
out.println("class " + ns + " {"); |
| 693 |
out.println("public:"); |
| 694 |
out.println(" static const QString name;"); |
| 695 |
out.println(" static const int numberOfMembers;"); |
| 696 |
out.println(" static const QString names[" + nm + "];"); |
| 697 |
out.println(" static int (* const numberOfInstances[" + nm |
| 698 |
+ "])(const Introspectable*);"); |
| 699 |
out.println(" static QVariant (* const value[" + nm |
| 700 |
+ "])(const Introspectable*, int position);"); |
| 701 |
out.println(" static const Introspectable* (* const introspectable[" |
| 702 |
+ nm + "])(const Introspectable*, int position);"); |
| 703 |
for (Member m : s.members) { |
| 704 |
if (s.name.equals("StyleTextPropAtom") |
| 705 |
&& config.enableStyleTextPropAtomFix |
| 706 |
&& m.name.equals("todo")) { |
| 707 |
break; |
| 708 |
} |
| 709 |
if (!m.isStruct && !(m.isChoice)) { |
| 710 |
if (m.condition != null) { |
| 711 |
out.println(" static int count_" + m.name |
| 712 |
+ "(const Introspectable* i) {"); |
| 713 |
out.println(" return static_cast<const " + s.name |
| 714 |
+ "*>(i)->_has_" + m.name + " ?1 :0;"); |
| 715 |
out.println(" }"); |
| 716 |
} |
| 717 |
} else if (m.isOptional || m.condition != null) { |
| 718 |
out.println(" static int count_" + m.name |
| 719 |
+ "(const Introspectable* i) {"); |
| 720 |
out.println(" return get_" + m.name + "(i, 0) ?1 :0;"); |
| 721 |
out.println(" }"); |
| 722 |
} else if (m.isArray) { |
| 723 |
out.println(" static int count_" + m.name |
| 724 |
+ "(const Introspectable* i) {"); |
| 725 |
out.println(" return static_cast<const " + s.name |
| 726 |
+ "*>(i)->" + m.name + ".size();"); |
| 727 |
out.println(" }"); |
| 728 |
} |
| 729 |
if (m.isStruct || m.isChoice) { |
| 730 |
out.println(" static const Introspectable* get_" + m.name |
| 731 |
+ "(const Introspectable* i, int j) {"); |
| 732 |
} else { |
| 733 |
out.println(" static QVariant get_" + m.name |
| 734 |
+ "(const Introspectable* i, int j) {"); |
| 735 |
} |
| 736 |
String dm = "static_cast<const " + s.name + "*>(i)->" + m.name + ""; |
| 737 |
if (!(m.isChoice)) { |
| 738 |
out.print(" "); |
| 739 |
if (!m.isStruct) { |
| 740 |
if (m.isArray && m.type() != m.type().registry.uint8) { |
| 741 |
out.println("return qVariantFromValue(" + dm + ");"); |
| 742 |
} else { |
| 743 |
out.println("return " + dm + ";"); |
| 744 |
} |
| 745 |
} else if (m.isArray) { |
| 746 |
out.println("return &(" + dm + "[j]);"); |
| 747 |
} else if (m.isOptional || m.condition != null) { |
| 748 |
out.println("return " + dm + ".data();"); |
| 749 |
} else { |
| 750 |
out.println("return &(" + dm + ");"); |
| 751 |
} |
| 752 |
} else { |
| 753 |
out.println(" return static_cast<const " + s.name |
| 754 |
+ "*>(i)->" + m.name + ".data();"); |
| 755 |
} |
| 756 |
out.println(" }"); |
| 757 |
} |
| 758 |
out.println("};"); |
| 759 |
out.println("const QString " + ns + "::name(\"" + s.name + "\");"); |
| 760 |
out.println("const int " + ns + "::numberOfMembers(" + nm + ");"); |
| 761 |
out.println("const QString " + ns + "::names[" + nm + "] = {"); |
| 762 |
for (Member m : s.members) { |
| 763 |
out.println(" \"" + m.name + "\","); |
| 764 |
} |
| 765 |
out.println("};"); |
| 766 |
out.println("int (* const " + ns + "::numberOfInstances[" + nm |
| 767 |
+ "])(const Introspectable*) = {"); |
| 768 |
for (Member m : s.members) { |
| 769 |
if (m.condition != null |
| 770 |
|| ((m.isStruct || m.isChoice) && (m.isOptional || m.isArray))) { |
| 771 |
out.println(" _Introspection::count_" + m.name + ","); |
| 772 |
} else { |
| 773 |
// arrays of simple types count as one instance |
| 774 |
out.println(" Introspection::one,"); |
| 775 |
} |
| 776 |
} |
| 777 |
out.println("};"); |
| 778 |
out.println("QVariant (* const " + ns + "::value[" + nm |
| 779 |
+ "])(const Introspectable*, int position) = {"); |
| 780 |
for (Member m : s.members) { |
| 781 |
if (s.name.equals("StyleTextPropAtom") |
| 782 |
&& config.enableStyleTextPropAtomFix |
| 783 |
&& m.name.equals("todo")) { |
| 784 |
break; |
| 785 |
} else if (m.isStruct || m.isChoice) { |
| 786 |
out.println(" Introspection::nullValue,"); |
| 787 |
} else { |
| 788 |
out.println(" _Introspection::get_" + m.name + ","); |
| 789 |
} |
| 790 |
} |
| 791 |
out.println("};"); |
| 792 |
out.println("const Introspectable* (* const " + ns |
| 793 |
+ "::introspectable[" + nm |
| 794 |
+ "])(const Introspectable*, int position) = {"); |
| 795 |
for (Member m : s.members) { |
| 796 |
if (m.isStruct || m.isChoice) { |
| 797 |
out.println(" _Introspection::get_" + m.name + ","); |
| 798 |
} else { |
| 799 |
out.println(" Introspection::null,"); |
| 800 |
} |
| 801 |
} |
| 802 |
out.println("};"); |
| 803 |
out.println("const Introspection " + s.name + "::_introspection("); |
| 804 |
out |
| 805 |
.println(" \"" |
| 806 |
+ s.name |
| 807 |
+ "\", " |
| 808 |
+ s.members.size() |
| 809 |
+ ", _Introspection::names, _Introspection::numberOfInstances, _Introspection::value, _Introspection::introspectable);"); |
| 810 |
} |
| 811 |
|
| 812 |
private void printChoiceParser(PrintWriter out, String s, String structure, |
| 813 |
Member m) { |
| 814 |
Choice c = (Choice) m.type(); |
| 815 |
if (c.commonType == null) { |
| 816 |
printUnsureChoiceParser(out, s, structure, m); |
| 817 |
} else { |
| 818 |
printSureChoiceParser(out, s, structure, m); |
| 819 |
} |
| 820 |
} |
| 821 |
|
| 822 |
String getClause(String name, TypeRegistry.Type t, Option.Lim lim) { |
| 823 |
String ls = ""; |
| 824 |
if (lim.limitations != null && lim.limitations.length > 0) { |
| 825 |
for (int i = 0; i < lim.limitations.length; ++i) { |
| 826 |
Limitation l = lim.limitations[i]; |
| 827 |
String condition = l.expression; |
| 828 |
String mname = name; |
| 829 |
if (t instanceof Struct) { |
| 830 |
mname += "." + l.name; |
| 831 |
} |
| 832 |
if (condition == null) { |
| 833 |
condition = getCondition(mname, l); |
| 834 |
} else { |
| 835 |
condition = getExpression(mname, condition); |
| 836 |
} |
| 837 |
if (ls.length() > 0) { |
| 838 |
ls += "&&"; |
| 839 |
} |
| 840 |
ls += "(" + condition + ")"; |
| 841 |
} |
| 842 |
} else if (lim.lims != null && lim.lims.length > 0) { |
| 843 |
for (int i = 0; i < lim.lims.length; ++i) { |
| 844 |
Option.Lim l = lim.lims[i]; |
| 845 |
String condition = getClause(name, t, l); |
| 846 |
if (ls.length() > 0) { |
| 847 |
ls += "||"; |
| 848 |
} |
| 849 |
ls += "(" + condition + ")"; |
| 850 |
} |
| 851 |
} |
| 852 |
return ls.replace("..", "."); |
| 853 |
} |
| 854 |
|
| 855 |
private void printSureChoiceParser(PrintWriter out, String s, |
| 856 |
String structure, Member m) { |
| 857 |
out.println(s + "_m = in.setMark();"); |
| 858 |
Choice c = (Choice) m.type(); |
| 859 |
String type = getTypeName(c.commonType); |
| 860 |
if (c.commonType instanceof Struct) { |
| 861 |
out.println(s + type + " _choice(&_s);"); |
| 862 |
out.println(s + "parse" + type + "(in, _choice);"); |
| 863 |
} else { |
| 864 |
out.println(s + type + " _choice = in.read" + c.commonType.name |
| 865 |
+ "();"); |
| 866 |
} |
| 867 |
out.println(s + "in.rewind(_m);"); |
| 868 |
out.println(s + "qint64 startPos = in.getPosition();"); |
| 869 |
for (int i = 0; i < c.options.size(); ++i) { |
| 870 |
out.print(s); |
| 871 |
Option o = c.options.get(i); |
| 872 |
String clause = getClause("_choice", o.limitsType, o.lim); |
| 873 |
out.print("if (startPos == in.getPosition()"); |
| 874 |
if (clause == null || (!m.isOptional && i == c.options.size() - 1)) { |
| 875 |
out.println(") {"); |
| 876 |
} else { |
| 877 |
out.println(" && (" + clause + ")) {"); |
| 878 |
} |
| 879 |
out.println(s + " _s." + m.name + " = " + structure + "::" |
| 880 |
+ m.type().name + "(new " + o.type.name + "(&_s));"); |
| 881 |
out.println(s + " parse" + o.type.name + "(in, *(" + o.type.name |
| 882 |
+ "*)_s." + m.name + ".data());"); |
| 883 |
out.println(s + "}"); |
| 884 |
} |
| 885 |
} |
| 886 |
|
| 887 |
private void printUnsureChoiceParser(PrintWriter out, String s, |
| 888 |
String structure, Member m) { |
| 889 |
String closing = ""; |
| 890 |
String exception = "_x"; |
| 891 |
String choice; |
| 892 |
out.println(s + "_m = in.setMark();"); |
| 893 |
Choice c = (Choice) m.type(); |
| 894 |
String choices[] = c.getChoiceNames(); |
| 895 |
int length = (m.isOptional) ? choices.length : choices.length - 1; |
| 896 |
for (int i = 0; i < length; ++i) { |
| 897 |
choice = choices[i]; |
| 898 |
out.println(s + "try {"); |
| 899 |
out.println(s + " _s." + m.name + " = " + structure + "::" |
| 900 |
+ c.name + "(new " + choice + "(&_s));"); |
| 901 |
out.println(s + " parse" + choice + "(in, *(" + choice + "*)_s." |
| 902 |
+ m.name + ".data());"); |
| 903 |
out.println(s + "} catch (IncorrectValueException " + exception |
| 904 |
+ ") {"); |
| 905 |
out.println(s + " _s." + m.name + ".clear();"); |
| 906 |
out.println(s + " in.rewind(_m);"); |
| 907 |
exception = exception + "x"; |
| 908 |
closing = closing + "}"; |
| 909 |
} |
| 910 |
if (!m.isOptional) { |
| 911 |
choice = choices[choices.length - 1]; |
| 912 |
out.println(s + " _s." + m.name + " = " + structure + "::" |
| 913 |
+ c.name + "(new " + choice + "(&_s));"); |
| 914 |
out.println(s + " parse" + choice + "(in, *(" + choice + "*)_s." |
| 915 |
+ m.name + ".data());"); |
| 916 |
} |
| 917 |
out.println(s + closing); |
| 918 |
} |
| 919 |
|
| 920 |
private void printFixedSizeArrayParser(PrintWriter out, String s, Member m) { |
| 921 |
out.println(s + "qint64 _startPos = in.getPosition();"); |
| 922 |
/* _totalSize should really be just getExpression("_s", m.size) |
| 923 |
The check for the end of the stream is only a workaround for |
| 924 |
a limitation in the current Excel file parser. In Excel, |
| 925 |
the stream is split up in blocks and the current code parses |
| 926 |
these blocks separately and reassembles them later instead of |
| 927 |
assembling the raw data transparantly in a stream. */ |
| 928 |
out.println(s + "int _totalSize = qMin(" + getExpression("_s", m.size) |
| 929 |
+ ", quint32(in.getSize() - _startPos));"); |
| 930 |
out.println(s + "_atend = in.getPosition() - _startPos >= _totalSize;"); |
| 931 |
out.println(s + "while (!_atend) {"); |
| 932 |
out.println(s + " _s." + m.name + ".append(" + m.type().name |
| 933 |
+ "(&_s));"); |
| 934 |
out.println(s + " parse" + m.type().name + "(in, _s." + m.name |
| 935 |
+ ".last());"); |
| 936 |
out.println(s + " _atend = in.getPosition() - _startPos >= _totalSize;"); |
| 937 |
out.println(s + "}"); |
| 938 |
} |
| 939 |
|
| 940 |
private void printVariableArrayParser(PrintWriter out, String s, Member m) { |
| 941 |
out.println(s + "_atend = false;"); |
| 942 |
out.println(s + "while (!_atend) {"); |
| 943 |
out.println(s + " _m = in.setMark();"); |
| 944 |
out.println(s + " try {"); |
| 945 |
out.println(s + " _s." + m.name + ".append(" + m.type().name |
| 946 |
+ "(&_s));"); |
| 947 |
out.println(s + " parse" + m.type().name + "(in, _s." + m.name |
| 948 |
+ ".last());"); |
| 949 |
out.println(s + " } catch(IncorrectValueException _e) {"); |
| 950 |
out.println(s + " _s." + m.name + ".removeLast();"); |
| 951 |
out.println(s + " _atend = true;"); |
| 952 |
out.println(s + " in.rewind(_m);"); |
| 953 |
out.println(s + " } catch(EOFException _e) {"); |
| 954 |
out.println(s + " _s." + m.name + ".removeLast();"); |
| 955 |
out.println(s + " _atend = true;"); |
| 956 |
out.println(s + " in.rewind(_m);"); |
| 957 |
out.println(s + " }"); |
| 958 |
out.println(s + "}"); |
| 959 |
} |
| 960 |
|
| 961 |
private void printOptionalMemberParser(PrintWriter out, String s, Member m) { |
| 962 |
out.println(s + "_m = in.setMark();"); |
| 963 |
Option o = new Option((Struct) m.type(), null); |
| 964 |
String type = getTypeName(o.limitsType); |
| 965 |
out.println(s + "try {"); |
| 966 |
out.println(s + " " + type + " _optionCheck(&_s);"); |
| 967 |
out.println(s + " parse" + type + "(in, _optionCheck);"); |
| 968 |
out.println(s + " _possiblyPresent = " |
| 969 |
+ getClause("_optionCheck", o.limitsType, o.lim) + ";"); |
| 970 |
out.println(s + "} catch(EOFException _e) {"); |
| 971 |
out.println(s + " _possiblyPresent = false;"); |
| 972 |
out.println(s + "}"); |
| 973 |
|
| 974 |
out.println(s + "in.rewind(_m);"); |
| 975 |
out.println(s + "_m = in.setMark();"); |
| 976 |
out.println(s + "if (_possiblyPresent) {"); |
| 977 |
out.println(s + " try {"); |
| 978 |
out.println(s + " _s." + m.name + " = QSharedPointer<" |
| 979 |
+ m.type().name + ">(new " + m.type().name + "(&_s));"); |
| 980 |
out.println(s + " parse" + m.type().name + "(in, *_s." + m.name |
| 981 |
+ ".data());"); |
| 982 |
out.println(s + " } catch(IncorrectValueException _e) {"); |
| 983 |
out.println(s + " _s." + m.name + ".clear();"); |
| 984 |
out.println(s + " in.rewind(_m);"); |
| 985 |
out.println(s + " } catch(EOFException _e) {"); |
| 986 |
out.println(s + " _s." + m.name + ".clear();"); |
| 987 |
out.println(s + " in.rewind(_m);"); |
| 988 |
out.println(s + " }"); |
| 989 |
out.println(s + "}"); |
| 990 |
} |
| 991 |
|
| 992 |
private void printLimitationCheck(PrintWriter out, String s, String name, |
| 993 |
Member m) { |
| 994 |
for (Limitation l : m.limitations) { |
| 995 |
String mname = l.name; |
| 996 |
if (!"".equals(mname)) { |
| 997 |
mname = name + "." + mname; |
| 998 |
} else { |
| 999 |
mname = name; |
| 1000 |
} |
| 1001 |
if (!m.isStruct) { |
| 1002 |
mname = "((" + getTypeName(m.type()) + ")" + mname + ")"; |
| 1003 |
} |
| 1004 |
String condition = l.expression; |
| 1005 |
if (condition == null) { |
| 1006 |
condition = getCondition(mname, l); |
| 1007 |
} else { |
| 1008 |
condition = getExpression(mname, condition); |
| 1009 |
} |
| 1010 |
|
| 1011 |
out.println(s + "if (!(" + condition + ")) {"); |
| 1012 |
String exceptionType = "IncorrectValueException"; |
| 1013 |
out.println(s + " throw " + exceptionType |
| 1014 |
+ "(in.getPosition(), \"" + condition + "\");"); |
| 1015 |
out.println(s + "}"); |
| 1016 |
} |
| 1017 |
} |
| 1018 |
|
| 1019 |
static String getExpression(String structure, String expression) { |
| 1020 |
if (Pattern.matches(".*[A-Za-z].*", expression)) { |
| 1021 |
return prependStructureToExpression(expression, structure); |
| 1022 |
} |
| 1023 |
return structure + expression; |
| 1024 |
} |
| 1025 |
|
| 1026 |
static String getCondition(String name, Limitation l) { |
| 1027 |
String value = l.value; |
| 1028 |
String cmp = " == "; |
| 1029 |
String cmb = " || "; |
| 1030 |
if (value.startsWith("!")) { |
| 1031 |
value = value.substring(1); |
| 1032 |
cmp = " != "; |
| 1033 |
cmb = " && "; |
| 1034 |
} |
| 1035 |
if (value.contains("|")) { |
| 1036 |
String values[] = value.split("\\|"); |
| 1037 |
String c = name + cmp + values[0]; |
| 1038 |
for (int i = 1; i < values.length; ++i) { |
| 1039 |
c = c + cmb + name + cmp + values[i]; |
| 1040 |
} |
| 1041 |
return c; |
| 1042 |
} |
| 1043 |
if (!"".equals(value)) { |
| 1044 |
return name + cmp + value; |
| 1045 |
} |
| 1046 |
return l.value; |
| 1047 |
} |
| 1048 |
} |