1 16 17 package org.springframework.web.util; 18 19 27 class HtmlCharacterEntityDecoder { 28 29 private static final int MAX_REFERENCE_SIZE = 10; 30 31 32 private final HtmlCharacterEntityReferences characterEntityReferences; 33 34 private final String originalMessage; 35 36 private final StringBuffer decodedMessage; 37 38 private int currentPosition = 0; 39 40 private int nextPotentialReferencePosition = -1; 41 42 private int nextSemicolonPosition = -2; 43 44 45 public HtmlCharacterEntityDecoder(HtmlCharacterEntityReferences characterEntityReferences, String original) { 46 this.characterEntityReferences = characterEntityReferences; 47 this.originalMessage = original; 48 this.decodedMessage = new StringBuffer (originalMessage.length()); 49 } 50 51 public String decode() { 52 while (currentPosition < originalMessage.length()) { 53 findNextPotentialReference(currentPosition); 54 copyCharactersTillPotentialReference(); 55 processPossibleReference(); 56 } 57 return decodedMessage.toString(); 58 } 59 60 private void findNextPotentialReference(int startPosition) { 61 nextPotentialReferencePosition = Math.max(startPosition, nextSemicolonPosition - MAX_REFERENCE_SIZE); 62 63 do { 64 nextPotentialReferencePosition = 65 originalMessage.indexOf('&', nextPotentialReferencePosition); 66 67 if (nextSemicolonPosition != -1 && 68 nextSemicolonPosition < nextPotentialReferencePosition) 69 nextSemicolonPosition = originalMessage.indexOf(';', nextPotentialReferencePosition + 1); 70 71 boolean isPotentialReference = 72 nextPotentialReferencePosition != -1 73 && nextSemicolonPosition != -1 74 && nextPotentialReferencePosition - nextSemicolonPosition < MAX_REFERENCE_SIZE; 75 76 if (isPotentialReference) { 77 break; 78 } 79 if (nextPotentialReferencePosition == -1) { 80 break; 81 } 82 if (nextSemicolonPosition == -1) { 83 nextPotentialReferencePosition = -1; 84 break; 85 } 86 87 nextPotentialReferencePosition = nextPotentialReferencePosition + 1; 88 } 89 while (nextPotentialReferencePosition != -1); 90 } 91 92 93 private void copyCharactersTillPotentialReference() { 94 if (nextPotentialReferencePosition != currentPosition) { 95 int skipUntilIndex = nextPotentialReferencePosition != -1 ? 96 nextPotentialReferencePosition : originalMessage.length(); 97 if (skipUntilIndex - currentPosition > 3) { 98 decodedMessage.append(originalMessage.substring(currentPosition, skipUntilIndex)); 99 currentPosition = skipUntilIndex; 100 } 101 else { 102 while (currentPosition < skipUntilIndex) 103 decodedMessage.append(originalMessage.charAt(currentPosition++)); 104 } 105 } 106 } 107 108 private void processPossibleReference() { 109 if (nextPotentialReferencePosition != -1) { 110 boolean isNumberedReference = originalMessage.charAt(currentPosition + 1) == '#'; 111 boolean wasProcessable = isNumberedReference ? processNumberedReference() : processNamedReference(); 112 if (wasProcessable) { 113 currentPosition = nextSemicolonPosition + 1; 114 } 115 else { 116 char currentChar = originalMessage.charAt(currentPosition); 117 decodedMessage.append(currentChar); 118 currentPosition++; 119 } 120 } 121 } 122 123 private boolean processNumberedReference() { 124 boolean isHexNumberedReference = 125 originalMessage.charAt(nextPotentialReferencePosition + 2) == 'x' || 126 originalMessage.charAt(nextPotentialReferencePosition + 2) == 'X'; 127 try { 128 int value = (!isHexNumberedReference) ? 129 Integer.parseInt(getReferenceSubstring(2)) : 130 Integer.parseInt(getReferenceSubstring(3), 16); 131 decodedMessage.append((char) value); 132 return true; 133 } 134 catch (NumberFormatException ex) { 135 return false; 136 } 137 } 138 139 private boolean processNamedReference() { 140 String referenceName = getReferenceSubstring(1); 141 char mappedCharacter = characterEntityReferences.convertToCharacter(referenceName); 142 if (mappedCharacter != HtmlCharacterEntityReferences.CHAR_NULL) { 143 decodedMessage.append(mappedCharacter); 144 return true; 145 } 146 return false; 147 } 148 149 private String getReferenceSubstring(int referenceOffset) { 150 return originalMessage.substring(nextPotentialReferencePosition + referenceOffset, nextSemicolonPosition); 151 } 152 153 } 154 | Popular Tags |