Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Browse the repository at this point in the history
Fixed JENKINS-11066
- Loading branch information
1 parent
94db175
commit 0c98e30
Showing
5 changed files
with
283 additions
and
11 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
270 changes: 270 additions & 0 deletions
270
src/main/java/org/jenkinsci/plugins/envinject/util/SortedProperties.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,270 @@ | ||
package org.jenkinsci.plugins.envinject.util; | ||
|
||
|
||
import java.io.IOException; | ||
import java.io.InputStream; | ||
import java.io.Reader; | ||
import java.util.LinkedHashMap; | ||
|
||
/** | ||
* @author Gregory Boissinot | ||
*/ | ||
public class SortedProperties extends LinkedHashMap<Object, Object> { | ||
|
||
|
||
class LineReader { | ||
public LineReader(InputStream inStream) { | ||
this.inStream = inStream; | ||
inByteBuf = new byte[8192]; | ||
} | ||
|
||
public LineReader(Reader reader) { | ||
this.reader = reader; | ||
inCharBuf = new char[8192]; | ||
} | ||
|
||
byte[] inByteBuf; | ||
char[] inCharBuf; | ||
char[] lineBuf = new char[1024]; | ||
int inLimit = 0; | ||
int inOff = 0; | ||
InputStream inStream; | ||
Reader reader; | ||
|
||
int readLine() throws IOException { | ||
int len = 0; | ||
char c = 0; | ||
|
||
boolean skipWhiteSpace = true; | ||
boolean isCommentLine = false; | ||
boolean isNewLine = true; | ||
boolean appendedLineBegin = false; | ||
boolean precedingBackslash = false; | ||
boolean skipLF = false; | ||
while (true) { | ||
if (inOff >= inLimit) { | ||
inLimit = (inStream == null) ? reader.read(inCharBuf) | ||
: inStream.read(inByteBuf); | ||
inOff = 0; | ||
if (inLimit <= 0) { | ||
if (len == 0 || isCommentLine) { | ||
return -1; | ||
} | ||
return len; | ||
} | ||
} | ||
if (inStream != null) { | ||
//The line below is equivalent to calling a | ||
//ISO8859-1 decoder. | ||
c = (char) (0xff & inByteBuf[inOff++]); | ||
} else { | ||
c = inCharBuf[inOff++]; | ||
} | ||
if (skipLF) { | ||
skipLF = false; | ||
if (c == '\n') { | ||
continue; | ||
} | ||
} | ||
if (skipWhiteSpace) { | ||
if (c == ' ' || c == '\t' || c == '\f') { | ||
continue; | ||
} | ||
if (!appendedLineBegin && (c == '\r' || c == '\n')) { | ||
continue; | ||
} | ||
skipWhiteSpace = false; | ||
appendedLineBegin = false; | ||
} | ||
if (isNewLine) { | ||
isNewLine = false; | ||
if (c == '#' || c == '!') { | ||
isCommentLine = true; | ||
continue; | ||
} | ||
} | ||
|
||
if (c != '\n' && c != '\r') { | ||
lineBuf[len++] = c; | ||
if (len == lineBuf.length) { | ||
int newLength = lineBuf.length * 2; | ||
if (newLength < 0) { | ||
newLength = Integer.MAX_VALUE; | ||
} | ||
char[] buf = new char[newLength]; | ||
System.arraycopy(lineBuf, 0, buf, 0, lineBuf.length); | ||
lineBuf = buf; | ||
} | ||
//flip the preceding backslash flag | ||
if (c == '\\') { | ||
precedingBackslash = !precedingBackslash; | ||
} else { | ||
precedingBackslash = false; | ||
} | ||
} else { | ||
// reached EOL | ||
if (isCommentLine || len == 0) { | ||
isCommentLine = false; | ||
isNewLine = true; | ||
skipWhiteSpace = true; | ||
len = 0; | ||
continue; | ||
} | ||
if (inOff >= inLimit) { | ||
inLimit = (inStream == null) | ||
? reader.read(inCharBuf) | ||
: inStream.read(inByteBuf); | ||
inOff = 0; | ||
if (inLimit <= 0) { | ||
return len; | ||
} | ||
} | ||
if (precedingBackslash) { | ||
len -= 1; | ||
//skip the leading whitespace characters in following line | ||
skipWhiteSpace = true; | ||
appendedLineBegin = true; | ||
precedingBackslash = false; | ||
if (c == '\r') { | ||
skipLF = true; | ||
} | ||
} else { | ||
return len; | ||
} | ||
} | ||
} | ||
} | ||
|
||
|
||
} | ||
|
||
public synchronized void load(Reader reader) throws IOException { | ||
load0(new LineReader(reader)); | ||
} | ||
|
||
|
||
private void load0(LineReader lr) throws IOException { | ||
char[] convtBuf = new char[1024]; | ||
int limit; | ||
int keyLen; | ||
int valueStart; | ||
char c; | ||
boolean hasSep; | ||
boolean precedingBackslash; | ||
while ((limit = lr.readLine()) >= 0) { | ||
c = 0; | ||
keyLen = 0; | ||
valueStart = limit; | ||
hasSep = false; | ||
|
||
//System.out.println("line=<" + new String(lineBuf, 0, limit) + ">"); | ||
precedingBackslash = false; | ||
while (keyLen < limit) { | ||
c = lr.lineBuf[keyLen]; | ||
//need check if escaped. | ||
if ((c == '=' || c == ':') && !precedingBackslash) { | ||
valueStart = keyLen + 1; | ||
hasSep = true; | ||
break; | ||
} else if ((c == ' ' || c == '\t' || c == '\f') && !precedingBackslash) { | ||
valueStart = keyLen + 1; | ||
break; | ||
} | ||
if (c == '\\') { | ||
precedingBackslash = !precedingBackslash; | ||
} else { | ||
precedingBackslash = false; | ||
} | ||
keyLen++; | ||
} | ||
while (valueStart < limit) { | ||
c = lr.lineBuf[valueStart]; | ||
if (c != ' ' && c != '\t' && c != '\f') { | ||
if (!hasSep && (c == '=' || c == ':')) { | ||
hasSep = true; | ||
} else { | ||
break; | ||
} | ||
} | ||
valueStart++; | ||
} | ||
String key = loadConvert(lr.lineBuf, 0, keyLen, convtBuf); | ||
String value = loadConvert(lr.lineBuf, valueStart, limit - valueStart, convtBuf); | ||
put(key, value); | ||
} | ||
|
||
|
||
} | ||
|
||
private String loadConvert(char[] in, int off, int len, char[] convtBuf) { | ||
if (convtBuf.length < len) { | ||
int newLen = len * 2; | ||
if (newLen < 0) { | ||
newLen = Integer.MAX_VALUE; | ||
} | ||
convtBuf = new char[newLen]; | ||
} | ||
char aChar; | ||
char[] out = convtBuf; | ||
int outLen = 0; | ||
int end = off + len; | ||
|
||
while (off < end) { | ||
aChar = in[off++]; | ||
if (aChar == '\\') { | ||
aChar = in[off++]; | ||
if (aChar == 'u') { | ||
// Read the xxxx | ||
int value = 0; | ||
for (int i = 0; i < 4; i++) { | ||
aChar = in[off++]; | ||
switch (aChar) { | ||
case '0': | ||
case '1': | ||
case '2': | ||
case '3': | ||
case '4': | ||
case '5': | ||
case '6': | ||
case '7': | ||
case '8': | ||
case '9': | ||
value = (value << 4) + aChar - '0'; | ||
break; | ||
case 'a': | ||
case 'b': | ||
case 'c': | ||
case 'd': | ||
case 'e': | ||
case 'f': | ||
value = (value << 4) + 10 + aChar - 'a'; | ||
break; | ||
case 'A': | ||
case 'B': | ||
case 'C': | ||
case 'D': | ||
case 'E': | ||
case 'F': | ||
value = (value << 4) + 10 + aChar - 'A'; | ||
break; | ||
default: | ||
throw new IllegalArgumentException( | ||
"Malformed \\uxxxx encoding."); | ||
} | ||
} | ||
out[outLen++] = (char) value; | ||
} else { | ||
if (aChar == 't') aChar = '\t'; | ||
else if (aChar == 'r') aChar = '\r'; | ||
else if (aChar == 'n') aChar = '\n'; | ||
else if (aChar == 'f') aChar = '\f'; | ||
out[outLen++] = aChar; | ||
} | ||
} else { | ||
out[outLen++] = aChar; | ||
} | ||
} | ||
return new String(out, 0, outLen); | ||
} | ||
|
||
} |