private Map readProps(bool listVals) // listVals is Str:Str[]
{
Charset origCharset = charset();
charset(Charset.utf8());
try
{
Map props = new Map(Sys.StrType, listVals ? Sys.StrType.toListOf() : Sys.StrType);
StringBuilder name = new StringBuilder();
StringBuilder val = null;
int inBlockComment = 0;
bool inEndOfLineComment = false;
int c = ' ', last = ' ';
int lineNum = 1;
while (true)
{
last = c;
c = rChar();
if (c < 0)
{
break;
}
// end of line
if (c == '\n' || c == '\r')
{
inEndOfLineComment = false;
if (last == '\r' && c == '\n')
{
continue;
}
string n = FanStr.makeTrim(name);
if (val != null)
{
addProp(props, n, FanStr.makeTrim(val), listVals);
name = new StringBuilder();
val = null;
}
else if (n.Length > 0)
{
throw IOErr.make("Invalid name/value pair [Line " + lineNum + "]").val;
}
lineNum++;
continue;
}
// if in comment
if (inEndOfLineComment)
{
continue;
}
// block comment
if (inBlockComment > 0)
{
if (last == '/' && c == '*')
{
inBlockComment++;
}
if (last == '*' && c == '/')
{
inBlockComment--;
}
continue;
}
// equal
if (c == '=' && val == null)
{
val = new StringBuilder();
continue;
}
// comment
if (c == '/' && FanInt.isSpace(last))
{
int peek = rChar();
if (peek < 0)
{
break;
}
if (peek == '/')
{
inEndOfLineComment = true; continue;
}
if (peek == '*')
{
inBlockComment++; continue;
}
unreadChar(peek);
}
// escape or line continuation
if (c == '\\')
{
int peek = rChar();
if (peek < 0)
{
break;
}
else if (peek == 'n')
{
c = '\n';
}
else if (peek == 'r')
{
c = '\r';
}
else if (peek == 't')
{
c = '\t';
}
else if (peek == '\\')
{
c = '\\';
}
else if (peek == '\r' || peek == '\n')
{
// line continuation
lineNum++;
if (peek == '\r')
{
peek = rChar();
if (peek != '\n')
{
unreadChar(peek);
}
}
while (true)
{
peek = rChar();
if (peek == ' ' || peek == '\t')
{
continue;
}
unreadChar(peek);
break;
}
continue;
}
else if (peek == 'u')
{
int n3 = hex(rChar());
int n2 = hex(rChar());
int n1 = hex(rChar());
int n0 = hex(rChar());
if (n3 < 0 || n2 < 0 || n1 < 0 || n0 < 0)
{
throw IOErr.make("Invalid hex value for \\uxxxx [Line " + lineNum + "]").val;
}
c = ((n3 << 12) | (n2 << 8) | (n1 << 4) | n0);
}
else
{
throw IOErr.make("Invalid escape sequence [Line " + lineNum + "]").val;
}
}
// normal character
if (val == null)
{
name.Append((char)c);
}
else
{
val.Append((char)c);
}
}
string nm = FanStr.makeTrim(name);
if (val != null)
{
addProp(props, nm, FanStr.makeTrim(val), listVals);
}
else if (nm.Length > 0)
{
throw IOErr.make("Invalid name/value pair [Line " + lineNum + "]").val;
}
return(props);
}
finally
{
try { close(); } catch (System.Exception e) { Err.dumpStack(e); }
charset(origCharset);
}
}