|
@@ -1,12 +1,11 @@ |
1 |
1 |
|
package com.temp.shared.utils; |
2 |
2 |
|
|
3 |
|
- |
import java.util.ArrayList; |
4 |
|
- |
import java.util.List; |
|
3 |
+ |
import java.util.*; |
5 |
4 |
|
|
6 |
5 |
|
/** |
7 |
6 |
|
* Class to encode (& package) AND decode (& unpackage) multiple strings to and |
8 |
7 |
|
* from a single HTML Friendly String. |
9 |
|
- |
* |
|
8 |
+ |
* <p/> |
10 |
9 |
|
* Because IE will process this data and apply the "whitespace" rule - all |
11 |
10 |
|
* consecutive whitespace character(s) are converted to a SINGLE space, the |
12 |
11 |
|
* encoded form must NOT have whitespace in it unless it is already a single |
|
@@ -17,31 +16,30 @@ |
17 |
16 |
|
public class HtmlFriendlySectionCodec { |
18 |
17 |
|
private static final char SPACE = ' '; |
19 |
18 |
|
private static final char NEWLINE = '\n'; |
20 |
|
- |
private static final char[] SPACE_OPTIONS = { '~', '^' }; |
21 |
|
- |
private static final char[] NEWLINE_OPTIONS = { '|', '#' }; |
22 |
|
- |
private static final char[] SEPARATOR_OPTIONS = { '=', '*' }; |
|
19 |
+ |
private static final char[] SPACE_OPTIONS = {'~', '^'}; |
|
20 |
+ |
private static final char[] NEWLINE_OPTIONS = {'|', '#'}; |
|
21 |
+ |
private static final char[] SEPARATOR_OPTIONS = {'=', '*'}; |
23 |
22 |
|
|
24 |
23 |
|
/** |
25 |
24 |
|
* Encode the sections to a single HTML friendly string. |
26 |
25 |
|
* |
27 |
|
- |
* @param sections |
28 |
|
- |
* !null or empty, and no array entries may be null |
|
26 |
+ |
* @param sections !null or empty, and no array entries may be null |
29 |
27 |
|
* |
30 |
28 |
|
* @return single HTML friendly string ready to be decoded |
31 |
29 |
|
*/ |
32 |
|
- |
public static String encode(String... sections) { |
33 |
|
- |
String space = determineSeparator(SPACE_OPTIONS, 1, sections); |
34 |
|
- |
String newLine = determineSeparator(NEWLINE_OPTIONS, 1, sections); |
35 |
|
- |
String separator = determineSeparator(SEPARATOR_OPTIONS, 8, sections); |
|
30 |
+ |
public static String encode( String... sections ) { |
|
31 |
+ |
String space = determineSeparator( SPACE_OPTIONS, 1, sections ); |
|
32 |
+ |
String newLine = determineSeparator( NEWLINE_OPTIONS, 1, sections ); |
|
33 |
+ |
String separator = determineSeparator( SEPARATOR_OPTIONS, 8, sections ); |
36 |
34 |
|
|
37 |
35 |
|
StringBuilder sb = new StringBuilder(); |
38 |
36 |
|
// Header |
39 |
|
- |
sb.append(newLine).append(SPACE).append(space).append(SPACE).append(separator).append(SPACE).append(newLine).append(NEWLINE); |
|
37 |
+ |
sb.append( newLine ).append( SPACE ).append( space ).append( SPACE ).append( separator ).append( SPACE ).append( newLine ).append( NEWLINE ); |
40 |
38 |
|
// Sections |
41 |
|
- |
SectionCodec sectionCodec = new SectionCodec(space, newLine); |
42 |
|
- |
for (String section : sections) { |
43 |
|
- |
sectionCodec.encode(section, sb); |
44 |
|
- |
sb.append(NEWLINE).append(separator).append(NEWLINE); |
|
39 |
+ |
SectionCodec sectionCodec = new SectionCodec( space, newLine ); |
|
40 |
+ |
for ( String section : sections ) { |
|
41 |
+ |
sectionCodec.encode( section, sb ); |
|
42 |
+ |
sb.append( NEWLINE ).append( separator ).append( NEWLINE ); |
45 |
43 |
|
} |
46 |
44 |
|
return sb.toString(); |
47 |
45 |
|
} |
|
@@ -49,62 +47,61 @@ |
49 |
47 |
|
/** |
50 |
48 |
|
* Decode the sections from a single HTML friendly string. |
51 |
49 |
|
* |
52 |
|
- |
* @param encodedSections |
53 |
|
- |
* !null or empty (must have at least the Header - see above) |
|
50 |
+ |
* @param encodedSections !null or empty (must have at least the Header - see above) |
54 |
51 |
|
* |
55 |
52 |
|
* @return the decoded sections |
56 |
53 |
|
*/ |
57 |
|
- |
public static String[] decode(String encodedSections) { |
|
54 |
+ |
public static String[] decode( String encodedSections ) { |
58 |
55 |
|
// Header |
59 |
|
- |
int spAt1 = encodedSections.indexOf(SPACE); |
60 |
|
- |
int spAt2 = encodedSections.indexOf(SPACE, spAt1 + 1); |
61 |
|
- |
int spAt3 = encodedSections.indexOf(SPACE, spAt2 + 1); |
62 |
|
- |
if (spAt3 == -1) { |
63 |
|
- |
throw invalidHeader(encodedSections); |
64 |
|
- |
} |
65 |
|
- |
String newLine = Assert.noEmpty("Header newLine", encodedSections.substring(0, spAt1)); |
66 |
|
- |
String space = Assert.noEmpty("Header space", encodedSections.substring(spAt1 + 1, spAt2)); |
67 |
|
- |
String separator = Assert.noEmpty("Header separator", encodedSections.substring(spAt2 + 1, spAt3)); |
|
56 |
+ |
int spAt1 = encodedSections.indexOf( SPACE ); |
|
57 |
+ |
int spAt2 = encodedSections.indexOf( SPACE, spAt1 + 1 ); |
|
58 |
+ |
int spAt3 = encodedSections.indexOf( SPACE, spAt2 + 1 ); |
|
59 |
+ |
if ( spAt3 == -1 ) { |
|
60 |
+ |
throw invalidHeader( encodedSections ); |
|
61 |
+ |
} |
|
62 |
+ |
String newLine = Assert.noEmpty( "Header newLine", encodedSections.substring( 0, spAt1 ) ); |
|
63 |
+ |
String space = Assert.noEmpty( "Header space", encodedSections.substring( spAt1 + 1, spAt2 ) ); |
|
64 |
+ |
String separator = Assert.noEmpty( "Header separator", encodedSections.substring( spAt2 + 1, spAt3 ) ); |
68 |
65 |
|
|
69 |
|
- |
if (!encodedSections.substring(spAt3 + 1).startsWith(newLine)) { |
70 |
|
- |
throw invalidHeader(encodedSections); |
|
66 |
+ |
if ( !encodedSections.substring( spAt3 + 1 ).startsWith( newLine ) ) { |
|
67 |
+ |
throw invalidHeader( encodedSections ); |
71 |
68 |
|
} |
72 |
69 |
|
// Sections |
73 |
|
- |
String sectionsText = encodedSections.substring(spAt3 + 1 + newLine.length()).replace(NEWLINE, SPACE).trim(); |
74 |
|
- |
if (sectionsText.length() == 0) { |
|
70 |
+ |
String sectionsText = encodedSections.substring( spAt3 + 1 + newLine.length() ).replace( NEWLINE, SPACE ).trim(); |
|
71 |
+ |
if ( sectionsText.length() == 0 ) { |
75 |
72 |
|
return new String[0]; // Empty Array |
76 |
73 |
|
} |
77 |
|
- |
SectionCodec sectionCodec = new SectionCodec(space, newLine); |
|
74 |
+ |
SectionCodec sectionCodec = new SectionCodec( space, newLine ); |
78 |
75 |
|
List<String> sections = new ArrayList<String>(); |
79 |
|
- |
for (int at; -1 != (at = sectionsText.indexOf(separator)); sectionsText = sectionsText.substring(at + separator.length()).trim()) { |
80 |
|
- |
String section = sectionsText.substring(0, at); |
81 |
|
- |
sections.add(sectionCodec.decode(section)); |
|
76 |
+ |
for ( int at; -1 != (at = sectionsText.indexOf( separator )); sectionsText = sectionsText.substring( at + separator.length() ).trim() ) { |
|
77 |
+ |
String section = sectionsText.substring( 0, at ); |
|
78 |
+ |
sections.add( sectionCodec.decode( section ) ); |
82 |
79 |
|
} |
83 |
|
- |
if (sectionsText.length() != 0) { |
84 |
|
- |
throw new IllegalArgumentException("Junk after last section: '" + sectionsText + "'"); |
|
80 |
+ |
if ( sectionsText.length() != 0 ) { |
|
81 |
+ |
throw new IllegalArgumentException( "Junk after last section: '" + sectionsText + "'" ); |
85 |
82 |
|
} |
86 |
|
- |
return sections.toArray(new String[sections.size()]); |
|
83 |
+ |
return sections.toArray( new String[sections.size()] ); |
87 |
84 |
|
} |
88 |
85 |
|
|
89 |
|
- |
private static IllegalArgumentException invalidHeader(String encodedSections) { |
90 |
|
- |
return new IllegalArgumentException("Unable to extract the 'Header' from " + encodedSections); |
|
86 |
+ |
private static IllegalArgumentException invalidHeader( String encodedSections ) { |
|
87 |
+ |
return new IllegalArgumentException( "Unable to extract the 'Header' from " + encodedSections ); |
91 |
88 |
|
} |
92 |
89 |
|
|
93 |
|
- |
private static String determineSeparator(char[] options, int lengthFactor, String[] sections) { |
94 |
|
- |
for (int blockSize = lengthFactor; true; blockSize += lengthFactor) { |
95 |
|
- |
for (char option : options) { |
96 |
|
- |
StringBuilder sb = new StringBuilder(blockSize); |
97 |
|
- |
for (int i = 0; i < blockSize; i++) { |
98 |
|
- |
sb.append(option); |
|
90 |
+ |
private static String determineSeparator( char[] options, int lengthFactor, String[] sections ) { |
|
91 |
+ |
for ( int blockSize = lengthFactor; true; blockSize += lengthFactor ) { |
|
92 |
+ |
for ( char option : options ) { |
|
93 |
+ |
StringBuilder sb = new StringBuilder( blockSize ); |
|
94 |
+ |
for ( int i = 0; i < blockSize; i++ ) { |
|
95 |
+ |
sb.append( option ); |
99 |
96 |
|
} |
100 |
97 |
|
boolean acceptable = true; |
101 |
|
- |
for (String section : sections) { |
102 |
|
- |
if (section.contains(sb)) { |
|
98 |
+ |
for ( String section : sections ) { |
|
99 |
+ |
if ( section.contains( sb ) ) { |
103 |
100 |
|
acceptable = false; |
104 |
101 |
|
break; |
105 |
102 |
|
} |
106 |
103 |
|
} |
107 |
|
- |
if (acceptable) { |
|
104 |
+ |
if ( acceptable ) { |
108 |
105 |
|
return sb.toString(); // The Separator we'll use |
109 |
106 |
|
} |
110 |
107 |
|
} |
|
@@ -115,70 +112,70 @@ |
115 |
112 |
|
private String space; |
116 |
113 |
|
private String newLine; |
117 |
114 |
|
|
118 |
|
- |
public SectionCodec(String space, String newLine) { |
|
115 |
+ |
public SectionCodec( String space, String newLine ) { |
119 |
116 |
|
this.space = space; |
120 |
117 |
|
this.newLine = newLine; |
121 |
118 |
|
} |
122 |
119 |
|
|
123 |
|
- |
public void encode(String section, StringBuilder sb) { |
124 |
|
- |
for (int i = 0; i < section.length(); i++) { |
125 |
|
- |
char c = section.charAt(i); |
126 |
|
- |
if (c == SPACE) { |
127 |
|
- |
sb.append(space); |
128 |
|
- |
} else if (c == NEWLINE) { |
129 |
|
- |
sb.append(newLine).append(NEWLINE); |
|
120 |
+ |
public void encode( String section, StringBuilder sb ) { |
|
121 |
+ |
for ( int i = 0; i < section.length(); i++ ) { |
|
122 |
+ |
char c = section.charAt( i ); |
|
123 |
+ |
if ( c == SPACE ) { |
|
124 |
+ |
sb.append( space ); |
|
125 |
+ |
} else if ( c == NEWLINE ) { |
|
126 |
+ |
sb.append( newLine ).append( NEWLINE ); |
130 |
127 |
|
} else { |
131 |
|
- |
HtmlEntity.append(c, sb); |
|
128 |
+ |
HtmlEntity.append( c, sb ); |
132 |
129 |
|
} |
133 |
130 |
|
} |
134 |
131 |
|
} |
135 |
132 |
|
|
136 |
|
- |
public String decode(String section) { |
137 |
|
- |
StringBuilder sb = new StringBuilder(section); |
138 |
|
- |
purgeAll(sb, SPACE); |
139 |
|
- |
purgeAll(sb, NEWLINE); |
140 |
|
- |
replaceAll(sb, space, SPACE); |
141 |
|
- |
replaceAll(sb, newLine, NEWLINE); |
142 |
|
- |
int ampAt = sb.indexOf("&"); |
143 |
|
- |
if (ampAt != -1) { |
|
133 |
+ |
public String decode( String section ) { |
|
134 |
+ |
StringBuilder sb = new StringBuilder( section ); |
|
135 |
+ |
purgeAll( sb, SPACE ); |
|
136 |
+ |
purgeAll( sb, NEWLINE ); |
|
137 |
+ |
replaceAll( sb, space, SPACE ); |
|
138 |
+ |
replaceAll( sb, newLine, NEWLINE ); |
|
139 |
+ |
int ampAt = sb.indexOf( "&" ); |
|
140 |
+ |
if ( ampAt != -1 ) { |
144 |
141 |
|
int from = 0; |
145 |
142 |
|
do { |
146 |
|
- |
String entity = extractEntity(sb, ampAt); |
147 |
|
- |
char c = HtmlEntity.fromStringForm(entity); |
148 |
|
- |
replace(sb, entity, ampAt, c); |
|
143 |
+ |
String entity = extractEntity( sb, ampAt ); |
|
144 |
+ |
char c = HtmlEntity.fromStringForm( entity ); |
|
145 |
+ |
replace( sb, entity, ampAt, c ); |
149 |
146 |
|
from = ampAt + 1; |
150 |
|
- |
} while (-1 != (ampAt = sb.indexOf("&", from))); |
|
147 |
+ |
} while ( -1 != (ampAt = sb.indexOf( "&", from )) ); |
151 |
148 |
|
} |
152 |
149 |
|
return sb.toString(); |
153 |
150 |
|
} |
154 |
151 |
|
|
155 |
|
- |
private String extractEntity(StringBuilder sb, int ampAt) { |
156 |
|
- |
int semiAt = sb.indexOf(";", ampAt); |
157 |
|
- |
if (semiAt == -1) { |
158 |
|
- |
throw new IllegalArgumentException("Not an Html Entity starting at: " + sb.substring(ampAt)); |
159 |
|
- |
} |
160 |
|
- |
return sb.substring(ampAt, semiAt + 1); |
|
152 |
+ |
private String extractEntity( StringBuilder sb, int ampAt ) { |
|
153 |
+ |
int semiAt = sb.indexOf( ";", ampAt ); |
|
154 |
+ |
if ( semiAt == -1 ) { |
|
155 |
+ |
throw new IllegalArgumentException( "Not an Html Entity starting at: " + sb.substring( ampAt ) ); |
|
156 |
+ |
} |
|
157 |
+ |
return sb.substring( ampAt, semiAt + 1 ); |
161 |
158 |
|
} |
162 |
159 |
|
|
163 |
|
- |
private void purgeAll(StringBuilder sb, char characterToRemove) { |
164 |
|
- |
for (int i = sb.length() - 1; 0 <= i; i--) { |
165 |
|
- |
if (characterToRemove == sb.charAt(i)) { |
166 |
|
- |
sb.deleteCharAt(i); |
|
160 |
+ |
private void purgeAll( StringBuilder sb, char characterToRemove ) { |
|
161 |
+ |
for ( int i = sb.length() - 1; 0 <= i; i-- ) { |
|
162 |
+ |
if ( characterToRemove == sb.charAt( i ) ) { |
|
163 |
+ |
sb.deleteCharAt( i ); |
167 |
164 |
|
} |
168 |
165 |
|
} |
169 |
166 |
|
} |
170 |
167 |
|
|
171 |
|
- |
private void replaceAll(StringBuilder sb, String stringToReplace, char replacementChar) { |
172 |
|
- |
for (int at; -1 != (at = sb.indexOf(stringToReplace));) { |
173 |
|
- |
replace(sb, stringToReplace, at, replacementChar); |
|
168 |
+ |
private void replaceAll( StringBuilder sb, String stringToReplace, char replacementChar ) { |
|
169 |
+ |
for ( int at; -1 != (at = sb.indexOf( stringToReplace )); ) { |
|
170 |
+ |
replace( sb, stringToReplace, at, replacementChar ); |
174 |
171 |
|
} |
175 |
172 |
|
} |
176 |
173 |
|
|
177 |
|
- |
private void replace(StringBuilder sb, String stringToReplace, int at, char replacementChar) { |
|
174 |
+ |
private void replace( StringBuilder sb, String stringToReplace, int at, char replacementChar ) { |
178 |
175 |
|
// remove all but one |
179 |
|
- |
sb.delete(at, at + (stringToReplace.length() - 1)); |
|
176 |
+ |
sb.delete( at, at + (stringToReplace.length() - 1) ); |
180 |
177 |
|
// then replace the one remaining! |
181 |
|
- |
sb.setCharAt(at, replacementChar); |
|
178 |
+ |
sb.setCharAt( at, replacementChar ); |
182 |
179 |
|
} |
183 |
180 |
|
} |
184 |
181 |
|
} |