package org.develnext.jphp.zend.ext.standard; import org.develnext.jphp.zend.ext.support.NaturalOrderComparator; import php.runtime.Memory; import php.runtime.annotation.Runtime.Immutable; import php.runtime.annotation.Runtime.Reference; import php.runtime.common.DigestUtils; import php.runtime.common.Messages; import php.runtime.common.StringUtils; import php.runtime.env.Environment; import php.runtime.env.TraceInfo; import php.runtime.exceptions.TodoException; import php.runtime.ext.core.MathFunctions; import php.runtime.ext.support.compile.FunctionsContainer; import php.runtime.lang.ForeachIterator; import php.runtime.memory.*; import php.runtime.util.PrintF; import php.runtime.util.SScanF; import javax.xml.bind.DatatypeConverter; import java.io.*; import java.net.URI; import java.net.URLDecoder; import java.net.URLEncoder; import java.nio.charset.StandardCharsets; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.text.DecimalFormat; import java.text.DecimalFormatSymbols; import java.util.Arrays; import java.util.HashSet; import java.util.Set; import java.util.UUID; import java.util.concurrent.atomic.AtomicLong; import java.util.zip.CRC32; import java.util.zip.GZIPInputStream; import java.util.zip.GZIPOutputStream; /** * TODO: * - addcslashes * - bin2hex ? * - chunk_split */ public class StringFunctions extends FunctionsContainer { private static final DecimalFormatSymbols DEFAULT_DECIMAL_FORMAT_SYMBOLS; private static final StringConstants constants = new StringConstants(); private static final ArrayMemory HTML_ENTITIES; private static final ArrayMemory HTML_SPECIALCHARS; protected static char toUUChar(int d) { if (d == 0) return (char) 0x60; else return (char) (0x20 + (d & 0x3f)); } protected static boolean isWhitespace(char ch) { return ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r'; } protected static char toUpperCase(char ch) { if (ch >= 'a' && ch <= 'z') return (char) ('A' + (ch - 'a')); else return ch; } protected static char toHexChar(int d) { d &= 0xf; if (d < 10) return (char) (d + '0'); else return (char) (d - 10 + 'a'); } protected static char toUpperHexChar(int d) { d &= 0xf; if (d < 10) return (char) (d + '0'); else return (char) (d - 10 + 'A'); } protected static int hexToDigit(char ch) { if ('0' <= ch && ch <= '9') return ch - '0'; else if ('a' <= ch && ch <= 'f') return ch - 'a' + 10; else if ('A' <= ch && ch <= 'F') return ch - 'A' + 10; else return -1; } protected static int octToDigit(char ch) { if ('0' <= ch && ch <= '7') return ch - '0'; else return -1; } public static Memory sscanf(Environment env, TraceInfo trace, String string, String format, @Reference Memory... args) { SScanF.Segment[] formatArray = SScanF.parse(env, trace, format); int strlen = string.length(); int sIndex = 0; boolean isReturnArray = args == null || args.length == 0; int argIndex = 0; if (strlen == 0) { return isReturnArray ? Memory.NULL : Memory.CONST_INT_M1; } ArrayMemory array = new ArrayMemory(); for (int i = 0; i < formatArray.length; i++) { SScanF.Segment segment = formatArray[i]; Memory var; if (!segment.isAssigned()) { var = null; } else if (isReturnArray) { var = array; } else { if (argIndex < args.length) { var = args[argIndex]; if (sIndex < strlen) argIndex++; } else { env.warning(trace, "sscanf(): not enough variables passed in"); var = new ReferenceMemory(); } } if (!(var instanceof ReferenceMemory)) var = new ReferenceMemory(var); sIndex = segment.apply(string, strlen, sIndex, (ReferenceMemory) var, isReturnArray); if (sIndex < 0) { if (isReturnArray) return sscanfFillNull(array, formatArray, i); else return LongMemory.valueOf(argIndex); } } return sscanfReturn(env, trace, array, args, argIndex, isReturnArray, false); } private static Memory sscanfReturn(Environment env, TraceInfo trace, ArrayMemory array, Memory[] args, int argIndex, boolean isReturnArray, boolean isWarn) { if (isReturnArray) return array; else { if (isWarn && args != null && argIndex != args.length) env.warning(trace, "%s vars passed in but saw only %s '%' args", args.length, argIndex); return LongMemory.valueOf(argIndex); } } private static Memory sscanfFillNull(ArrayMemory array, SScanF.Segment[] formatArray, int fIndex) { for (; fIndex < formatArray.length; fIndex++) { SScanF.Segment segment = formatArray[fIndex]; if (segment.isAssigned()) array.add(Memory.NULL); } return array; } public static Memory sprintf(Environment env, TraceInfo trace, String format, Memory... args) { PrintF printF = new PrintF(env.getLocale(), format, args); String result = printF.toString(); if (result == null) { env.warning(trace, "Too few arguments"); return Memory.NULL; } else return new StringMemory(result); } public static Memory vsprintf(Environment env, TraceInfo trace, String format, Memory array) { if (array.isArray()) { return sprintf(env, trace, format, array.toValue(ArrayMemory.class).values()); } else return sprintf(env, trace, format, array); } public static int printf(Environment env, TraceInfo trace, String format, Memory... args) { Memory str = sprintf(env, trace, format, args); if (str.isNull()) return 0; else { String value = str.toString(); env.echo(value); return value.length(); } } public static int vprintf(Environment env, TraceInfo trace, String format, Memory array) { if (array.isArray()) { return printf(env, trace, format, array.toValue(ArrayMemory.class).values()); } else return printf(env, trace, format, array); } /** * Parses the cslashes bitmap returning an actual bitmap. * * @param charset the bitmap string * @return the actual bitmap */ private static boolean[] parseCharsetBitmap(Environment env, TraceInfo trace, String charset) { boolean[] bitmap = new boolean[256]; int length = charset.length(); for (int i = 0; i < length; i++) { char ch = charset.charAt(i); // XXX: the bitmap eventual might need to deal with unicode if (ch >= 256) continue; bitmap[ch] = true; if (length <= i + 3) continue; if (charset.charAt(i + 1) != '.' || charset.charAt(i + 2) != '.') continue; char last = charset.charAt(i + 3); if (last < ch) { env.warning(trace, "character set range is invalid: %s..%s", ch, last); continue; } i += 3; for (; ch <= last; ch++) { bitmap[ch] = true; } // TODO: handling of '@'? } return bitmap; } @Immutable public static String addcslashes(Environment env, TraceInfo trace, String source, String characters) { boolean[] bitmap = parseCharsetBitmap(env, trace, characters); int length = source.length(); StringBuilder sb = new StringBuilder(length * 5 / 4); for (int i = 0; i < length; i++) { char ch = source.charAt(i); if (ch >= 256 || !bitmap[ch]) { sb.append(ch); continue; } switch (ch) { case 0x07: sb.append("\\a"); break; case '\b': sb.append("\\b"); break; case '\t': sb.append("\\t"); break; case '\n': sb.append("\\n"); break; case 0xb: sb.append("\\v"); break; case '\f': sb.append("\\f"); break; case '\r': sb.append("\\r"); break; default: if (ch < 0x20 || ch >= 0x7f) { // save as octal sb.append("\\"); sb.append((char) ('0' + ((ch >> 6) & 7))); sb.append((char) ('0' + ((ch >> 3) & 7))); sb.append((char) ('0' + ((ch) & 7))); break; } else { sb.append("\\"); sb.append(ch); break; } } } return sb.toString(); } @Immutable public static String addslashes(String source) { StringBuilder sb = new StringBuilder(); int length = source.length(); for (int i = 0; i < length; i++) { char ch = source.charAt(i); switch (ch) { case 0x0: sb.append("\\0"); break; case '\'': sb.append("\\'"); break; case '\"': sb.append("\\\""); break; case '\\': sb.append("\\\\"); break; default: sb.append(ch); break; } } return sb.toString(); } @Immutable public static String bin2hex(Memory _value) { String value = _value.toBinaryString(); StringBuilder sb = new StringBuilder(); int ch; int length = value.length(); for (int i = 0; i < length; i++) { ch = value.charAt(i); int d = (ch >> 4) & 0xf; if (d < 10) sb.append((char) (d + '0')); else sb.append((char) (d + 'a' - 10)); d = (ch) & 0xf; if (d < 10) sb.append((char) (d + '0')); else sb.append((char) (d + 'a' - 10)); } return sb.toString(); } @Immutable public static String hex2bin(Memory _s) { String s = _s.toBinaryString(); StringBuilder sb = new StringBuilder(); int len = s.length(); for (int i = 0; i + 1 < len; i += 2) { int d1 = hexDigit(s.charAt(i)); int d2 = hexDigit(s.charAt(i + 1)); int d = d1 * 16 + d2; sb.append((char) d); } return sb.toString(); } private static int hexDigit(int c) { if ('0' <= c && c <= '9') { return c - '0'; } else if ('a' <= c && c <= 'f') { return c - 'a' + 10; } else if ('A' <= c && c <= 'F') { return c - 'A' + 10; } else { return 0; } } @Immutable public static Memory chunk_split(Environment env, TraceInfo trace, String body, int chunkLen, String end) { if (chunkLen < 1) { env.warning(trace, "chunk_split(): Chunk length should be greater than zero"); return Memory.FALSE; } StringBuilder sb = new StringBuilder(); int i = 0; for (; i + chunkLen <= body.length(); i += chunkLen) { sb.append(body.substring(i, i + chunkLen)); sb.append(end); } if (i < body.length()) { sb.append(body.substring(i)); sb.append(end); } return new StringMemory(sb.toString()); } @Immutable public static Memory chunk_split(Environment env, TraceInfo trace, String body, int chunkLen) { return chunk_split(env, trace, body, chunkLen, "\r\n"); } @Immutable public static Memory chunk_split(Environment env, TraceInfo trace, String body) { return chunk_split(env, trace, body, 76); } @Immutable public static Memory convert_cyr_string(Environment env, TraceInfo trace, String str, String from, String to) { throw new TodoException(); } @Immutable public static String trim(String s) { return s.trim(); } @Immutable public static String trim(String s, String charsetList) { return rtrim(ltrim(s, charsetList), charsetList); } @Immutable public static String ltrim(String s) { int i = 0; while (i < s.length() && Character.isWhitespace(s.charAt(i))) { i++; } return i >= s.length() ? "" : s.substring(i); } @Immutable public static String ltrim(String s, String charsetList) { int i = 0; while (i < s.length() && charsetList.indexOf(s.charAt(i)) > -1) { i++; } return i >= s.length() ? "" : s.substring(i); } @Immutable public static String rtrim(String s) { int i = s.length() - 1; while (i > 0 && Character.isWhitespace(s.charAt(i))) { i--; } return i <= 0 ? "" : s.substring(0, i + 1); } @Immutable public static String rtrim(String s, String charsetList) { int i = s.length() - 1; while (i > 0 && charsetList.indexOf(s.charAt(i)) > -1) { i--; } return i <= 0 ? "" : s.substring(0, i + 1); } @Immutable public static String chop(String s) { return rtrim(s); } @Immutable public static String quotemeta(String string) { int len = string.length(); StringBuilder sb = new StringBuilder(len * 5 / 4); for (int i = 0; i < len; i++) { char ch = string.charAt(i); switch (ch) { case '.': case '\\': case '+': case '*': case '?': case '[': case '^': case ']': case '(': case ')': case '$': sb.append("\\"); sb.append(ch); break; default: sb.append(ch); } } return sb.toString(); } private static final char[] SOUNDEX_VALUES = "01230120022455012623010202".toCharArray(); @Immutable public static Memory soundex(String string) { int length = string.length(); if (length == 0) return Memory.FALSE; StringBuilder sb = new StringBuilder(); int count = 0; char lastCode = 0; for (int i = 0; i < length && count < 4; i++) { char ch = toUpperCase(string.charAt(i)); if ('A' <= ch && ch <= 'Z') { char code = SOUNDEX_VALUES[ch - 'A']; if (count == 0) { sb.append(ch); count++; } else if (code != '0' && code != lastCode) { sb.append(code); count++; } lastCode = code; } } for (; count < 4; count++) { sb.append('0'); } return new StringMemory(sb.toString()); } @Immutable public static String str_rot13(String string) { int len = string.length(); StringBuilder sb = new StringBuilder(len); for (int i = 0; i < len; i++) { char ch = string.charAt(i); if ('a' <= ch && ch <= 'z') { int off = ch - 'a'; sb.append((char) ('a' + (off + 13) % 26)); } else if ('A' <= ch && ch <= 'Z') { int off = ch - 'A'; sb.append((char) ('A' + (off + 13) % 26)); } else { sb.append(ch); } } return sb.toString(); } public static String str_shuffle(String string) { char[] chars = string.toCharArray(); int length = chars.length; for (int i = 0; i < length; i++) { int rand = MathFunctions.RANDOM.nextInt(length); char temp = chars[rand]; chars[rand] = chars[i]; chars[i] = temp; } return new String(chars); } public static Memory str_split(String string, int chunk) { ArrayMemory array = new ArrayMemory(); if (string.isEmpty()) { array.add(new StringMemory(string)); return array; } int strLen = string.length(); for (int i = 0; i < strLen; i += chunk) { String value; if (i + chunk <= strLen) { value = string.substring(i, i + chunk); } else { value = string.substring(i); } array.add(new StringMemory(value)); } return array; } public static Memory str_split(String string) { return str_split(string, 1); } @Immutable public static int strcoll(String value1, String value2) { int cmp = value1.compareTo(value2); if (cmp == 0) return 0; else if (cmp < 0) return -1; else return 1; } @Immutable public static int strcmp(String value1, String value2) { int aLen = value1.length(); int bLen = value2.length(); for (int i = 0; i < aLen && i < bLen; i++) { char chA = value1.charAt(i); char chB = value2.charAt(i); if (chA == chB) continue; if (chA < chB) return -1; else return 1; } if (aLen == bLen) return 0; else if (aLen < bLen) return -1; else return 1; } @Immutable public static int strncmp(String value1, String value2, int len) { int len1 = value1.length(); int len2 = value2.length(); String _value1 = len1 <= len ? value1 : value1.substring(0, len); String _value2 = len2 <= len ? value2 : value2.substring(0, len); return _value1.compareTo(_value2); } @Immutable public static int strcasecmp(String value1, String value2) { return value1.compareToIgnoreCase(value2); } @Immutable public static int strncasecmp(String value1, String value2, int len) { int len1 = value1.length(); int len2 = value2.length(); String _value1 = len1 <= len ? value1 : value1.substring(0, len); String _value2 = len2 <= len ? value2 : value2.substring(0, len); return _value1.compareToIgnoreCase(_value2); } /*@Runtime.Immutable public static String nl2br(String value, boolean isXhtml){ StringBuilder sb = new StringBuilder(); String br = isXhtml ? "<br />" : "<br>"; int length = value.length(); for (int i = 0; i < length; i++) { char ch = value.charAt(i); char next_ch = i >= length - 1 ? '\0' : value.charAt(i + 1); if ((ch == '\r' && next_ch == '\n') || (ch == '\n' && next_ch == '\r')){ sb.append(br); sb.append(ch); sb.append(next_ch); i += 1; continue; } if (ch == '\r' || ch == '\n'){ sb.append(br); } sb.append(ch); } return sb.toString(); }*/ @Immutable public static String nl2br(String value) { return nl2br(value, true); } @Immutable public static Memory implode(Environment env, TraceInfo trace, Memory glue, Memory pieces) { ArrayMemory array; String delimiter; if (glue.isArray()) { array = (ArrayMemory) glue; delimiter = pieces.toString(); } else if (pieces.isArray()) { array = (ArrayMemory) pieces; delimiter = glue.toString(); } else { env.warning(trace, "Argument must be an array"); return Memory.NULL; } StringBuilder builder = new StringBuilder(); int i = 0, size = array.size(); for (Memory el : array) { builder.append(el.toString()); if (i != size - 1) builder.append(delimiter); i++; } return new StringMemory(builder.toString()); } @Immutable public static Memory implode(Environment env, TraceInfo trace, Memory pieces) { return implode(env, trace, Memory.NULL, pieces); } @Immutable public static Memory join(Environment env, TraceInfo trace, Memory glue, Memory pieces) { return implode(env, trace, glue, pieces); } @Immutable public static Memory join(Environment env, TraceInfo trace, Memory pieces) { return implode(env, trace, Memory.NULL, pieces); } public static Memory explode(String delimiter, String string, int limit) { if (limit == 0) limit = 1; String[] result; if (limit < 0) { result = StringUtils.split(string, delimiter); result = Arrays.copyOfRange(result, 0, result.length + limit); } else result = StringUtils.split(string, delimiter, limit); return ArrayMemory.ofStrings(result); } public static Memory explode(String delimiter, String string) { return explode(delimiter, string, Integer.MAX_VALUE); } @Immutable public static String lcfirst(String value) { if (value.isEmpty()) return ""; return String.valueOf(Character.toLowerCase(value.charAt(0))) + value.substring(1); } @Immutable public static String ucfirst(String value) { if (value.isEmpty()) return ""; return String.valueOf(Character.toUpperCase(value.charAt(0))) + value.substring(1); } @Immutable public static String ucwords(String value) { char[] buffer = value.toCharArray(); boolean prevSpace = true; // first char to Upper for (int i = 0; i < buffer.length; i++) { char ch = buffer[i]; if (Character.isSpaceChar(ch)) { prevSpace = true; continue; } if (prevSpace) { buffer[i] = Character.toUpperCase(ch); prevSpace = false; } } return new String(buffer); } private static final ThreadLocal<MessageDigest> md5Digest = new ThreadLocal<MessageDigest>() { @Override protected MessageDigest initialValue() { try { return MessageDigest.getInstance("MD5"); } catch (NoSuchAlgorithmException e) { throw new RuntimeException(e); } } }; private static final ThreadLocal<MessageDigest> sha1Digest = new ThreadLocal<MessageDigest>() { @Override protected MessageDigest initialValue() { try { return MessageDigest.getInstance("SHA1"); } catch (NoSuchAlgorithmException e) { throw new RuntimeException(e); } } }; public static Memory md5(Environment env, Memory value, boolean rawOutput) { MessageDigest md = md5Digest.get(); md.reset(); md.update(value.getBinaryBytes(env.getDefaultCharset())); if (rawOutput) return new BinaryMemory(md.digest()); else return new StringMemory(DigestUtils.bytesToHex(md.digest())); } public static Memory md5(Environment env, Memory value) { return md5(env, value, false); } public static Memory md5_file(Environment env, TraceInfo trace, String fileName) { return md5_file(env, trace, fileName, false); } public static Memory md5_file(Environment env, TraceInfo trace, String fileName, boolean rawOutput) { try { BufferedInputStream reader = new BufferedInputStream(new FileInputStream(fileName)); try { MessageDigest md = md5Digest.get(); md.reset(); int len; byte[] buff = new byte[1024]; while ((len = reader.read(buff)) > 0) { md.update(buff, 0, len); } if (rawOutput) return new BinaryMemory(md.digest()); else return new StringMemory(DigestUtils.bytesToHex(md.digest())); } finally { reader.close(); } } catch (FileNotFoundException e) { env.warning(trace, "md5_file(): " + Messages.ERR_FILE_NOT_FOUND.fetch(fileName)); return Memory.FALSE; } catch (IOException e) { env.warning(trace, "md5_file(): " + e.getMessage()); return Memory.FALSE; } } public static Memory sha1(Environment env, Memory value, boolean rawOutput) { MessageDigest md = sha1Digest.get(); md.reset(); md.update(value.getBinaryBytes(env.getDefaultCharset())); if (rawOutput) { return new BinaryMemory(md.digest()); } else { return new StringMemory(DigestUtils.bytesToHex(md.digest())); } } @Immutable public static Memory sha1(Environment env, Memory value) { return sha1(env, value, false); } public static Memory sha1_file(Environment env, TraceInfo trace, String fileName) { return sha1_file(env, trace, fileName, false); } public static Memory sha1_file(Environment env, TraceInfo trace, String fileName, boolean rawOutput) { try { BufferedInputStream reader = new BufferedInputStream(new FileInputStream(fileName)); try { MessageDigest md = sha1Digest.get(); md.reset(); int len; byte[] buff = new byte[1024]; while ((len = reader.read(buff)) > 0) { md.update(buff, 0, len); } if (rawOutput) return new BinaryMemory(md.digest()); else return new StringMemory(DigestUtils.bytesToHex(md.digest())); } finally { reader.close(); } } catch (FileNotFoundException e) { env.warning(trace, "sha1_file(): " + Messages.ERR_FILE_NOT_FOUND.fetch(fileName)); return Memory.FALSE; } catch (IOException e) { env.warning(trace, "sha1_file(): " + e.getMessage()); return Memory.FALSE; } } @Immutable public static Memory substr(String value, int start, int length) { int strLen = value.length(); if (start < 0) start = strLen + start; if (start < 0 || start >= strLen) return Memory.FALSE; if (length == 0) return Memory.CONST_EMPTY_STRING; int end; if (length < 0) end = strLen + length; else end = (strLen < length) ? strLen : start + length; if (end <= start) return Memory.FALSE; else if (strLen <= end) return new StringMemory(value.substring(start)); else return new StringMemory(value.substring(start, end)); } @Immutable public static Memory substr(String value, int start) { int length = value.length(); if (start < 0) start = length + start; if (start < 0 || start > length) return Memory.FALSE; return new StringMemory(value.substring(start)); } @Immutable public static Memory substr_count(Environment env, TraceInfo trace, String haystack, String needle, int offset, Memory _length) { if (needle.isEmpty()) { env.warning(trace, "Empty substring"); return Memory.FALSE; } int haystackLength = haystack.length(); if (offset < 0) { env.warning(trace, "Offset should be greater than or equal to 0"); return Memory.FALSE; } if (offset > haystackLength) { env.warning(trace, "Offset value %s exceeds string length", offset); return Memory.FALSE; } int length; int end; int needleLength = needle.length(); if (_length != null) { length = _length.toInteger(); end = offset + length - 1; if (length <= 0) { env.warning(trace, "Length should be greater than 0"); return Memory.FALSE; } if (length > (haystackLength - offset)) { env.warning(trace, "Length value %s exceeds string length", length); return Memory.FALSE; } } else { end = haystackLength - needleLength + 1; } int count = 0; if (needleLength == 1) { char ch = needle.charAt(0); for (int i = offset; i < end; i++) { if (ch == haystack.charAt(i)) count++; } } else { for (int i = offset; i < end; i++) { if (haystack.startsWith(needle, i)) { count++; i += needleLength; } } } return LongMemory.valueOf(count); } @Immutable public static Memory substr_count(Environment env, TraceInfo trace, String haystack, String needle, int offset) { return substr_count(env, trace, haystack, needle, offset, null); } @Immutable public static Memory substr_count(Environment env, TraceInfo trace, String haystack, String needle) { return substr_count(env, trace, haystack, needle, 0, null); } @Immutable public static Memory substr_compare(Environment env, TraceInfo trace, String mainStr, String str, int offset, Memory lenV, boolean isCaseInsensitive) { int strLen = mainStr.length(); if (lenV != null && lenV.toInteger() == 0) return Memory.FALSE; int len = lenV == null ? 0 : lenV.toInteger(); if (strLen < offset) { env.warning(trace, "offset can not be greater than length of string"); return Memory.FALSE; } if (len > strLen || len + offset > strLen) { return Memory.FALSE; } if (lenV == null) mainStr = substr(mainStr, offset).toString(); else mainStr = substr(mainStr, offset, len).toString(); str = lenV == null ? str : substr(str, 0, len).toString(); if (isCaseInsensitive) return LongMemory.valueOf(strcasecmp(mainStr, str)); else return LongMemory.valueOf(strcmp(mainStr, str)); } @Immutable public static Memory substr_compare(Environment env, TraceInfo trace, String mainStr, String str, int offset, Memory lenV) { return substr_compare(env, trace, mainStr, str, offset, lenV, false); } @Immutable public static Memory substr_compare(Environment env, TraceInfo trace, String mainStr, String str, int offset) { return substr_compare(env, trace, mainStr, str, offset, null, false); } @Immutable public static String strtolower(String string) { return string.toLowerCase(); } @Immutable public static String strtoupper(String string) { return string.toUpperCase(); } @Immutable public static String strrev(String string) { return StringUtils.reverse(string); } @Immutable public static Memory strrchr(String haystack, char needle) { int i = haystack.lastIndexOf(needle); if (i > 0) return new StringMemory(haystack.substring(i)); else return Memory.FALSE; } @Immutable public static Memory strchr(String haystack, char needle, boolean beforeNeedle) { int i = haystack.indexOf(needle); if (i >= 0) { return new StringMemory(beforeNeedle ? haystack.substring(0, i) : haystack.substring(i)); } else return Memory.FALSE; } @Immutable public static Memory strchr(String haystack, char needle) { return strchr(haystack, needle, false); } @Immutable public static Memory strstr(String haystack, char needle, boolean beforeNeedle) { return strchr(haystack, needle, beforeNeedle); } @Immutable public static Memory strstr(String haystack, char needle) { return strchr(haystack, needle, false); } @Immutable public static Memory strpos(Environment env, TraceInfo trace, String haystack, Memory needle, int offset) { int haystackLen = haystack.length(); if (offset < 0 || offset > haystackLen) { env.warning(trace, "strpos(): Offset not contained in string"); return Memory.FALSE; } if (haystackLen == 0) return Memory.FALSE; char ch = '\0'; String search = null; if (needle.isString()) { search = needle.toString(); if (search.length() == 1) { ch = search.charAt(0); search = null; } } else { ch = needle.toChar(); } int p; if (search == null) { p = haystack.indexOf(ch, offset); } else { if (search.isEmpty()) { env.warning(trace, "Empty needle"); return Memory.FALSE; } p = haystack.indexOf(search, offset); } if (p < 0) return Memory.FALSE; else return LongMemory.valueOf(p); } @Immutable public static Memory strpos(Environment env, TraceInfo trace, String haystack, Memory needle) { return strpos(env, trace, haystack, needle, 0); } @Immutable public static Memory strrpos(Environment env, TraceInfo trace, String haystack, Memory needle, int offset) { int haystackLen = haystack.length(); if (offset < 0 || offset > haystackLen) { env.warning(trace, "Offset not contained in string"); return Memory.FALSE; } if (haystackLen == 0) return Memory.FALSE; char ch = '\0'; String search = null; if (needle.isString()) { search = needle.toString(); if (search.length() == 1) { ch = search.charAt(0); search = null; } } else { ch = needle.toChar(); } int p; if (search == null) { p = haystack.lastIndexOf(ch, offset); } else { if (search.isEmpty()) { env.warning(trace, "Empty needle"); return Memory.FALSE; } p = haystack.lastIndexOf(search, offset); } if (p < 0) return Memory.FALSE; else return LongMemory.valueOf(p); } @Immutable public static Memory strrpos(Environment env, TraceInfo trace, String haystack, Memory needle) { return strrpos(env, trace, haystack, needle, 0); } @Immutable public static Memory strripos(Environment env, TraceInfo trace, String haystack, Memory needleV) { return strripos(env, trace, haystack, needleV, null); } @Immutable public static Memory strripos(Environment env, TraceInfo trace, String haystack, Memory needleV, Memory offsetV) { String needle; if (needleV.isString()) { needle = needleV.toString(); } else { needle = String.valueOf((char) needleV.toInteger()); } int offset; if (offsetV == null) { offset = haystack.length(); } else { offset = offsetV.toInteger(); if (haystack.length() < offset) { env.warning(trace, "strripos(): offset cannot exceed string length"); return Memory.FALSE; } } haystack = haystack.toLowerCase(); needle = needle.toLowerCase(); int pos = haystack.lastIndexOf(needle, offset); if (pos < 0) { return Memory.FALSE; } else { return LongMemory.valueOf(pos); } } @Immutable public static Memory stripos(Environment env, TraceInfo trace, String haystack, Memory needle, int offset) { int haystackLen = haystack.length(); if (offset < 0 || offset > haystackLen) { env.warning(trace, "stripos(): Offset not contained in string"); return Memory.FALSE; } if (haystackLen == 0) return Memory.FALSE; char ch = '\0'; String search = null; if (needle.isString()) { search = needle.toString(); if (search.length() == 1) { ch = Character.toUpperCase(search.charAt(0)); search = null; } } else { ch = Character.toUpperCase(needle.toChar()); } int p = -1; if (search == null) { for (int i = offset; i < haystackLen; i++) { if (Character.toUpperCase(haystack.charAt(i)) == ch) { p = i; break; } } } else { if (search.isEmpty()) { env.warning(trace, "Empty needle"); return Memory.FALSE; } p = StringUtils.indexOfIgnoreCase(haystack, search, offset); } if (p < 0) return Memory.FALSE; else return LongMemory.valueOf(p); } @Immutable public static Memory stripos(Environment env, TraceInfo trace, String haystack, Memory needle) { return stripos(env, trace, haystack, needle, 0); } @Immutable public static Memory strlen(Environment env, TraceInfo trace, Memory string) { if (string.isArray()) { env.warning(trace, "expects parameter 1 to be string, array given"); return Memory.NULL; } if (string instanceof BinaryMemory) return LongMemory.valueOf(string.getBinaryBytes(env.getDefaultCharset()).length); return LongMemory.valueOf(string.toString().length()); } protected static String _substr_replace(String string, String replacement, int start, int length) { int strLength = string.length(); if (start > strLength) start = strLength; else if (start < 0) start = strLength + start; if (start < 0) start = 0; int end; if (length < 0) end = Math.max(strLength + length, start); else end = (strLength < length) ? strLength : (start + length); StringBuilder result = new StringBuilder(); result.append(string.substring(0, start)); result.append(replacement); result.append(string.substring(end)); return result.toString(); } public static Memory str_replace(Environment env, TraceInfo trace, Memory search, Memory replace, Memory string) { return str_replace(env, trace, search, replace, string, Memory.UNDEFINED); } public static Memory str_replace(Environment env, TraceInfo trace, Memory search, Memory replace, Memory string, @Reference Memory _count) { return _str_replace(env, trace, search, replace, string, _count, false); } public static Memory str_ireplace(Environment env, TraceInfo trace, Memory search, Memory replace, Memory string) { return str_ireplace(env, trace, search, replace, string, Memory.UNDEFINED); } public static Memory str_ireplace(Environment env, TraceInfo trace, Memory search, Memory replace, Memory string, @Reference Memory _count) { return _str_replace(env, trace, search, replace, string, _count, true); } protected static Memory _str_replace_impl(Environment env, TraceInfo trace, Memory search, Memory replace, Memory string, @Reference Memory _count, boolean isInsensitive) { String searchText = search.toString(); String replaceText = replace.toString(); String text = string.toString(); AtomicLong count = _count.isUndefined() ? null : new AtomicLong(_count.toLong()); text = StringUtils.replace(text, searchText, replaceText, isInsensitive, count); if (count != null) _count.assign(count.get()); return StringMemory.valueOf(text); } protected static Memory _str_replace(Environment env, TraceInfo trace, Memory search, Memory replace, Memory string, @Reference Memory count, boolean isInsensitive) { if (count.isReference()) { count.assign(0); } if (string.isNull()) { return Memory.CONST_EMPTY_STRING; } if (string.isArray()) { ForeachIterator iterator = string.getNewIterator(env); ArrayMemory result = new ArrayMemory(); while (iterator.next()) { Memory key = iterator.getMemoryKey(); Memory value = iterator.getValue(); if (value.isArray()) { result.refOfIndex(key).assign(value.toImmutable()); } else { Memory ret = _str_replace( env, trace, search, replace, StringMemory.valueOf(value.toString()), count, isInsensitive ); result.refOfIndex(key).assign(ret); } } return result.toConstant(); } else { if (!search.isArray()) { String searchStr = search.toString(); if (searchStr.isEmpty()) { return string; } if (replace.isArray()) { env.warning(trace, "str_replace(): Array to string conversion"); } string = _str_replace_impl(env, trace, StringMemory.valueOf(searchStr), StringMemory.valueOf(replace.toString()), string, count, isInsensitive); } else if (replace.isArray()) { ForeachIterator searchIterator = search.getNewIterator(env); ForeachIterator replaceIterator = replace.getNewIterator(env); while (searchIterator.next()) { Memory searchValue = searchIterator.getValue(); Memory replaceValue; if (replaceIterator.next()) { replaceValue = replaceIterator.getValue(); } else { replaceValue = Memory.NULL; } string = _str_replace(env, trace, StringMemory.valueOf(searchValue.toString()), StringMemory.valueOf(replaceValue.toString()), string, count, isInsensitive); } } else { ForeachIterator searchIterator = search.getNewIterator(env); while (searchIterator.next()) { string = _str_replace( env, trace, StringMemory.valueOf(searchIterator.getValue().toString()), replace, string, count, isInsensitive ); } } } return string; } @Immutable public static Memory substr_replace(Environment env, TraceInfo trace, Memory string, Memory replacementM, Memory startM, Memory lengthM) { int start = 0; int length = Integer.MAX_VALUE / 2; String replacement = ""; ForeachIterator replacementIterator = null; if (replacementM.isArray()) replacementIterator = replacementM.getNewIterator(env, false, false); else replacement = replacementM.toString(); ForeachIterator startIterator = null; if (startM.isArray()) startIterator = startM.getNewIterator(env, false, false); else start = startM.toInteger(); ForeachIterator lengthIterator = null; if (lengthM.isArray()) lengthIterator = lengthM.getNewIterator(env, false, false); else length = lengthM.toInteger(); if (string.isArray()) { ArrayMemory resultArray = new ArrayMemory(); ForeachIterator iterator = string.getNewIterator(env, false, false); while (iterator.next()) { String value = iterator.getValue().toString(); if (replacementIterator != null && replacementIterator.next()) replacement = replacementIterator.getValue().toString(); if (lengthIterator != null && lengthIterator.next()) length = lengthIterator.getValue().toInteger(); if (startIterator != null && startIterator.next()) start = startIterator.getValue().toInteger(); String result = _substr_replace(value, replacement, start, length); resultArray.add(new StringMemory(result)); } return resultArray.toConstant(); } else { if (replacementIterator != null && replacementIterator.next()) replacement = replacementIterator.getValue().toString(); if (lengthIterator != null && lengthIterator.next()) length = lengthIterator.getValue().toInteger(); if (startIterator != null && startIterator.next()) start = startIterator.getValue().toInteger(); return new StringMemory(_substr_replace(string.toString(), replacement, start, length)); } } @Immutable public static Memory substr_replace(Environment env, TraceInfo trace, Memory string, Memory replacementM, Memory startM) { return substr_replace(env, trace, string, replacementM, startM, LongMemory.valueOf(Integer.MAX_VALUE / 2)); } @Immutable public static Memory wordwrap(String str, int width, String _break, boolean cut) { int length = str.length(); StringBuilderMemory sb = new StringBuilderMemory(); int done = 0; int prevSpacePos = 0; int start = 0; int wordLength = 0; for (int i = 0; i < length + 1; i++) { char ch = i == length ? ' ' : str.charAt(i); if (Character.isSpaceChar(ch) || (cut && wordLength + 1 >= width)) { if (done >= width || i == length) { if (done <= width) { sb.append(str.substring(start, i)); } else { sb.append(str.substring(start, prevSpacePos)); i = prevSpacePos; } start = i + 1; if (i != length) sb.append(_break); done = 0; continue; } else prevSpacePos = i; wordLength = 0; } done++; wordLength++; } return sb; } @Immutable public static Memory wordwrap(String str, int width, String _break) { return wordwrap(str, width, _break, false); } @Immutable public static Memory wordwrap(String str, int width) { return wordwrap(str, width, "\n", false); } @Immutable public static Memory wordwrap(String str) { return wordwrap(str, 75, "\n", false); } @Immutable public static String number_format(double number, int decimals, char decPoint, char thousandsSep) { String pattern; if (decimals > 0) { StringBuilder patternBuilder = new StringBuilder(6 + decimals); patternBuilder.append(thousandsSep == 0 ? "###0." : "#,##0."); for (int i = 0; i < decimals; i++) { patternBuilder.append('0'); } pattern = patternBuilder.toString(); } else { pattern = thousandsSep == 0 ? "###0" : "#,##0"; } DecimalFormatSymbols decimalFormatSymbols; if (decPoint == '.' && thousandsSep == ',') { decimalFormatSymbols = DEFAULT_DECIMAL_FORMAT_SYMBOLS; } else { decimalFormatSymbols = new DecimalFormatSymbols(); decimalFormatSymbols.setDecimalSeparator(decPoint); decimalFormatSymbols.setGroupingSeparator(thousandsSep); decimalFormatSymbols.setZeroDigit('0'); } DecimalFormat format = new DecimalFormat(pattern, decimalFormatSymbols); String result = format.format(number); if (decPoint == 0 && decimals > 0) { // no way to get DecimalFormat to output nothing for the point, // so remove it here int i = result.lastIndexOf(decPoint); return result.substring(0, i) + result.substring(i + 1, result.length()); } else { return result; } } @Immutable public static String number_format(double number, int decimals) { return number_format(number, decimals, '.', ','); } @Immutable public static String number_format(double number) { return number_format(number, 0, '.', ','); } @Immutable public static String str_repeat(String input, int multiplier) { if (multiplier <= 0) return ""; StringBuilder sb = new StringBuilder(); for (int i = 0; i < multiplier; i++) sb.append(input); return sb.toString(); } @Immutable public static String str_pad(String string, int length, String pad, int type) { int strLen = string.length(); int padLen = length - strLen; if (padLen <= 0) { return string; } if (pad == null || pad.length() == 0) { pad = " "; } int leftPad = 0; int rightPad = 0; switch (type) { case 0: leftPad = padLen; break; case 1: default: rightPad = padLen; break; case 2: leftPad = padLen / 2; rightPad = padLen - leftPad; break; } int padStringLen = pad.length(); StringBuilder sb = new StringBuilder(string.length() + padLen); for (int i = 0; i < leftPad; i++) { sb.append(pad.charAt(i % padStringLen)); } sb = sb.append(string); for (int i = 0; i < rightPad; i++) { sb.append(pad.charAt(i % padStringLen)); } return sb.toString(); } @Immutable public static String str_pad(String string, int length, String pad) { return str_pad(string, length, pad, constants.STR_PAD_RIGHT); } @Immutable public static String str_pad(String string, int length) { return str_pad(string, length, " ", constants.STR_PAD_RIGHT); } @Immutable public static int crc32(Environment env, Memory value) { CRC32 crc = new CRC32(); crc.update(value.getBinaryBytes(env.getDefaultCharset())); return (int) crc.getValue(); } @Immutable public static String nl2br(String string, boolean isXhtml) { String br = "<br />"; if (!isXhtml) { br = "<br>"; } return string.replaceAll("(\\r?\\n)", br + "$1"); } @Immutable public static String htmlspecialchars_decode(String string) { return htmlspecialchars_decode(string, StringConstants.ENT_COMPAT); } @Immutable public static String htmlspecialchars_decode(String string, int quoteStyle) { int len = string.length(); StringBuilder sb = new StringBuilder(); for (int i = 0; i < len; i++) { char ch = string.charAt(i); if (ch != '&') { sb.append(ch); continue; } switch (string.charAt(i + 1)) { case 'a': sb.append('&'); if (i + 4 < len && string.charAt(i + 2) == 'm' && string.charAt(i + 3) == 'p' && string.charAt(i + 4) == ';') { i += 4; } break; case 'q': if ((quoteStyle & StringConstants.ENT_HTML_QUOTE_DOUBLE) != 0 && i + 5 < len && string.charAt(i + 2) == 'u' && string.charAt(i + 3) == 'o' && string.charAt(i + 4) == 't' && string.charAt(i + 5) == ';') { i += 5; sb.append('"'); } else { sb.append('&'); } break; case '#': if ((quoteStyle & StringConstants.ENT_HTML_QUOTE_SINGLE) != 0 && i + 5 < len && string.charAt(i + 2) == '0' && string.charAt(i + 3) == '3' && string.charAt(i + 4) == '9' && string.charAt(i + 5) == ';') { i += 5; sb.append('\''); } else { sb.append('&'); } break; case 'l': if (i + 3 < len && string.charAt(i + 2) == 't' && string.charAt(i + 3) == ';') { i += 3; sb.append('<'); } else { sb.append('&'); } break; case 'g': if (i + 3 < len && string.charAt(i + 2) == 't' && string.charAt(i + 3) == ';') { i += 3; sb.append('>'); } else { sb.append('&'); } break; default: sb.append('&'); } } return sb.toString(); } @Immutable public static Memory htmlspecialchars(Environment env, TraceInfo trace, Memory _string, int quoteStyle) { return htmlspecialchars(env, trace, _string, quoteStyle, "UTF-8"); } @Immutable public static Memory htmlspecialchars(Environment env, TraceInfo trace, Memory _string) { return htmlspecialchars(env, trace, _string, StringConstants.ENT_COMPAT, "UTF-8"); } public static Memory htmlspecialchars(Environment env, TraceInfo trace, Memory _string, int quoteStyle, String charset) { try { String string = new String(_string.getBinaryBytes(env.getDefaultCharset()), charset); int len = string.length(); StringBuilderMemory sb = new StringBuilderMemory(); for (int i = 0; i < len; i++) { char ch = string.charAt(i); switch (ch) { case '&': sb.append("&"); break; case '"': if ((quoteStyle & StringConstants.ENT_HTML_QUOTE_DOUBLE) != 0) { sb.append("""); } else { sb.append(ch); } break; case '\'': if ((quoteStyle & StringConstants.ENT_HTML_QUOTE_SINGLE) != 0) { sb.append("'"); } else { sb.append(ch); } break; case '<': sb.append("<"); break; case '>': sb.append(">"); break; default: sb.append(ch); break; } } return sb; } catch (UnsupportedEncodingException e) { env.warning(trace, "htmlspecialchars(): unsupported encoding - %s", charset); return Memory.FALSE; } } @Immutable public static Memory html_entity_decode(Environment env, TraceInfo trace, Memory _string, int flags, String encoding) { try { String string = new String(_string.getBinaryBytes(env.getDefaultCharset()), encoding); int len = string.length(); int htmlEntityStart = -1; StringBuilder result = new StringBuilder(); for (int i = 0; i < len; i++) { char ch = string.charAt(i); if (ch == '&' && htmlEntityStart < 0) { htmlEntityStart = i; } else if (htmlEntityStart < 0) { result.append(ch); } else if (ch == ';') { String entity = string.substring(htmlEntityStart, i + 1); Memory value = HTML_ENTITIES.getByScalar(entity); if (value == null) { result.append(entity); } else { result.append(value); } htmlEntityStart = -1; } else if (!(('a' <= ch && ch <= 'z') || ('A' <= ch && ch <= 'Z'))) { result.append('&'); i = htmlEntityStart; htmlEntityStart = -1; } } if (htmlEntityStart > 0) { result.append(string, htmlEntityStart, len); } return new StringMemory(result.toString()); } catch (UnsupportedEncodingException e) { env.warning(trace, "html_entity_decode(): unsupported encoding - %s", encoding); return Memory.FALSE; } } public static Memory htmlentities(Environment env, TraceInfo trace, Memory _string, int quoteStyle, String encoding) { try { String string = new String(_string.getBinaryBytes(env.getDefaultCharset()), encoding); StringBuffer sb = new StringBuffer(); int length = string.length(); for (int i = 0; i < length; ++i) { char ch = string.charAt(i); Memory el = HTML_ENTITIES.getByScalar(String.valueOf(ch)); if (ch == '"') { if ((quoteStyle & StringConstants.ENT_HTML_QUOTE_DOUBLE) != 0) { sb.append("""); } else { sb.append(ch); } } else if (ch == '\'') { if ((quoteStyle & StringConstants.ENT_HTML_QUOTE_SINGLE) != 0) { sb.append("'"); } else { sb.append('\''); } } else if (el != null) { sb.append(el); } else { sb.append(ch); } } return new StringMemory(sb.toString()); } catch (UnsupportedEncodingException e) { env.warning(trace, "htmlentities(): unsupported encoding - %s", encoding); return Memory.FALSE; } } @Immutable public static int levenshtein(String str1, String str2) { return levenshtein(str1, str2, 1, 1, 1); } @Immutable public static int levenshtein(String s1, String s2, int cost_ins, int cost_rep, int cost_del) { int i, j, flip, ii, ii2, cost; int l1 = s1.length(); int l2 = s2.length(); if (l1 > 255) return -1; if (l2 > 255) return -1; int cr = cost_rep; int ci = cost_ins; int cd = cost_del; int cutHalf = flip = Math.max(l1, l2); int minCost = Math.min(Math.min(cd, ci), cr); int minD = Math.max(minCost, (l1 - l2) * cd); int minI = Math.max(minCost, (l2 - l1) * ci); int[] buf = new int[(cutHalf * 2) + 1]; for (i = 0; i <= l2; ++i) { buf[i] = i * minD; } for (i = 0; i < l1; ++i, flip = cutHalf - flip) { char ch = s1.charAt(i); buf[flip] = (i + 1) * minI; ii = flip; ii2 = cutHalf - flip; for (j = 0; j < l2; ++j, ++ii, ++ii2) { cost = (ch == s2.charAt(j) ? 0 : cr); buf[ii + 1] = Math.min(Math.min(buf[ii2 + 1] + cd, buf[ii] + ci), buf[ii2] + cost); } } return buf[l2 + cutHalf - flip]; } @Immutable public static Memory convert_uudecode(String source) { int length = source.length(); if (length == 0) { return Memory.FALSE; } StringBuilder builder = new StringBuilder(); int i = 0; while (i < length) { int ch1 = source.charAt(i++); if (ch1 == 0x60 || ch1 == 0x20) { break; } else if (ch1 < 0x20 || 0x5f < ch1) { continue; } int sublen = ch1 - 0x20; while (sublen > 0) { int code; code = ((source.charAt(i++) - 0x20) & 0x3f) << 18; code += ((source.charAt(i++) - 0x20) & 0x3f) << 12; code += ((source.charAt(i++) - 0x20) & 0x3f) << 6; code += ((source.charAt(i++) - 0x20) & 0x3f); builder.append(code >> 16); if (sublen > 1) { builder.append(code >> 8); } if (sublen > 2) { builder.append(code); } sublen -= 3; } } return new StringMemory(builder.toString()); } @Immutable public static Memory convert_uuencode(String source) { if (source.length() == 0) { return Memory.FALSE; } StringBuilderMemory result = new StringBuilderMemory(); int i = 0; int length = source.length(); while (i < length) { int sublen = length - i; if (45 < sublen) { sublen = 45; } result.append((char) (sublen + 0x20)); int end = i + sublen; while (i < end) { int code = source.charAt(i++) << 16; if (i < length) { code += source.charAt(i++) << 8; } if (i < length) { code += source.charAt(i++); } result.append(toUUChar(((code >> 18) & 0x3f))); result.append(toUUChar(((code >> 12) & 0x3f))); result.append(toUUChar(((code >> 6) & 0x3f))); result.append(toUUChar(((code) & 0x3f))); } result.append('\n'); } result.append((char) 0x60); result.append('\n'); return result; } @Immutable public static String metaphone(String string) { int length = string.length(); int index = 0; char ch = 0; // ignore everything up until first letter for (; index < length; index++) { ch = toUpperCase(string.charAt(index)); if ('A' <= ch && ch <= 'Z') { break; } } if (index == length) { return ""; } int lastIndex = length - 1; StringBuilder result = new StringBuilder(length); char nextCh = index < lastIndex ? toUpperCase(string.charAt(index + 1)) : 0; switch (ch) { case 'A': if (nextCh == 'E') { result.append('E'); index += 2; } else { result.append('A'); index += 1; } break; case 'E': case 'I': case 'O': case 'U': result.append(ch); index += 1; break; case 'G': case 'K': case 'P': if (nextCh == 'N') { result.append('N'); index += 2; } break; case 'W': if (nextCh == 'H' || nextCh == 'R') { result.append(nextCh); index += 2; } else { switch (nextCh) { case 'A': case 'E': case 'I': case 'O': case 'U': result.append('W'); index += 2; break; default: break; } } break; case 'X': result.append('S'); index += 1; break; default: break; } char prevCh; for (; index < length; index++) { if (index > 0) { prevCh = toUpperCase(string.charAt(index - 1)); } else { prevCh = 0; } ch = toUpperCase(string.charAt(index)); if (ch < 'A' || ch > 'Z') { continue; } if (ch == prevCh && ch != 'C') { continue; } if (index + 1 < length) { nextCh = toUpperCase(string.charAt(index + 1)); } else { nextCh = 0; } char nextnextCh; if (index + 2 < length) { nextnextCh = toUpperCase(string.charAt(index + 2)); } else { nextnextCh = 0; } switch (ch) { case 'B': if (prevCh != 'M') { result.append('B'); } break; case 'C': switch (nextCh) { case 'E': case 'I': case 'Y': // makesoft if (nextCh == 'I' && nextnextCh == 'A') { result.append('X'); } else if (prevCh == 'S') { } else { result.append('S'); } break; default: if (nextCh == 'H') { result.append('X'); index++; } else { result.append('K'); } break; } break; case 'D': if (nextCh == 'G') { switch (nextnextCh) { case 'E': case 'I': case 'Y': // makesoft result.append('J'); index++; break; default: result.append('T'); break; } } else { result.append('T'); } break; case 'G': if (nextCh == 'H') { boolean isSilent = false; if (index - 3 >= 0) { char prev3Ch = toUpperCase(string.charAt(index - 3)); switch (prev3Ch) { // noghtof case 'B': case 'D': case 'H': isSilent = true; break; default: break; } } if (!isSilent) { if (index - 4 >= 0) { char prev4Ch = toUpperCase(string.charAt(index - 4)); isSilent = (prev4Ch == 'H'); } } if (!isSilent) { result.append('F'); index++; } } else if (nextCh == 'N') { char nextnextnextCh; if (index + 3 < length) { nextnextnextCh = toUpperCase(string.charAt(index + 3)); } else { nextnextnextCh = 0; } if (nextnextCh < 'A' || nextnextCh > 'Z') { } else if (nextnextCh == 'E' && nextnextnextCh == 'D') { } else { result.append('K'); } } else if (prevCh == 'G') { result.append('K'); } else { switch (nextCh) { case 'E': case 'I': case 'Y': // makesoft result.append('J'); break; default: result.append('K'); break; } } break; case 'H': case 'W': case 'Y': switch (nextCh) { case 'A': case 'E': case 'I': case 'O': case 'U': // followed by a vowel if (ch == 'H') { switch (prevCh) { case 'C': case 'G': case 'P': case 'S': case 'T': // affecth break; default: result.append('H'); break; } } else { result.append(ch); } break; default: // not followed by a vowel break; } break; case 'K': if (prevCh != 'C') { result.append('K'); } break; case 'P': if (nextCh == 'H') { result.append('F'); } else { result.append('P'); } break; case 'Q': result.append('K'); break; case 'S': if (nextCh == 'I' && (nextnextCh == 'O' || nextnextCh == 'A')) { result.append('X'); } else if (nextCh == 'H') { result.append('X'); index++; } else { result.append('S'); } break; case 'T': if (nextCh == 'I' && (nextnextCh == 'O' || nextnextCh == 'A')) { result.append('X'); } else if (nextCh == 'H') { result.append('0'); index++; } else { result.append('T'); } break; case 'V': result.append('F'); break; case 'X': result.append('K'); result.append('S'); break; case 'Z': result.append('S'); break; case 'F': case 'J': case 'L': case 'M': case 'N': case 'R': result.append(ch); break; default: break; } } return result.toString(); } @Immutable public static Memory strspn(String string, String characters, int offset, int length) { return strspnImpl(string, characters, offset, length, true); } @Immutable public static Memory strspn(String string, String characters, int offset) { return strspnImpl(string, characters, offset, -2147483648, true); } @Immutable public static Memory strspn(String string, String characters) { return strspnImpl(string, characters, 0, -2147483648, true); } private static Memory strspnImpl(String string, String characters, int offset, int length, boolean isMatch) { int strlen = string.length(); if (offset < 0) { offset += strlen; if (offset < 0) { offset = 0; } } if (offset > strlen) { return Memory.FALSE; } if (length == -2147483648) { length = strlen; } else if (length < 0) { length += (strlen - offset); if (length < 0) { length = 0; } } int end = offset + length; if (strlen < end) { end = strlen; } int count = 0; for (; offset < end; offset++) { char ch = string.charAt(offset); boolean isPresent = characters.indexOf(ch) > -1; if (isPresent == isMatch) { count++; } else { return LongMemory.valueOf(count); } } return LongMemory.valueOf(count); } @Immutable public static Memory strpbrk(String haystack, String charList) { int len = haystack.length(); int sublen = charList.length(); for (int i = 0; i < len; i++) { for (int j = 0; j < sublen; j++) { if (haystack.charAt(i) == charList.charAt(j)) { return new StringMemory(haystack.substring(i)); } } } return Memory.FALSE; } @Immutable public static Memory stristr(String haystack, Memory needleV) { String needleLower; if (needleV.isString()) { needleLower = needleV.toString().toLowerCase(); } else { char lower = Character.toLowerCase((char) needleV.toLong()); needleLower = String.valueOf(lower); } String haystackLower = haystack.toLowerCase(); int i = haystackLower.indexOf(needleLower); if (i >= 0) { return new StringMemory(haystack.substring(i)); } else { return Memory.FALSE; } } @Immutable public static String stripslashes(String string) { StringBuilder sb = new StringBuilder(); int len = string.length(); for (int i = 0; i < len; i++) { char ch = string.charAt(i); if (ch == '\\') { if (i + 1 < len) { char ch2 = string.charAt(i + 1); if (ch2 == '0') { ch2 = 0x0; } sb.append(ch2); i++; } } else { sb.append(ch); } } return sb.toString(); } @Immutable public static String stripcslashes(String source) { StringBuilder result = new StringBuilder(source.length()); int length = source.length(); for (int i = 0; i < length; i++) { int ch = source.charAt(i); if (ch == '\\') { i++; if (i == length) { ch = '\\'; } else { ch = source.charAt(i); switch (ch) { case 'a': ch = 0x07; break; case 'b': ch = '\b'; break; case 't': ch = '\t'; break; case 'n': ch = '\n'; break; case 'v': ch = 0xb; break; case 'f': ch = '\f'; break; case 'r': ch = '\r'; break; case 'x': // up to two digits for a hex number if (i + 1 == length) { break; } int digitValue = hexToDigit(source.charAt(i + 1)); if (digitValue < 0) { break; } ch = digitValue; i++; if (i + 1 == length) { break; } digitValue = hexToDigit(source.charAt(i + 1)); if (digitValue < 0) { break; } ch = ((ch << 4) | digitValue); i++; break; default: // up to three digits from 0 to 7 for an octal number digitValue = octToDigit((char) ch); if (digitValue < 0) { break; } ch = digitValue; if (i + 1 == length) { break; } digitValue = octToDigit(source.charAt(i + 1)); if (digitValue < 0) { break; } ch = ((ch << 3) | digitValue); i++; if (i + 1 == length) { break; } digitValue = octToDigit(source.charAt(i + 1)); if (digitValue < 0) { break; } ch = ((ch << 3) | digitValue); i++; } } } // if ch == '/' result.append((char) ch); } return result.toString(); } @Immutable public static String strip_tags(String string) { return strip_tags(string, null); } @Immutable public static String strip_tags(String string, Memory allowTags) { StringBuilder result = new StringBuilder(); Set<String> allowedTagMap = null; if (allowTags != null) { allowedTagMap = getAllowedTags(allowTags.toString()); } int len = string.length(); for (int i = 0; i < len; i++) { char ch = string.charAt(i); if (i + 1 >= len || ch != '<') { result.append(ch); continue; } ch = string.charAt(i + 1); if (Character.isWhitespace(ch)) { i++; result.append('<'); result.append(ch); continue; } int tagNameStart = i + 1; if (ch == '/') { tagNameStart++; } int j = tagNameStart; while (j < len && (ch = string.charAt(j)) != '>' // && ch != '/' && !Character.isWhitespace(ch)) { j++; } String tagName = string.substring(tagNameStart, j); int tagEnd = 0; if (allowedTagMap != null && allowedTagMap.contains(tagName)) { result.append(string, i, Math.min(j + 1, len)); } else { while (j < len && (ch = string.charAt(j)) != '<') { if (ch == '>') { tagEnd = j; } j++; } } i = (tagEnd != 0) ? tagEnd : j; } return result.toString(); } private static Set<String> getAllowedTags(String str) { int len = str.length(); Set<String> set = new HashSet<String>(); for (int i = 0; i < len; i++) { char ch = str.charAt(i); switch (ch) { case '<': int j = i + 1; while (j < len && (ch = str.charAt(j)) != '>' //&& ch != '/' && !Character.isWhitespace(ch)) { j++; } if (ch == '>' && i + 1 < j && j < len) { set.add(str.substring(i + 1, j)); } i = j; default: continue; } } return set; } public static Memory str_word_count(String string, int format, String additionalWordCharacters) { if (format < 0 || format > 2) { return Memory.NULL; } int strlen = string.length(); boolean isAdditionalWordCharacters = false; if (additionalWordCharacters != null) { isAdditionalWordCharacters = additionalWordCharacters.length() > 0; } ArrayMemory resultArray = null; if (format > 0) { resultArray = new ArrayMemory(); } boolean isBetweenWords = true; int wordCount = 0; int lastWordStart = 0; for (int i = 0; i <= strlen; i++) { boolean isWordCharacter; if (i < strlen) { int ch = string.charAt(i); isWordCharacter = Character.isLetter(ch) || ch == '-' || ch == '\'' || (isAdditionalWordCharacters && additionalWordCharacters.indexOf(ch) > -1); } else { isWordCharacter = false; } if (isWordCharacter) { if (isBetweenWords) { // starting a word isBetweenWords = false; lastWordStart = i; wordCount++; } } else { if (!isBetweenWords) { // finished a word isBetweenWords = true; if (format > 0) { String word = string.substring(lastWordStart, i); if (format == 1) { resultArray.add(new StringMemory(word)); } else if (format == 2) { resultArray.refOfIndex(lastWordStart).assign(word); } } } } } if (resultArray == null) { return LongMemory.valueOf(wordCount); } else { return resultArray.toConstant(); } } public static String base64_encode(Environment env, Memory value) { return DatatypeConverter.printBase64Binary(value.getBinaryBytes(env.getDefaultCharset())); } public static Memory base64_decode(String value) { try { return new BinaryMemory(DatatypeConverter.parseBase64Binary(value)); } catch (IllegalArgumentException e) { return Memory.FALSE; } } public static Memory parse_url(String url, int component) { try { URI uri = URI.create(url); switch (component) { case 0: return uri.getScheme() == null ? Memory.NULL : StringMemory.valueOf(uri.getScheme()); case 1: return uri.getHost() == null ? Memory.NULL : StringMemory.valueOf(uri.getHost()); case 2: return uri.getPort() == -1 ? Memory.NULL : LongMemory.valueOf(uri.getPort()); case 3: case 4: return uri.getUserInfo() != null ? Memory.NULL : StringMemory.valueOf(uri.getUserInfo()); case 5: return uri.getPath() != null ? Memory.NULL : StringMemory.valueOf(uri.getPath()); case 6: return uri.getQuery() != null ? Memory.NULL : StringMemory.valueOf(uri.getQuery()); case 7: return uri.getFragment() != null ? Memory.NULL : StringMemory.valueOf(uri.getFragment()); case -1: ArrayMemory result = new ArrayMemory(); if (uri.getScheme() != null) { result.refOfIndex("scheme").assign(uri.getScheme()); } if (uri.getHost() != null) { result.refOfIndex("host").assign(uri.getHost()); } if (uri.getPort() != -1) { result.refOfIndex("port").assign(uri.getPort()); } if (uri.getPath() != null) { result.refOfIndex("path").assign(uri.getPath()); } if (uri.getUserInfo() != null) { result.refOfIndex("user").assign(uri.getUserInfo()); } if (uri.getQuery() != null) { result.refOfIndex("query").assign(uri.getQuery()); } if (uri.getFragment() != null) { result.refOfIndex("fragment").assign(uri.getFragment()); } return result.toConstant(); default: return Memory.FALSE; } } catch (IllegalArgumentException e) { return Memory.FALSE; } } public static Memory parse_url(String url) { return parse_url(url, -1); } public static String uniqid(String prefix) { return prefix + UUID.fromString(String.valueOf(System.currentTimeMillis())).toString().replace("-", ""); } public static String uniqid() { return uniqid(""); } public static String urldecode(String url) throws UnsupportedEncodingException { return URLDecoder.decode(url, "UTF-8"); } public static String urlencode(String url) throws UnsupportedEncodingException { return URLEncoder.encode(url, "UTF-8"); } public static String rawurlencode(String url) throws UnsupportedEncodingException { return URLEncoder.encode(url, "UTF-8") // OAuth encodes some characters differently: .replace("+", "%20").replace("*", "%2A") .replace("%7E", "~"); } public static String rawurldecode(String url) throws UnsupportedEncodingException { return URLDecoder.decode(url, "UTF-8") // OAuth encodes some characters differently: .replace("%20", "+").replace("%2A", "*") .replace("~", "%7E"); } public static void setLocale() { // nop. } public static void dl(String extension) { // ... nop } public static int strnatcmp(String one, String two) { return new NaturalOrderComparator(false, false).compare(one, two); } public static int strnatcasecmp(String one, String two) { return new NaturalOrderComparator(true, false).compare(one, two); } static class MyGZIPOutputStream extends GZIPOutputStream { public MyGZIPOutputStream( OutputStream out ) throws IOException { super( out ); } public void setLevel( int level ) { def.setLevel(level); } } /*protected static byte[] gzencodeImpl(String str, int level) throws IOException { try (ByteArrayOutputStream out = new ByteArrayOutputStream()) { try (MyGZIPOutputStream gzip = new MyGZIPOutputStream(out)) { gzip.setLevel(level); gzip.write(str.getBytes(StandardCharsets.UTF_8)); } return out.toByteArray(); //return out.toString(StandardCharsets.ISO_8859_1); // Some single byte encoding } } public static String gzdecodeImpl(byte[] str) throws IOException { ByteArrayOutputStream baos = new ByteArrayOutputStream(); try (GZIPInputStream gis = new GZIPInputStream(new ByteArrayInputStream(str))) { int b; while ((b = gis.read()) != -1) { baos.write((byte) b); } } return new String(baos.toByteArray(), StandardCharsets.UTF_8); } public static Memory gzencode(String value) throws IOException { return gzencode(value, -1); } public static Memory gzencode(String value, int level) { if (level == -1) { level = 6; } try { return new BinaryMemory(gzencodeImpl(value, level)); } catch (IOException e) { return Memory.FALSE; } } public static Memory gzdecode(Environment env, Memory value) { try { return StringMemory.valueOf(gzdecodeImpl(value.getBinaryBytes(env.getDefaultCharset()))); } catch (IOException e) { return Memory.FALSE; } }*/ static { DEFAULT_DECIMAL_FORMAT_SYMBOLS = new DecimalFormatSymbols(); DEFAULT_DECIMAL_FORMAT_SYMBOLS.setDecimalSeparator('.'); DEFAULT_DECIMAL_FORMAT_SYMBOLS.setGroupingSeparator(','); DEFAULT_DECIMAL_FORMAT_SYMBOLS.setZeroDigit('0'); HTML_ENTITIES = new ArrayMemory(); HTML_ENTITIES.put("\"", new StringMemory(""")); HTML_ENTITIES.put("&", new StringMemory("&")); HTML_ENTITIES.put("\"", new StringMemory("'")); HTML_ENTITIES.put("<", new StringMemory("<")); HTML_ENTITIES.put(">", new StringMemory(">")); HTML_ENTITIES.put(" ", new StringMemory(" ")); HTML_ENTITIES.put("¡", new StringMemory("¡")); HTML_ENTITIES.put("¢", new StringMemory("¢")); HTML_ENTITIES.put("£", new StringMemory("£")); HTML_ENTITIES.put("¤", new StringMemory("¤")); HTML_ENTITIES.put("¥", new StringMemory("¥")); HTML_ENTITIES.put("¦", new StringMemory("¦")); HTML_ENTITIES.put("§", new StringMemory("§")); HTML_ENTITIES.put("¨", new StringMemory("¨")); HTML_ENTITIES.put("©", new StringMemory("©")); HTML_ENTITIES.put("ª", new StringMemory("ª")); HTML_ENTITIES.put("«", new StringMemory("«")); HTML_ENTITIES.put("¬", new StringMemory("¬")); HTML_ENTITIES.put("­", new StringMemory("­")); HTML_ENTITIES.put("®", new StringMemory("®")); HTML_ENTITIES.put("¯", new StringMemory("¯")); HTML_ENTITIES.put("°", new StringMemory("°")); HTML_ENTITIES.put("±", new StringMemory("±")); HTML_ENTITIES.put("²", new StringMemory("²")); HTML_ENTITIES.put("³", new StringMemory("³")); HTML_ENTITIES.put("´", new StringMemory("´")); HTML_ENTITIES.put("µ", new StringMemory("µ")); HTML_ENTITIES.put("¶", new StringMemory("¶")); HTML_ENTITIES.put("·", new StringMemory("·")); HTML_ENTITIES.put("¸", new StringMemory("¸")); HTML_ENTITIES.put("¹", new StringMemory("¹")); HTML_ENTITIES.put("º", new StringMemory("º")); HTML_ENTITIES.put("»", new StringMemory("»")); HTML_ENTITIES.put("¼", new StringMemory("¼")); HTML_ENTITIES.put("½", new StringMemory("½")); HTML_ENTITIES.put("¾", new StringMemory("¾")); HTML_ENTITIES.put("¿", new StringMemory("¿")); HTML_ENTITIES.put("À", new StringMemory("À")); HTML_ENTITIES.put("Á", new StringMemory("Á")); HTML_ENTITIES.put("Â", new StringMemory("Â")); HTML_ENTITIES.put("Ã", new StringMemory("Ã")); HTML_ENTITIES.put("Ä", new StringMemory("Ä")); HTML_ENTITIES.put("Å", new StringMemory("Å")); HTML_ENTITIES.put("Æ", new StringMemory("Æ")); HTML_ENTITIES.put("Ç", new StringMemory("Ç")); HTML_ENTITIES.put("È", new StringMemory("È")); HTML_ENTITIES.put("É", new StringMemory("É")); HTML_ENTITIES.put("Ê", new StringMemory("Ê")); HTML_ENTITIES.put("Ë", new StringMemory("Ë")); HTML_ENTITIES.put("Ì", new StringMemory("Ì")); HTML_ENTITIES.put("Í", new StringMemory("Í")); HTML_ENTITIES.put("Î", new StringMemory("Î")); HTML_ENTITIES.put("Ï", new StringMemory("Ï")); HTML_ENTITIES.put("Ð", new StringMemory("Ð")); HTML_ENTITIES.put("Ñ", new StringMemory("Ñ")); HTML_ENTITIES.put("Ò", new StringMemory("Ò")); HTML_ENTITIES.put("Ó", new StringMemory("Ó")); HTML_ENTITIES.put("Ô", new StringMemory("Ô")); HTML_ENTITIES.put("Õ", new StringMemory("Õ")); HTML_ENTITIES.put("Ö", new StringMemory("Ö")); HTML_ENTITIES.put("×", new StringMemory("×")); HTML_ENTITIES.put("Ø", new StringMemory("Ø")); HTML_ENTITIES.put("Ù", new StringMemory("Ù")); HTML_ENTITIES.put("Ú", new StringMemory("Ú")); HTML_ENTITIES.put("Û", new StringMemory("Û")); HTML_ENTITIES.put("Ü", new StringMemory("Ü")); HTML_ENTITIES.put("Ý", new StringMemory("Ý")); HTML_ENTITIES.put("Þ", new StringMemory("Þ")); HTML_ENTITIES.put("ß", new StringMemory("ß")); HTML_ENTITIES.put("à", new StringMemory("à")); HTML_ENTITIES.put("á", new StringMemory("á")); HTML_ENTITIES.put("â", new StringMemory("â")); HTML_ENTITIES.put("ã", new StringMemory("ã")); HTML_ENTITIES.put("ä", new StringMemory("ä")); HTML_ENTITIES.put("å", new StringMemory("å")); HTML_ENTITIES.put("æ", new StringMemory("æ")); HTML_ENTITIES.put("ç", new StringMemory("ç")); HTML_ENTITIES.put("è", new StringMemory("è")); HTML_ENTITIES.put("é", new StringMemory("é")); HTML_ENTITIES.put("ê", new StringMemory("ê")); HTML_ENTITIES.put("ë", new StringMemory("ë")); HTML_ENTITIES.put("ì", new StringMemory("ì")); HTML_ENTITIES.put("í", new StringMemory("í")); HTML_ENTITIES.put("î", new StringMemory("î")); HTML_ENTITIES.put("ï", new StringMemory("ï")); HTML_ENTITIES.put("ð", new StringMemory("ð")); HTML_ENTITIES.put("ñ", new StringMemory("ñ")); HTML_ENTITIES.put("ò", new StringMemory("ò")); HTML_ENTITIES.put("ó", new StringMemory("ó")); HTML_ENTITIES.put("ô", new StringMemory("ô")); HTML_ENTITIES.put("õ", new StringMemory("õ")); HTML_ENTITIES.put("ö", new StringMemory("ö")); HTML_ENTITIES.put("÷", new StringMemory("÷")); HTML_ENTITIES.put("ø", new StringMemory("ø")); HTML_ENTITIES.put("ù", new StringMemory("ù")); HTML_ENTITIES.put("ú", new StringMemory("ú")); HTML_ENTITIES.put("û", new StringMemory("û")); HTML_ENTITIES.put("ü", new StringMemory("ü")); HTML_ENTITIES.put("ý", new StringMemory("ý")); HTML_ENTITIES.put("þ", new StringMemory("þ")); HTML_ENTITIES.put("ÿ", new StringMemory("ÿ")); HTML_ENTITIES.put("Œ", new StringMemory("Œ")); HTML_ENTITIES.put("œ", new StringMemory("œ")); HTML_ENTITIES.put("Š", new StringMemory("Š")); HTML_ENTITIES.put("š", new StringMemory("š")); HTML_ENTITIES.put("Ÿ", new StringMemory("Ÿ")); HTML_ENTITIES.put("ƒ", new StringMemory("ƒ")); HTML_ENTITIES.put("ˆ", new StringMemory("ˆ")); HTML_ENTITIES.put("˜", new StringMemory("˜")); HTML_ENTITIES.put("Α", new StringMemory("Α")); HTML_ENTITIES.put("Β", new StringMemory("Β")); HTML_ENTITIES.put("Γ", new StringMemory("Γ")); HTML_ENTITIES.put("Δ", new StringMemory("Δ")); HTML_ENTITIES.put("Ε", new StringMemory("Ε")); HTML_ENTITIES.put("Ζ", new StringMemory("Ζ")); HTML_ENTITIES.put("Η", new StringMemory("Η")); HTML_ENTITIES.put("Θ", new StringMemory("Θ")); HTML_ENTITIES.put("Ι", new StringMemory("Ι")); HTML_ENTITIES.put("Κ", new StringMemory("Κ")); HTML_ENTITIES.put("Λ", new StringMemory("Λ")); HTML_ENTITIES.put("Μ", new StringMemory("Μ")); HTML_ENTITIES.put("Ν", new StringMemory("Ν")); HTML_ENTITIES.put("Ξ", new StringMemory("Ξ")); HTML_ENTITIES.put("Ο", new StringMemory("Ο")); HTML_ENTITIES.put("Π", new StringMemory("Π")); HTML_ENTITIES.put("Ρ", new StringMemory("Ρ")); HTML_ENTITIES.put("Σ", new StringMemory("Σ")); HTML_ENTITIES.put("Τ", new StringMemory("Τ")); HTML_ENTITIES.put("Υ", new StringMemory("Υ")); HTML_ENTITIES.put("Φ", new StringMemory("Φ")); HTML_ENTITIES.put("Χ", new StringMemory("Χ")); HTML_ENTITIES.put("Ψ", new StringMemory("Ψ")); HTML_ENTITIES.put("Ω", new StringMemory("Ω")); HTML_ENTITIES.put("α", new StringMemory("α")); HTML_ENTITIES.put("β", new StringMemory("β")); HTML_ENTITIES.put("γ", new StringMemory("γ")); HTML_ENTITIES.put("δ", new StringMemory("δ")); HTML_ENTITIES.put("ε", new StringMemory("ε")); HTML_ENTITIES.put("ζ", new StringMemory("ζ")); HTML_ENTITIES.put("η", new StringMemory("η")); HTML_ENTITIES.put("θ", new StringMemory("θ")); HTML_ENTITIES.put("ι", new StringMemory("ι")); HTML_ENTITIES.put("κ", new StringMemory("κ")); HTML_ENTITIES.put("λ", new StringMemory("λ")); HTML_ENTITIES.put("μ", new StringMemory("μ")); HTML_ENTITIES.put("ν", new StringMemory("ν")); HTML_ENTITIES.put("ξ", new StringMemory("ξ")); HTML_ENTITIES.put("ο", new StringMemory("ο")); HTML_ENTITIES.put("π", new StringMemory("π")); HTML_ENTITIES.put("ρ", new StringMemory("ρ")); HTML_ENTITIES.put("ς", new StringMemory("ς")); HTML_ENTITIES.put("σ", new StringMemory("σ")); HTML_ENTITIES.put("τ", new StringMemory("τ")); HTML_ENTITIES.put("υ", new StringMemory("υ")); HTML_ENTITIES.put("φ", new StringMemory("φ")); HTML_ENTITIES.put("χ", new StringMemory("χ")); HTML_ENTITIES.put("ψ", new StringMemory("ψ")); HTML_ENTITIES.put("ω", new StringMemory("ω")); HTML_ENTITIES.put("ϑ", new StringMemory("ϑ")); HTML_ENTITIES.put("ϒ", new StringMemory("ϒ")); HTML_ENTITIES.put("ϖ", new StringMemory("ϖ")); HTML_ENTITIES.put(" ", new StringMemory(" ")); HTML_ENTITIES.put(" ", new StringMemory(" ")); HTML_ENTITIES.put(" ", new StringMemory(" ")); HTML_ENTITIES.put("‌", new StringMemory("‌")); HTML_ENTITIES.put("‍", new StringMemory("‍")); HTML_ENTITIES.put("‎", new StringMemory("‎")); HTML_ENTITIES.put("‏", new StringMemory("‏")); HTML_ENTITIES.put("–", new StringMemory("–")); HTML_ENTITIES.put("—", new StringMemory("—")); HTML_ENTITIES.put("‘", new StringMemory("‘")); HTML_ENTITIES.put("’", new StringMemory("’")); HTML_ENTITIES.put("‚", new StringMemory("‚")); HTML_ENTITIES.put("“", new StringMemory("“")); HTML_ENTITIES.put("”", new StringMemory("”")); HTML_ENTITIES.put("„", new StringMemory("„")); HTML_ENTITIES.put("†", new StringMemory("†")); HTML_ENTITIES.put("‡", new StringMemory("‡")); HTML_ENTITIES.put("•", new StringMemory("•")); HTML_ENTITIES.put("…", new StringMemory("…")); HTML_ENTITIES.put("‰", new StringMemory("‰")); HTML_ENTITIES.put("′", new StringMemory("′")); HTML_ENTITIES.put("″", new StringMemory("″")); HTML_ENTITIES.put("‹", new StringMemory("‹")); HTML_ENTITIES.put("›", new StringMemory("›")); HTML_ENTITIES.put("‾", new StringMemory("‾")); HTML_ENTITIES.put("⁄", new StringMemory("⁄")); HTML_ENTITIES.put("€", new StringMemory("€")); HTML_ENTITIES.put("ℑ", new StringMemory("ℑ")); HTML_ENTITIES.put("℘", new StringMemory("℘")); HTML_ENTITIES.put("ℜ", new StringMemory("ℜ")); HTML_ENTITIES.put("™", new StringMemory("™")); HTML_ENTITIES.put("ℵ", new StringMemory("ℵ")); HTML_ENTITIES.put("←", new StringMemory("←")); HTML_ENTITIES.put("↑", new StringMemory("↑")); HTML_ENTITIES.put("→", new StringMemory("→")); HTML_ENTITIES.put("↓", new StringMemory("↓")); HTML_ENTITIES.put("↔", new StringMemory("↔")); HTML_ENTITIES.put("↵", new StringMemory("↵")); HTML_ENTITIES.put("⇐", new StringMemory("⇐")); HTML_ENTITIES.put("⇑", new StringMemory("⇑")); HTML_ENTITIES.put("⇒", new StringMemory("⇒")); HTML_ENTITIES.put("⇓", new StringMemory("⇓")); HTML_ENTITIES.put("⇔", new StringMemory("⇔")); HTML_ENTITIES.put("∀", new StringMemory("∀")); HTML_ENTITIES.put("∂", new StringMemory("∂")); HTML_ENTITIES.put("∃", new StringMemory("∃")); HTML_ENTITIES.put("∅", new StringMemory("∅")); HTML_ENTITIES.put("∇", new StringMemory("∇")); HTML_ENTITIES.put("∈", new StringMemory("∈")); HTML_ENTITIES.put("∉", new StringMemory("∉")); HTML_ENTITIES.put("∋", new StringMemory("∋")); HTML_ENTITIES.put("∏", new StringMemory("∏")); HTML_ENTITIES.put("∑", new StringMemory("∑")); HTML_ENTITIES.put("−", new StringMemory("−")); HTML_ENTITIES.put("∗", new StringMemory("∗")); HTML_ENTITIES.put("√", new StringMemory("√")); HTML_ENTITIES.put("∝", new StringMemory("∝")); HTML_ENTITIES.put("∞", new StringMemory("∞")); HTML_ENTITIES.put("∠", new StringMemory("∠")); HTML_ENTITIES.put("∧", new StringMemory("∧")); HTML_ENTITIES.put("∨", new StringMemory("∨")); HTML_ENTITIES.put("∩", new StringMemory("∩")); HTML_ENTITIES.put("∪", new StringMemory("∪")); HTML_ENTITIES.put("∫", new StringMemory("∫")); HTML_ENTITIES.put("∴", new StringMemory("∴")); HTML_ENTITIES.put("∼", new StringMemory("∼")); HTML_ENTITIES.put("≅", new StringMemory("≅")); HTML_ENTITIES.put("≈", new StringMemory("≈")); HTML_ENTITIES.put("≠", new StringMemory("≠")); HTML_ENTITIES.put("≡", new StringMemory("≡")); HTML_ENTITIES.put("≤", new StringMemory("≤")); HTML_ENTITIES.put("≥", new StringMemory("≥")); HTML_ENTITIES.put("⊂", new StringMemory("⊂")); HTML_ENTITIES.put("⊃", new StringMemory("⊃")); HTML_ENTITIES.put("⊄", new StringMemory("⊄")); HTML_ENTITIES.put("⊆", new StringMemory("⊆")); HTML_ENTITIES.put("⊇", new StringMemory("⊇")); HTML_ENTITIES.put("⊕", new StringMemory("⊕")); HTML_ENTITIES.put("⊗", new StringMemory("⊗")); HTML_ENTITIES.put("⊥", new StringMemory("⊥")); HTML_ENTITIES.put("⋅", new StringMemory("⋅")); HTML_ENTITIES.put("⌈", new StringMemory("⌈")); HTML_ENTITIES.put("⌉", new StringMemory("⌉")); HTML_ENTITIES.put("⌊", new StringMemory("⌊")); HTML_ENTITIES.put("⌋", new StringMemory("⌋")); HTML_ENTITIES.put("〈", new StringMemory("⟨")); HTML_ENTITIES.put("〉", new StringMemory("⟩")); HTML_ENTITIES.put("◊", new StringMemory("◊")); HTML_ENTITIES.put("♠", new StringMemory("♠")); HTML_ENTITIES.put("♣", new StringMemory("♣")); HTML_ENTITIES.put("♥", new StringMemory("♥")); HTML_ENTITIES.put("♦", new StringMemory("♦")); HTML_SPECIALCHARS = new ArrayMemory(); HTML_SPECIALCHARS.put("<", new StringMemory("<")); HTML_SPECIALCHARS.put(">", new StringMemory(">")); HTML_SPECIALCHARS.put("&", new StringMemory("&")); ForeachIterator iterator = HTML_ENTITIES.foreachIterator(false, false); while (iterator.next()) { HTML_SPECIALCHARS.refOfIndex(iterator.getValue()).assign(iterator.getKey().toString()); } } }