001/* 002 * BridJ - Dynamic and blazing-fast native interop for Java. 003 * http://bridj.googlecode.com/ 004 * 005 * Copyright (c) 2010-2013, Olivier Chafik (http://ochafik.com/) 006 * All rights reserved. 007 * 008 * Redistribution and use in source and binary forms, with or without 009 * modification, are permitted provided that the following conditions are met: 010 * 011 * * Redistributions of source code must retain the above copyright 012 * notice, this list of conditions and the following disclaimer. 013 * * Redistributions in binary form must reproduce the above copyright 014 * notice, this list of conditions and the following disclaimer in the 015 * documentation and/or other materials provided with the distribution. 016 * * Neither the name of Olivier Chafik nor the 017 * names of its contributors may be used to endorse or promote products 018 * derived from this software without specific prior written permission. 019 * 020 * THIS SOFTWARE IS PROVIDED BY OLIVIER CHAFIK AND CONTRIBUTORS ``AS IS'' AND ANY 021 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 022 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 023 * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY 024 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 025 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 026 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 027 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 028 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 029 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 030 */ 031package org.bridj.demangling; 032 033import org.bridj.ann.Convention.Style; 034import java.lang.reflect.*; 035import java.util.ArrayList; 036import java.util.Collections; 037import java.util.List; 038 039import org.bridj.NativeLibrary; 040import org.bridj.demangling.Demangler.ClassRef; 041import org.bridj.demangling.Demangler.DemanglingException; 042import org.bridj.demangling.Demangler.MemberRef; 043import org.bridj.demangling.Demangler.NamespaceRef; 044import org.bridj.demangling.Demangler.Ident; 045import org.bridj.demangling.Demangler.IdentLike; 046import org.bridj.demangling.Demangler.TypeRef; 047import org.bridj.demangling.Demangler.SpecialName; 048import org.bridj.CLong; 049import org.bridj.ann.Convention; 050import java.math.BigInteger; 051import java.util.Collection; 052 053public class VC9Demangler extends Demangler { 054 055 public VC9Demangler(NativeLibrary library, String str) { 056 super(library, str); 057 } 058 059 private AccessLevelAndStorageClass parseAccessLevelAndStorageClass() throws DemanglingException { 060 AccessLevelAndStorageClass ac = new AccessLevelAndStorageClass(); 061 switch (consumeChar()) { 062 case 'A': 063 case 'B': 064 ac.modifiers = Modifier.PRIVATE; 065 break; 066 case 'C': 067 case 'D': 068 ac.modifiers = Modifier.PRIVATE | Modifier.STATIC; 069 break; 070 case 'E': 071 case 'F': 072 ac.modifiers = Modifier.PRIVATE; 073 ac.isVirtual = true; 074 break; 075 case 'G': 076 case 'H': 077 ac.modifiers = Modifier.PRIVATE; 078 ac.isThunk = true; 079 break; 080 case 'I': 081 case 'J': 082 ac.modifiers = Modifier.PROTECTED; 083 break; 084 case 'K': 085 case 'L': 086 ac.modifiers = Modifier.PROTECTED | Modifier.STATIC; 087 break; 088 case 'M': 089 case 'N': 090 ac.modifiers = Modifier.PROTECTED; 091 ac.isVirtual = true; 092 break; 093 case 'O': 094 case 'P': 095 ac.modifiers = Modifier.PROTECTED; 096 ac.isThunk = true; 097 break; 098 case 'Q': 099 case 'R': 100 ac.modifiers = Modifier.PUBLIC; 101 break; 102 case 'S': 103 case 'T': 104 ac.modifiers = Modifier.PUBLIC | Modifier.STATIC; 105 break; 106 case 'U': 107 case 'V': 108 ac.modifiers = Modifier.PUBLIC; 109 ac.isVirtual = true; 110 break; 111 case 'W': 112 case 'X': 113 ac.modifiers = Modifier.PUBLIC; 114 ac.isThunk = true; 115 break; 116 case 'Y': 117 case 'Z': 118 // No modifier, no storage class 119 ac.modifiers = 0; 120 break; 121 default: 122 throw error("Unknown access level + storage class"); 123 } 124 return ac; 125 } 126 127 private ClassRef parseTemplateType() throws DemanglingException { 128 //System.out.println("# START OF parseTemplateParams()"); 129 String name = parseNameFragment(); 130 //return withEmptyQualifiedNames(new DemanglingOp<ClassRef>() { public ClassRef run() throws DemanglingException { 131 List<TemplateArg> args = parseTemplateParams(); 132 133 List<Object> names = parseNameQualifications(); 134 135 //String ns = parseNameFragment(); 136 137 //System.out.println("parseTemplateParams() = " + args + ", ns = " + names); 138 ClassRef tr = new ClassRef(new Ident(name, args.toArray(new TemplateArg[args.size()]))); 139 tr.setEnclosingType(reverseNamespace(names)); 140 141 addBackRef(tr); 142 143 return tr; 144 //}}); 145 } 146 147 private void parseFunctionProperty(MemberRef mr) throws DemanglingException { 148 mr.callingConvention = parseCallingConvention(); 149 TypeRef returnType = consumeCharIf('@') ? classType(void.class) : parseType(true); 150// allQualifiedNames.clear(); 151 //withEmptyQualifiedNames(new DemanglingRunnable() { public void run() throws DemanglingException { 152 List<TypeRef> paramTypes = parseParams(); 153 mr.paramTypes = paramTypes.toArray(new TypeRef[paramTypes.size()]); 154 if (!consumeCharIf('Z')) { 155 List<TypeRef> throwTypes = parseParams(); 156 mr.throwTypes = throwTypes.toArray(new TypeRef[throwTypes.size()]); 157 } 158 159 mr.setValueType(returnType); 160 //}}); 161 } 162 163 static class AnonymousTemplateArg implements TemplateArg { 164 165 public AnonymousTemplateArg(String v) { 166 this.v = v; 167 } 168 String v; 169 170 //@Override 171 public boolean matchesParam(Object param, Annotations annotations) { 172 return true; // TODO wtf ? 173 } 174 175 @Override 176 public String toString() { 177 return v; 178 } 179 } 180 181 private TemplateArg parseTemplateParameter() throws DemanglingException { 182 switch (peekChar()) { 183 case '?': 184 consumeChar(); 185 return new AnonymousTemplateArg("'anonymous template param " + parseNumber(false) + "'"); 186 case '$': 187 consumeChar(); 188 switch (consumeChar()) { 189 case '0': 190 return new Constant(parseNumber(true)); 191 case '2': 192 int a = parseNumber(true); 193 int b = parseNumber(true); 194 return new Constant(a * Math.exp(10 * (int) Math.log(b - Math.log10(a) + 1))); 195 case 'D': 196 return new AnonymousTemplateArg("'anonymous template param " + parseNumber(false) + "'"); 197 case 'F': 198 return new AnonymousTemplateArg("'tuple (" + parseNumber(true) + ", " + parseNumber(true) + ")'"); 199 case 'G': 200 return new AnonymousTemplateArg("'tuple (" + parseNumber(true) + ", " + parseNumber(true) + ", " + parseNumber(true) + ")'"); 201 case 'Q': 202 return new AnonymousTemplateArg("'anonymous non-type template param " + parseNumber(false) + "'"); 203 } 204 break; 205 default: 206 //error("Unexpected template param value"); 207 } 208 return parseType(true); 209 } 210 211 static class AccessLevelAndStorageClass { 212 213 int modifiers; 214 boolean isVirtual = false, isThunk = false; 215 } 216 217 public MemberRef parseSymbol() throws DemanglingException { 218 MemberRef mr = new MemberRef(); 219 220 int iAt = str.indexOf('@'); 221 if (iAt >= 0 && consumeCharIf('_')) { 222 if (iAt > 0) { 223 mr.setMemberName(new Ident(str.substring(1, iAt))); 224 mr.setArgumentsStackSize(Integer.parseInt(str.substring(iAt + 1))); 225 return mr; 226 } 227 } 228 229 if (!consumeCharIf('@', '?')) 230 return null; 231 232 IdentLike memberName = parseFirstQualifiedTypeNameComponent(); 233 if (memberName instanceof SpecialName) { 234 SpecialName specialName = (SpecialName) memberName; 235 if (!specialName.isFunction()) { 236 return null; 237 } 238 } 239 mr.setMemberName(memberName); 240 List<Object> qNames = parseNameQualifications(); 241 242 //TypeRef qualifiedName = parseQualifiedTypeName(); 243 244 AccessLevelAndStorageClass ac = parseAccessLevelAndStorageClass(); 245 CVClassModifier cvMod = null; 246 if (ac.modifiers != 0 && !Modifier.isStatic(ac.modifiers)) { 247 cvMod = parseCVClassModifier(); 248 } 249 250 // Function property : 251 //allQualifiedNames.clear(); // TODO fix this !! 252 TypeRef encl; 253 if (cvMod != null && (cvMod.isMember || (memberName instanceof SpecialName) || Modifier.isPublic(ac.modifiers))) { 254 Object r = qNames.get(0); 255 ClassRef tr = r instanceof ClassRef ? (ClassRef) r : new ClassRef(new Ident((String) r)); 256 //tr.setSimpleName(qNames.get(0)); 257 qNames.remove(0); 258 tr.setEnclosingType(reverseNamespace(qNames)); 259 encl = tr; 260 } else { 261 encl = reverseNamespace(qNames); 262 } 263 264 addBackRef(encl); 265 mr.setEnclosingType(encl); 266 267 parseFunctionProperty(mr); 268 269 if (position != length) { 270 error("Failed to demangle the whole symbol"); 271 } 272 return mr; 273 } 274 275 TypeRef parseReturnType() throws DemanglingException { 276 TypeRef tr = parseType(true); 277 return tr; 278 } 279 280 int parseNumber(boolean allowSign) throws DemanglingException { 281 int sign = allowSign && consumeCharIf('?') ? -1 : 1; 282 if (Character.isDigit(peekChar())) { 283 char c = consumeChar(); 284 return sign * (int) (c - '0'); 285 } 286 if (peekChar() == '@') { 287 return 0; 288 } 289 290 char c; 291 StringBuilder b = new StringBuilder(); 292 long n = 0; 293 while (((c = consumeChar()) >= 'A' && c <= 'P') && c != '@') { 294 n += 16 * (c - 'A'); 295 } 296 297 String s = b.toString().trim(); 298 if (c != '@' || s.length() == 0) { 299 throw error("Expected a number here", -b.length()); 300 } 301 return sign * Integer.parseInt(s, 16); 302 } 303 304 TypeRef consumeIfBackRef() throws DemanglingException { 305 char c = peekChar(); 306 if (Character.isDigit(c)) { 307 consumeChar(); 308 int iBack = (int) (c - '0'); 309 return getBackRef(iBack); 310 } 311 return null; 312 } 313 314 TypeRef parseType(boolean allowVoid) throws DemanglingException { 315 TypeRef backRef = consumeIfBackRef(); 316 if (backRef != null) { 317 return backRef; 318 } 319 320 char c = consumeChar(); 321 switch (c) { 322 case '_': 323 TypeRef tr; 324 switch (consumeChar()) { 325 case 'D': // __int8 326 case 'E': // unsigned __int8 327 tr = classType(byte.class); 328 break; 329 case 'F': // __int16 330 case 'G': // unsigned __int16 331 tr = classType(short.class); 332 break; 333 case 'H': // __int32 334 case 'I': // unsigned __int32 335 tr = classType(int.class); 336 break; 337 case 'J': // __int64 338 case 'K': // unsigned __int64 339 tr = classType(long.class); 340 break; 341 case 'L': // __int128 342 tr = classType(BigInteger.class); 343 break; 344 case 'N': // bool 345 tr = classType(boolean.class); 346 break; 347 case '0': // array ?? 348 parseCVClassModifier(); 349 parseType(false); 350 tr = classType(Object[].class); 351 break; 352 case 'W': 353 tr = classType(char.class);//, Wide.class); 354 break; 355 default: 356 throw error(-1); 357 } 358 addBackRef(tr); 359 return tr; 360 case 'Z': 361 return classType(Object[].class); 362 case 'O': 363 throw error("'long double' type cannot be mapped !", -1); 364 case 'C': // signed char 365 case 'D': // char 366 case 'E': // unsigned char 367 return classType(byte.class); 368 case 'F': // short 369 case 'G': // unsigned short 370 return classType(short.class); 371 case 'H': // int 372 case 'I': // unsigned int 373 return classType(int.class); 374 case 'J': // long 375 case 'K': // unsigned long 376 return classType(CLong.class); 377 case 'M': // float 378 return classType(float.class); 379 case 'N': // double 380 return classType(double.class); 381 case 'Y': 382 throw error("TODO handle cointerfaces", -1); 383 case 'X': 384 // TODO handle coclass case 385 if (!allowVoid) { 386 return null; 387 } 388 return classType(void.class); 389 case '?': 390 parseCVClassModifier(); // TODO do something with this ! 391 return parseType(allowVoid); 392 case 'A': // reference 393 case 'B': // volatile reference 394 case 'P': // pointer 395 case 'Q': // const pointer 396 case 'R': // volatile pointer 397 case 'S': // const volatile pointer 398 if (!consumeCharsIf('$', 'A')) // __gc 399 { 400 consumeCharsIf('$', 'B'); // __pin 401 } 402 CVClassModifier cvMods = parseCVClassModifier(); 403 if (cvMods.isVariable) { 404 if (consumeCharIf('Y')) { 405 int dimensions = parseNumber(false); 406 int[] indices = new int[dimensions]; 407 for (int i = 0; i < dimensions; i++) { 408 indices[i] = parseNumber(false); 409 } 410 } 411 tr = pointerType(parseType(true)); 412 } else { 413 MemberRef mr = new MemberRef(); 414 parseFunctionProperty(mr); 415 tr = pointerType(new FunctionTypeRef(mr)); 416 } 417 addBackRef(tr); 418 return tr; 419 case 'V': // class 420 case 'U': // struct 421 case 'T': // union 422 //System.out.println("Found struct, class or union"); 423 return parseQualifiedTypeName(); 424 case 'W': // enum 425 Class<?> cl; 426 switch (consumeChar()) { 427 case '0': 428 case '1': 429 cl = byte.class; 430 break; 431 case '2': 432 case '3': 433 cl = short.class; 434 break; 435 case '4': 436 case '5': 437 cl = int.class; 438 break; 439 case '6': 440 case '7': // CLong : int on win32 and win64 ! 441 cl = int.class; 442 break; 443 default: 444 throw error("Unfinished enum", -1); 445 } 446 TypeRef qn = parseQualifiedTypeName(); 447 addBackRef(qn); 448 return classType(cl); 449 default: 450 throw error(-1); 451 } 452 } 453 454 static NamespaceRef reverseNamespace(List<Object> names) { 455 if (names == null || names.isEmpty()) { 456 return null; 457 } 458 Collections.reverse(names); 459 return new NamespaceRef(names.toArray()); 460 } 461 List<TypeRef> allQualifiedNames = new ArrayList<TypeRef>(); 462 463 interface DemanglingOp<T> { 464 465 T run() throws DemanglingException; 466 } 467 468 <T> T withEmptyQualifiedNames(DemanglingOp<T> action) throws DemanglingException { 469 List<TypeRef> list = allQualifiedNames; 470 try { 471 allQualifiedNames = new ArrayList<TypeRef>(); 472 return action.run(); 473 } finally { 474 allQualifiedNames = list; 475 } 476 } 477 478 IdentLike parseFirstQualifiedTypeNameComponent() throws DemanglingException { 479 if (consumeCharIf('?')) { 480 if (consumeCharIf('$')) { 481 return parseTemplateType().getIdent(); 482 } else { 483 return parseSpecialName(); 484 } 485 } else { 486 return new Ident(parseNameFragment()); 487 } 488 } 489 490 TypeRef parseQualifiedTypeName() throws DemanglingException { 491 TypeRef backRef = consumeIfBackRef(); 492 if (backRef != null) { 493 return backRef; 494 } 495 496 char c = peekChar(); 497 List<Object> names = parseNameQualifications(); 498 499 // TODO fix this : 500 //names.add(0, parseFirstQualifiedTypeNameComponent()); 501 Object first = names.get(0); 502 names.set(0, first instanceof String ? new Ident((String) first) : ((ClassRef) first).getIdent()); 503 504 if (names.size() == 1 && (names.get(0) instanceof TypeRef)) { 505 return (TypeRef) names.get(0); 506 } 507 508 /* 509 if (Character.isDigit(c)) { 510 consumeChar(); 511 int i = (int)(c - '0'); 512 if (i < 0 || i >= allQualifiedNames.size()) 513 throw error("Invalid back reference " + i + " (knows only " + allQualifiedNames + ")", -1); 514 names = new ArrayList<String>(allQualifiedNames.get(i)); 515 } else { 516 names = parseNames(); 517 }*/ 518 519 ClassRef tr = new ClassRef((Ident) names.get(0)); 520 names.remove(0); 521 tr.setEnclosingType(reverseNamespace(names)); 522 return tr; 523 } 524 525 public IdentLike parseSpecialName() throws DemanglingException { 526 switch (consumeChar()) { 527 case '0': 528 return SpecialName.Constructor; 529 case '1': 530 return SpecialName.Destructor; 531 case '2': 532 return SpecialName.New; 533 case '3': 534 return SpecialName.Delete; 535 case '4': 536 return SpecialName.OperatorAssign; 537 case '5': 538 return SpecialName.OperatorRShift; 539 case '6': 540 return SpecialName.OperatorLShift; 541 case '7': 542 return SpecialName.OperatorLogicNot; 543 case '8': 544 return SpecialName.OperatorEquals; 545 case '9': 546 return SpecialName.OperatorDifferent; 547 case 'A': 548 return SpecialName.OperatorSquareBrackets; 549 case 'B': 550 return SpecialName.OperatorCast; 551 case 'C': 552 return SpecialName.OperatorArrow; 553 case 'D': 554 return SpecialName.OperatorMultiply; 555 case 'E': 556 return SpecialName.OperatorIncrement; 557 case 'F': 558 return SpecialName.OperatorDecrement; 559 case 'G': 560 return SpecialName.OperatorSubstract; 561 case 'H': 562 return SpecialName.OperatorAdd; 563 case 'I': 564 return SpecialName.OperatorBitAnd; 565 case 'J': 566 return SpecialName.OperatorArrowStar; 567 case 'K': 568 return SpecialName.OperatorDivide; 569 case 'L': 570 return SpecialName.OperatorModulo; 571 case 'M': 572 return SpecialName.OperatorLower; 573 case 'N': 574 return SpecialName.OperatorLowerEquals; 575 case 'O': 576 return SpecialName.OperatorGreater; 577 case 'P': 578 return SpecialName.OperatorGreaterEquals; 579 case 'Q': 580 return SpecialName.OperatorComma; 581 case 'R': 582 return SpecialName.OperatorParenthesis; 583 case 'S': 584 return SpecialName.OperatorBitNot; 585 case 'T': 586 return SpecialName.OperatorXOR; 587 case 'U': 588 return SpecialName.OperatorBitOr; 589 case 'V': 590 return SpecialName.OperatorLogicAnd; 591 case 'W': 592 return SpecialName.OperatorLogicOr; 593 case 'X': 594 return SpecialName.OperatorMultiplyAssign; 595 case 'Y': 596 return SpecialName.OperatorAddAssign; 597 case 'Z': 598 return SpecialName.OperatorSubstractAssign; 599 case '_': 600 switch (consumeChar()) { 601 case '0': 602 return SpecialName.OperatorDivideAssign; 603 case '1': 604 return SpecialName.OperatorModuloAssign; 605 case '2': 606 return SpecialName.OperatorLShiftAssign; 607 case '3': 608 return SpecialName.OperatorRShiftAssign; 609 case '4': 610 return SpecialName.OperatorBitAndAssign; 611 case '5': 612 return SpecialName.OperatorBitOrAssign; 613 case '6': 614 return SpecialName.OperatorXORAssign; 615 case '7': 616 return SpecialName.VFTable; 617 case '8': 618 return SpecialName.VBTable; 619 case '9': 620 return SpecialName.VCall; 621 case 'E': 622 return SpecialName.VectorDeletingDestructor; 623 case 'G': 624 return SpecialName.ScalarDeletingDestructor; 625 default: 626 throw error("unhandled extended special name"); 627 } 628 629 default: 630 throw error("Invalid special name"); 631 } 632 } 633 634 private List<TypeRef> parseParams() throws DemanglingException { 635 List<TypeRef> paramTypes = new ArrayList<TypeRef>(); 636 if (!consumeCharIf('X')) { 637 char c; 638 while ((c = peekChar()) != '@' && c != 0 && (c != 'Z' || peekChar(2) == 'Z')) { 639 TypeRef tr = parseType(false); 640 if (tr == null) { 641 continue; 642 } 643 paramTypes.add(tr); 644 } 645 if (c == 'Z') { 646 consumeChar(); 647 } 648 //break; 649 if (c == '@') { 650 consumeChar(); 651 } 652 } 653 return paramTypes; 654 } 655 656 private List<TemplateArg> parseTemplateParams() throws DemanglingException { 657 return withEmptyQualifiedNames(new DemanglingOp<List<TemplateArg>>() { 658 public List<TemplateArg> run() throws DemanglingException { 659 List<TemplateArg> paramTypes = new ArrayList<TemplateArg>(); 660 if (!consumeCharIf('X')) { 661 char c; 662 while ((c = peekChar()) != '@' && c != 0) { 663 TemplateArg tr = parseTemplateParameter(); 664 if (tr == null) { 665 continue; 666 } 667 paramTypes.add(tr); 668 } 669 } 670 return paramTypes; 671 } 672 }); 673 } 674 675 String parseNameFragment() throws DemanglingException { 676 StringBuilder b = new StringBuilder(); 677 char c; 678 679 while ((c = consumeChar()) != '@') { 680 b.append(c); 681 } 682 683 if (b.length() == 0) { 684 throw new DemanglingException("Unexpected empty name fragment"); 685 } 686 687 String name = b.toString(); 688// allQualifiedNames.add(Collections.singletonList(name)); 689 return name; 690 } 691 692 void addBackRef(TypeRef tr) { 693 if (tr == null || allQualifiedNames.contains(tr)) { 694 return; 695 } 696 697 allQualifiedNames.add(tr); 698 } 699 700 TypeRef getBackRef(int i) throws DemanglingException { 701 if (i == allQualifiedNames.size()) { 702 i--; // TODO fix this !!! 703 } 704 if (i < 0 || i >= allQualifiedNames.size()) { 705 throw error("Invalid back references in name qualifications", -1); 706 } 707 return allQualifiedNames.get(i); 708 } 709 710 private List<Object> parseNameQualifications() throws DemanglingException { 711 List<Object> names = new ArrayList<Object>(); 712 713 if (Character.isDigit(peekChar())) { 714 try { 715 int i = consumeChar() - '0'; 716 names.add(getBackRef(i)); 717 expectChars('@'); 718 return names; 719 } catch (Exception ex) { 720 throw error("Invalid back references in name qualifications", -1); 721 } 722 } 723 724 while (peekChar() != '@') { 725 names.add(parseNameQualification()); 726 } 727 728 expectChars('@'); 729 return names; 730 } 731 732 Object parseNameQualification() throws DemanglingException { 733 if (consumeCharIf('?')) { 734 if (consumeCharIf('$')) { 735 return parseTemplateType(); 736 } else { 737 if (peekChar() == 'A') { 738 throw error("Anonymous numbered namespaces not handled yet"); 739 } 740 int namespaceNumber = parseNumber(false); 741 return String.valueOf(namespaceNumber); 742 } 743 } else { 744 return parseNameFragment(); 745 } 746 } 747 748 Style parseCallingConvention() throws DemanglingException { 749 Convention.Style cc; 750 boolean exported = true; 751 switch (consumeChar()) { 752 case 'A': 753 exported = false; 754 case 'B': 755 cc = Convention.Style.CDecl; 756 break; 757 case 'C': 758 exported = false; 759 case 'D': 760 cc = Convention.Style.Pascal; 761 break; 762 case 'E': 763 exported = false; 764 case 'F': 765 cc = Convention.Style.ThisCall; 766 break; 767 case 'G': 768 exported = false; 769 case 'H': 770 cc = Convention.Style.StdCall; 771 break; 772 case 'I': 773 exported = false; 774 case 'J': 775 cc = Convention.Style.FastCall; 776 break; 777 case 'K': 778 exported = false; 779 case 'L': 780 cc = null; 781 break; 782 case 'N': 783 cc = Convention.Style.CLRCall; 784 break; 785 default: 786 throw error("Unknown calling convention"); 787 } 788 return cc; 789 } 790 791 static class CVClassModifier { 792 793 boolean isVariable; 794 boolean isMember; 795 boolean isBased; 796 } 797 798 CVClassModifier parseCVClassModifier() throws DemanglingException { 799 CVClassModifier mod = new CVClassModifier(); 800 switch (peekChar()) { 801 case 'E': // __ptr64 802 case 'F': // __unaligned 803 case 'I': // __restrict 804 consumeChar(); 805 break; 806 } 807 boolean based = false; 808 switch (consumeChar()) { 809 case 'M': // __based 810 case 'N': // __based 811 case 'O': // __based 812 case 'P': // __based 813 mod.isBased = true; 814 case 'A': 815 case 'B': 816 case 'J': 817 case 'C': 818 case 'G': 819 case 'K': 820 case 'D': 821 case 'H': 822 case 'L': 823 mod.isVariable = true; 824 mod.isMember = false; 825 break; 826 case '2': // __based 827 case '3': // __based 828 case '4': // __based 829 case '5': // __based 830 mod.isBased = true; 831 case 'Q': 832 case 'U': 833 case 'Y': 834 case 'R': 835 case 'V': 836 case 'Z': 837 case 'S': 838 case 'W': 839 case '0': 840 case 'T': 841 case 'X': 842 case '1': 843 mod.isVariable = true; 844 mod.isMember = true; 845 break; 846 case '_': // __based 847 mod.isBased = true; 848 switch (consumeChar()) { 849 case 'A': 850 case 'B': 851 mod.isVariable = false; 852 break; 853 case 'C': 854 case 'D': 855 mod.isVariable = false; 856 mod.isMember = true; 857 break; 858 default: 859 throw error("Unknown extended __based class modifier", -1); 860 } 861 break; 862 case '6': 863 case '7': 864 mod.isVariable = false; 865 mod.isMember = false; 866 break; 867 case '8': 868 case '9': 869 mod.isVariable = false; 870 mod.isMember = true; 871 break; 872 default: 873 throw error("Unknown CV class modifier", -1); 874 } 875 if (mod.isBased) { 876 switch (consumeChar()) { 877 case '0': // __based(void) 878 break; 879 case '2': 880 parseNameQualifications(); 881 break; 882 case '5': // no __based() ?? 883 break; 884 } 885 } 886 return mod; 887 } 888}