0001: /*
0002: * Copyright (c) 1998-2008 Caucho Technology -- all rights reserved
0003: *
0004: * This file is part of Resin(R) Open Source
0005: *
0006: * Each copy or derived work must preserve the copyright notice and this
0007: * notice unmodified.
0008: *
0009: * Resin Open Source is free software; you can redistribute it and/or modify
0010: * it under the terms of the GNU General Public License as published by
0011: * the Free Software Foundation; either version 2 of the License, or
0012: * (at your option) any later version.
0013: *
0014: * Resin Open Source is distributed in the hope that it will be useful,
0015: * but WITHOUT ANY WARRANTY; without even the implied warranty of
0016: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
0017: * of NON-INFRINGEMENT. See the GNU General Public License for more
0018: * details.
0019: *
0020: * You should have received a copy of the GNU General Public License
0021: * along with Resin Open Source; if not, write to the
0022: *
0023: * Free Software Foundation, Inc.
0024: * 59 Temple Place, Suite 330
0025: * Boston, MA 02111-1307 USA
0026: *
0027: * @author Scott Ferguson
0028: */
0029:
0030: package com.caucho.quercus.env;
0031:
0032: import com.caucho.vfs.*;
0033: import com.caucho.quercus.lib.file.BinaryInput;
0034: import com.caucho.quercus.QuercusModuleException;
0035:
0036: import java.io.*;
0037: import java.util.IdentityHashMap;
0038:
0039: /**
0040: * Represents a PHP 5 style string builder (unicode.semantics = off)
0041: */
0042: public class StringBuilderValue extends StringValue {
0043: public static final StringBuilderValue EMPTY = new StringBuilderValue(
0044: "");
0045:
0046: private final static StringBuilderValue[] CHAR_STRINGS;
0047:
0048: protected char[] _buffer;
0049: protected int _length;
0050: protected boolean _isCopy;
0051: private int _hashCode;
0052:
0053: protected String _value;
0054:
0055: public StringBuilderValue() {
0056: _buffer = new char[128];
0057: }
0058:
0059: public StringBuilderValue(int capacity) {
0060: if (capacity < 64)
0061: capacity = 64;
0062:
0063: _buffer = new char[capacity];
0064: }
0065:
0066: public StringBuilderValue(char[] buffer, int offset, int length) {
0067: _buffer = new char[length];
0068: _length = length;
0069:
0070: System.arraycopy(buffer, offset, _buffer, 0, length);
0071: }
0072:
0073: public StringBuilderValue(byte[] buffer, int offset, int length) {
0074: _buffer = new char[length];
0075: _length = length;
0076:
0077: for (int i = offset; i < length; i++)
0078: _buffer[i] = (char) buffer[i];
0079: }
0080:
0081: public StringBuilderValue(byte[] buffer) {
0082: this (buffer, 0, buffer.length);
0083: }
0084:
0085: public StringBuilderValue(Byte[] buffer) {
0086: int length = buffer.length;
0087:
0088: _buffer = new char[length];
0089: _length = length;
0090:
0091: for (int i = 0; i < length; i++) {
0092: _buffer[i] = (char) buffer[i].byteValue();
0093: }
0094: }
0095:
0096: public StringBuilderValue(Character[] buffer) {
0097: int length = buffer.length;
0098:
0099: _buffer = new char[length];
0100: _length = length;
0101:
0102: for (int i = 0; i < length; i++) {
0103: _buffer[i] = buffer[i];
0104: }
0105: }
0106:
0107: public StringBuilderValue(char ch) {
0108: _buffer = new char[1];
0109: _length = 1;
0110:
0111: _buffer[0] = ch;
0112: }
0113:
0114: public StringBuilderValue(String s) {
0115: int len = s.length();
0116:
0117: _buffer = new char[len];
0118: _length = len;
0119:
0120: s.getChars(0, len, _buffer, 0);
0121: }
0122:
0123: public StringBuilderValue(char[] s) {
0124: int len = s.length;
0125:
0126: _buffer = new char[len];
0127: _length = len;
0128:
0129: System.arraycopy(s, 0, _buffer, 0, len);
0130: }
0131:
0132: public StringBuilderValue(char[] s, Value v1) {
0133: int len = s.length;
0134:
0135: if (len < 128)
0136: _buffer = new char[128];
0137: else
0138: _buffer = new char[len + 32];
0139:
0140: _length = len;
0141:
0142: System.arraycopy(s, 0, _buffer, 0, len);
0143:
0144: v1.appendTo(this );
0145: }
0146:
0147: public StringBuilderValue(Value v1) {
0148: _buffer = new char[128];
0149:
0150: v1.appendTo(this );
0151: }
0152:
0153: public StringBuilderValue(Value v1, Value v2) {
0154: _buffer = new char[128];
0155:
0156: v1.appendTo(this );
0157: v2.appendTo(this );
0158: }
0159:
0160: public StringBuilderValue(Value v1, Value v2, Value v3) {
0161: _buffer = new char[128];
0162:
0163: v1.appendTo(this );
0164: v2.appendTo(this );
0165: v3.appendTo(this );
0166: }
0167:
0168: /**
0169: * Creates the string.
0170: */
0171: public static StringValue create(char value) {
0172: if (value < CHAR_STRINGS.length)
0173: return CHAR_STRINGS[value];
0174: else
0175: return new StringBuilderValue(value);
0176: }
0177:
0178: /**
0179: * Creates a PHP string from a Java String.
0180: * If the value is null then NullValue is returned.
0181: */
0182: public static Value create(String value) {
0183: if (value == null)
0184: return NullValue.NULL;
0185: else if (value.length() == 0)
0186: return StringBuilderValue.EMPTY;
0187: else
0188: return new StringBuilderValue(value);
0189: }
0190:
0191: /*
0192: * Creates an empty string builder of the same type.
0193: */
0194: public StringValue createEmptyStringBuilder() {
0195: return new StringBuilderValue();
0196: }
0197:
0198: /*
0199: * Returns the empty string of same type.
0200: */
0201: public StringValue getEmptyString() {
0202: return EMPTY;
0203: }
0204:
0205: /**
0206: * Returns the value.
0207: */
0208: public String getValue() {
0209: return toString();
0210: }
0211:
0212: /**
0213: * Returns the type.
0214: */
0215: @Override
0216: public String getType() {
0217: return "string";
0218: }
0219:
0220: /**
0221: * Returns the ValueType.
0222: */
0223: @Override
0224: public ValueType getValueType() {
0225: return UnicodeBuilderValue.getValueType(_buffer, 0, _length);
0226: }
0227:
0228: /**
0229: * Returns true for a scalar
0230: */
0231: @Override
0232: public boolean isScalar() {
0233: return true;
0234: }
0235:
0236: /*
0237: * Returns true if this is a PHP5 string.
0238: */
0239: @Override
0240: public boolean isPHP5String() {
0241: return true;
0242: }
0243:
0244: /**
0245: * Converts to a boolean.
0246: */
0247: @Override
0248: public boolean toBoolean() {
0249: if (_length == 0)
0250: return false;
0251: else if (_length == 1 && _buffer[0] == '0')
0252: return false;
0253: else
0254: return true;
0255: }
0256:
0257: /**
0258: * Converts to a long.
0259: */
0260: @Override
0261: public long toLong() {
0262: return UnicodeBuilderValue.toLong(_buffer, 0, _length);
0263: }
0264:
0265: /**
0266: * Converts to a double.
0267: */
0268: @Override
0269: public double toDouble() {
0270: return UnicodeBuilderValue.toDouble(_buffer, 0, _length);
0271: }
0272:
0273: /**
0274: * Convert to an input stream.
0275: */
0276: @Override
0277: public InputStream toInputStream() {
0278: return new BuilderInputStream();
0279: }
0280:
0281: /**
0282: * Converts to a string.
0283: */
0284: @Override
0285: public String toString() {
0286: // XXX: encoding
0287: if (_value == null)
0288: _value = new String(_buffer, 0, _length);
0289:
0290: return _value;
0291: }
0292:
0293: /**
0294: * Converts to a BinaryValue.
0295: */
0296: @Override
0297: public StringValue toBinaryValue(Env env) {
0298: return this ;
0299: }
0300:
0301: /**
0302: * Converts to a BinaryValue in desired charset.
0303: */
0304: @Override
0305: public StringValue toBinaryValue(Env env, String charset) {
0306: return this ;
0307: }
0308:
0309: /**
0310: * Converts to a UnicodeValue.
0311: */
0312: @Override
0313: public StringValue toUnicodeValue() {
0314: return this ;
0315: }
0316:
0317: /**
0318: * Converts to a UnicodeValue.
0319: */
0320: @Override
0321: public StringValue toUnicodeValue(Env env) {
0322: return toUnicodeValue();
0323: }
0324:
0325: /**
0326: * Converts to a UnicodeValue in desired charset.
0327: */
0328: @Override
0329: public StringValue toUnicodeValue(Env env, String charset) {
0330: return toUnicodeValue();
0331: }
0332:
0333: /**
0334: * Converts to an object.
0335: */
0336: @Override
0337: public Object toJavaObject() {
0338: if (_value == null)
0339: _value = new String(_buffer, 0, _length);
0340:
0341: return _value;
0342: }
0343:
0344: /**
0345: * Converts to a string builder
0346: */
0347: @Override
0348: public StringValue toStringBuilder() {
0349: // XXX: can this just return this, or does it need to return a copy?
0350: return new StringBuilderValue(_buffer, 0, _length);
0351: }
0352:
0353: /**
0354: * Writes to a stream
0355: */
0356: @Override
0357: public void writeTo(OutputStream os) {
0358: try {
0359: int len = _length;
0360:
0361: for (int i = 0; i < len; i++)
0362: os.write(_buffer[i]);
0363: } catch (IOException e) {
0364: throw new QuercusModuleException(e);
0365: }
0366: }
0367:
0368: /**
0369: * Append to a string builder.
0370: */
0371: @Override
0372: public StringValue appendTo(StringBuilderValue bb) {
0373: bb.append(_buffer, 0, _length);
0374:
0375: return bb;
0376: }
0377:
0378: /**
0379: * Append to a string builder.
0380: */
0381: @Override
0382: public StringValue appendTo(UnicodeBuilderValue bb) {
0383: bb.append(_buffer, 0, _length);
0384:
0385: return bb;
0386: }
0387:
0388: /**
0389: * Append to a string builder.
0390: */
0391: @Override
0392: public StringValue appendTo(LargeStringBuilderValue bb) {
0393: bb.append(_buffer, 0, _length);
0394:
0395: return bb;
0396: }
0397:
0398: /**
0399: * Append to a string builder.
0400: */
0401: @Override
0402: public StringValue appendTo(BinaryBuilderValue bb) {
0403: bb.append(_buffer, 0, _length);
0404:
0405: return bb;
0406: }
0407:
0408: /**
0409: * Converts to a key.
0410: */
0411: @Override
0412: public Value toKey() {
0413: char[] buffer = _buffer;
0414: int len = _length;
0415:
0416: if (len == 0)
0417: return this ;
0418:
0419: int sign = 1;
0420: long value = 0;
0421:
0422: int i = 0;
0423: int ch = buffer[i];
0424: if (ch == '-') {
0425: sign = -1;
0426: i++;
0427: }
0428:
0429: for (; i < len; i++) {
0430: ch = buffer[i];
0431:
0432: if ('0' <= ch && ch <= '9')
0433: value = 10 * value + ch - '0';
0434: else
0435: return this ;
0436: }
0437:
0438: return new LongValue(sign * value);
0439: }
0440:
0441: /**
0442: * Converts to a byte array, with no consideration of character encoding.
0443: * Each character becomes one byte, characters with values above 255 are
0444: * not correctly preserved.
0445: */
0446: public byte[] toBytes() {
0447: byte[] bytes = new byte[_length];
0448:
0449: for (int i = _length - 1; i >= 0; i--)
0450: bytes[i] = (byte) _buffer[i];
0451:
0452: return bytes;
0453: }
0454:
0455: //
0456: // Operations
0457: //
0458:
0459: /**
0460: * Returns the character at an index
0461: */
0462: public Value get(Value key) {
0463: return charValueAt(key.toLong());
0464: }
0465:
0466: /**
0467: * Returns the character at an index
0468: */
0469: public Value getRef(Value key) {
0470: return charValueAt(key.toLong());
0471: }
0472:
0473: /**
0474: * sets the character at an index
0475: */
0476: /*
0477: public Value setCharAt(long index, String value)
0478: {
0479: int len = _length;
0480:
0481: if (index < 0 || len <= index)
0482: return this;
0483: else {
0484: StringBuilderValue sb = new StringBuilderValue(_buffer, 0, (int) index);
0485: sb.append(value);
0486: sb.append(_buffer, (int) (index + 1), (int) (len - index - 1));
0487:
0488: return sb;
0489: }
0490: }
0491: */
0492:
0493: //
0494: // CharSequence
0495: //
0496: /**
0497: * Returns the length of the string.
0498: */
0499: @Override
0500: public int length() {
0501: return _length;
0502: }
0503:
0504: /**
0505: * Returns the character at a particular location
0506: */
0507: @Override
0508: public char charAt(int index) {
0509: return _buffer[index];
0510: }
0511:
0512: /**
0513: * Returns the character at an index
0514: */
0515: @Override
0516: public Value charValueAt(long index) {
0517: int len = _length;
0518:
0519: if (index < 0 || len <= index)
0520: return UnsetStringValue.UNSET;
0521: else {
0522: int ch = _buffer[(int) index];
0523:
0524: if (ch < CHAR_STRINGS.length)
0525: return CHAR_STRINGS[ch];
0526: else
0527: return new StringBuilderValue((char) ch);
0528: }
0529: }
0530:
0531: /**
0532: * Returns the last index of the match string, starting from the head.
0533: */
0534: public int indexOf(char match) {
0535: int length = _length;
0536:
0537: char[] buffer = _buffer;
0538: for (int head = 0; head < length; head++) {
0539: if (buffer[head] == match)
0540: return head;
0541: }
0542:
0543: return -1;
0544: }
0545:
0546: /**
0547: * Returns the last index of the match string, starting from the head.
0548: */
0549: @Override
0550: public int indexOf(char match, int head) {
0551: int length = _length;
0552:
0553: char[] buffer = _buffer;
0554: for (; head < length; head++) {
0555: if (buffer[head] == match)
0556: return head;
0557: }
0558:
0559: return -1;
0560: }
0561:
0562: /**
0563: * Returns a subsequence
0564: */
0565: @Override
0566: public CharSequence subSequence(int start, int end) {
0567: if (end <= start)
0568: return StringBuilderValue.EMPTY;
0569:
0570: return new StringBuilderValue(_buffer, start, end - start);
0571: }
0572:
0573: /**
0574: * Convert to lower case.
0575: */
0576: @Override
0577: public StringValue toLowerCase() {
0578: int length = _length;
0579:
0580: StringBuilderValue string = new StringBuilderValue(length);
0581:
0582: char[] srcBuffer = _buffer;
0583: char[] dstBuffer = string._buffer;
0584:
0585: for (int i = 0; i < length; i++) {
0586: char ch = srcBuffer[i];
0587:
0588: if ('A' <= ch && ch <= 'Z')
0589: dstBuffer[i] = (char) (ch + 'a' - 'A');
0590: else
0591: dstBuffer[i] = ch;
0592: }
0593:
0594: string._length = length;
0595:
0596: return string;
0597: }
0598:
0599: /**
0600: * Convert to lower case.
0601: */
0602: @Override
0603: public StringValue toUpperCase() {
0604: int length = _length;
0605:
0606: StringBuilderValue string = new StringBuilderValue(_length);
0607:
0608: char[] srcBuffer = _buffer;
0609: char[] dstBuffer = string._buffer;
0610:
0611: for (int i = 0; i < length; i++) {
0612: char ch = srcBuffer[i];
0613:
0614: if ('a' <= ch && ch <= 'z')
0615: dstBuffer[i] = (char) (ch + 'A' - 'a');
0616: else
0617: dstBuffer[i] = ch;
0618: }
0619:
0620: string._length = length;
0621:
0622: return string;
0623: }
0624:
0625: /**
0626: * Returns true if the region matches
0627: */
0628: public boolean regionMatches(int offset, char[] mBuffer,
0629: int mOffset, int mLength) {
0630: int length = _length;
0631:
0632: if (length < offset + mLength)
0633: return false;
0634:
0635: char[] buffer = _buffer;
0636:
0637: for (int i = 0; i < mLength; i++) {
0638: if (buffer[offset + i] != mBuffer[mOffset + i])
0639: return false;
0640: }
0641:
0642: return true;
0643: }
0644:
0645: /**
0646: * Returns true if the region matches
0647: */
0648: public boolean regionMatchesIgnoreCase(int offset, char[] mBuffer,
0649: int mOffset, int mLength) {
0650: int length = _length;
0651:
0652: if (length < offset + mLength)
0653: return false;
0654:
0655: char[] buffer = _buffer;
0656:
0657: for (int i = 0; i < mLength; i++) {
0658: char a = buffer[offset + i];
0659: char b = mBuffer[mOffset + i];
0660:
0661: if ('A' <= a && a <= 'Z')
0662: a += 'a' - 'A';
0663:
0664: if ('A' <= b && b <= 'Z')
0665: b += 'a' - 'A';
0666:
0667: if (a != b)
0668: return false;
0669: }
0670:
0671: return true;
0672: }
0673:
0674: /**
0675: * Creates a string builder of the same type.
0676: */
0677: @Override
0678: public StringValue createStringBuilder() {
0679: return new StringBuilderValue();
0680: }
0681:
0682: /**
0683: * Creates a string builder of the same type.
0684: */
0685: @Override
0686: public StringValue createStringBuilder(int length) {
0687: return new StringBuilderValue(length);
0688: }
0689:
0690: /**
0691: * Converts to a string builder
0692: */
0693: @Override
0694: public StringValue toStringBuilder(Env env) {
0695: return new StringBuilderValue(_buffer, 0, _length);
0696: }
0697:
0698: //
0699: // append code
0700: //
0701:
0702: /**
0703: * Append a Java string to the value.
0704: */
0705: @Override
0706: public final StringValue append(String s) {
0707: int sublen = s.length();
0708:
0709: if (_buffer.length < _length + sublen)
0710: ensureCapacity(_length + sublen);
0711:
0712: for (int i = 0; i < sublen; i++) {
0713: _buffer[_length++] = s.charAt(i);
0714: }
0715:
0716: return this ;
0717: }
0718:
0719: /**
0720: * Append a Java string to the value.
0721: */
0722: @Override
0723: public final StringValue append(String s, int start, int end) {
0724: int sublen = end - start;
0725:
0726: if (_buffer.length < _length + sublen)
0727: ensureCapacity(_length + sublen);
0728:
0729: char[] buffer = _buffer;
0730: int length = _length;
0731:
0732: for (; start < end; start++)
0733: buffer[length++] = s.charAt(start);
0734:
0735: _length = length;
0736:
0737: return this ;
0738: }
0739:
0740: /**
0741: * Append a Java char to the value.
0742: */
0743: @Override
0744: public final StringValue append(char ch) {
0745: if (_buffer.length < _length + 1)
0746: ensureCapacity(_length + 1);
0747:
0748: _buffer[_length++] = ch;
0749:
0750: return this ;
0751: }
0752:
0753: /**
0754: * Append a Java buffer to the value.
0755: */
0756: @Override
0757: public final StringValue append(char[] buf, int offset, int length) {
0758: if (_buffer.length < _length + length)
0759: ensureCapacity(_length + length);
0760:
0761: char[] buffer = _buffer;
0762: int bufferLength = _length;
0763:
0764: for (; length > 0; length--)
0765: buffer[bufferLength++] = buf[offset++];
0766:
0767: _buffer = buffer;
0768: _length = bufferLength;
0769:
0770: return this ;
0771: }
0772:
0773: /**
0774: * Append a Java buffer to the value.
0775: */
0776: @Override
0777: public final StringValue appendUnicode(char[] buf, int offset,
0778: int length) {
0779: if (_buffer.length < _length + length)
0780: ensureCapacity(_length + length);
0781:
0782: char[] buffer = _buffer;
0783: int bufferLength = _length;
0784:
0785: for (; length > 0; length--)
0786: buffer[bufferLength++] = buf[offset++];
0787:
0788: _buffer = buffer;
0789: _length = bufferLength;
0790:
0791: return this ;
0792: }
0793:
0794: /**
0795: * Append a Java buffer to the value.
0796: */
0797: @Override
0798: public final StringValue append(char[] buf) {
0799: int length = buf.length;
0800:
0801: if (_buffer.length < _length + length)
0802: ensureCapacity(_length + length);
0803:
0804: char[] buffer = _buffer;
0805: int bufferLength = _length;
0806: _length = bufferLength + length;
0807:
0808: for (length--; length >= 0; length--)
0809: buffer[bufferLength + length] = buf[length];
0810:
0811: _buffer = buffer;
0812:
0813: return this ;
0814: }
0815:
0816: /**
0817: * Append a Java buffer to the value.
0818: */
0819: @Override
0820: public final StringValue appendUnicode(char[] buf) {
0821: int length = buf.length;
0822:
0823: if (_buffer.length < _length + length)
0824: ensureCapacity(_length + length);
0825:
0826: char[] buffer = _buffer;
0827: int bufferLength = _length;
0828: _length = bufferLength + length;
0829:
0830: for (length--; length >= 0; length--)
0831: buffer[bufferLength + length] = buf[length];
0832:
0833: _buffer = buffer;
0834:
0835: return this ;
0836: }
0837:
0838: /**
0839: * Append a Java buffer to the value.
0840: */
0841: @Override
0842: public final StringValue append(CharSequence buf, int head, int tail) {
0843: int length = tail - head;
0844:
0845: if (_buffer.length < _length + length)
0846: ensureCapacity(_length + length);
0847:
0848: if (buf instanceof StringBuilderValue) {
0849: StringBuilderValue sb = (StringBuilderValue) buf;
0850:
0851: System.arraycopy(sb._buffer, head, _buffer, _length, tail
0852: - head);
0853:
0854: _length += tail - head;
0855:
0856: return this ;
0857: } else {
0858: char[] buffer = _buffer;
0859: int bufferLength = _length;
0860:
0861: for (; head < tail; head++) {
0862: buffer[bufferLength++] = buf.charAt(head);
0863: }
0864:
0865: _length = bufferLength;
0866:
0867: return this ;
0868: }
0869: }
0870:
0871: /**
0872: * Append a Java buffer to the value.
0873: */
0874: // @Override
0875: public final StringValue append(StringBuilderValue sb, int head,
0876: int tail) {
0877: int length = tail - head;
0878:
0879: if (_buffer.length < _length + length)
0880: ensureCapacity(_length + length);
0881:
0882: System.arraycopy(sb._buffer, head, _buffer, _length, tail
0883: - head);
0884:
0885: _length += tail - head;
0886:
0887: return this ;
0888: }
0889:
0890: /**
0891: * Append a Java value to the value.
0892: */
0893: @Override
0894: public final StringValue append(Value v) {
0895: /*
0896: if (v.length() == 0)
0897: return this;
0898: else {
0899: // php/033a
0900: v.appendTo(this);
0901:
0902: return this;
0903: }
0904: */
0905:
0906: v.appendTo(this );
0907:
0908: return this ;
0909: }
0910:
0911: /**
0912: * Returns the first index of the match string, starting from the head.
0913: */
0914: @Override
0915: public int indexOf(CharSequence match, int head) {
0916: int length = length();
0917: int matchLength = match.length();
0918:
0919: if (matchLength <= 0)
0920: return -1;
0921: else if (head < 0)
0922: return -1;
0923:
0924: int end = length - matchLength;
0925: char first = match.charAt(0);
0926:
0927: loop: for (; head <= end; head++) {
0928: if (_buffer[head] != first)
0929: continue;
0930:
0931: for (int i = 1; i < matchLength; i++) {
0932: if (_buffer[head + i] != match.charAt(i))
0933: continue loop;
0934: }
0935:
0936: return head;
0937: }
0938:
0939: return -1;
0940: }
0941:
0942: /**
0943: * Append a Java value to the value.
0944: */
0945: @Override
0946: public StringValue appendUnicode(Value v) {
0947: v.appendTo(this );
0948:
0949: return this ;
0950: }
0951:
0952: /**
0953: * Append a Java value to the value.
0954: */
0955: @Override
0956: public StringValue appendUnicode(Value v1, Value v2) {
0957: v1.appendTo(this );
0958: v2.appendTo(this );
0959:
0960: return this ;
0961: }
0962:
0963: /**
0964: * Append a buffer to the value.
0965: */
0966: public StringValue append(byte[] buf, int offset, int length) {
0967: if (_buffer.length < _length + length)
0968: ensureCapacity(_length + length);
0969:
0970: char[] charBuffer = _buffer;
0971: int charLength = _length;
0972:
0973: for (int i = length - 1; i >= 0; i--) {
0974: charBuffer[charLength + i] = (char) (buf[offset + i] & 0xff);
0975: }
0976:
0977: _length += length;
0978:
0979: return this ;
0980: }
0981:
0982: /**
0983: * Append a double to the value.
0984: */
0985: public final StringValue append(byte[] buf) {
0986: return append(buf, 0, buf.length);
0987: }
0988:
0989: /**
0990: * Append a Java byte to the value without conversions.
0991: */
0992: @Override
0993: public final StringValue appendByte(int v) {
0994: int length = _length + 1;
0995:
0996: if (_buffer.length < length)
0997: ensureCapacity(length);
0998:
0999: _buffer[_length++] = (char) v;
1000:
1001: return this ;
1002: }
1003:
1004: /**
1005: * Append a Java boolean to the value.
1006: */
1007: @Override
1008: public final StringValue append(boolean v) {
1009: return append(v ? "true" : "false");
1010: }
1011:
1012: /**
1013: * Append a Java long to the value.
1014: */
1015: @Override
1016: public StringValue append(long v) {
1017: // XXX: this probably is frequent enough to special-case
1018:
1019: return append(String.valueOf(v));
1020: }
1021:
1022: /**
1023: * Append a Java double to the value.
1024: */
1025: @Override
1026: public StringValue append(double v) {
1027: return append(String.valueOf(v));
1028: }
1029:
1030: /**
1031: * Append a bytes to the value.
1032: */
1033: @Override
1034: public StringValue appendBytes(String s) {
1035: int sublen = s.length();
1036:
1037: if (_buffer.length < _length + sublen)
1038: ensureCapacity(_length + sublen);
1039:
1040: for (int i = 0; i < sublen; i++) {
1041: _buffer[_length++] = s.charAt(i);
1042: }
1043:
1044: return this ;
1045: }
1046:
1047: @Override
1048: public StringValue append(Reader reader, long length)
1049: throws IOException {
1050: // php/4407 - oracle clob callback passes very long length
1051:
1052: int sublen = Math.min(8192, (int) length);
1053:
1054: try {
1055: while (length > 0) {
1056: ensureAppendCapacity(sublen);
1057:
1058: int count = reader.read(_buffer, _length, sublen);
1059:
1060: if (count <= 0)
1061: break;
1062:
1063: length -= count;
1064: _length += count;
1065: }
1066:
1067: } catch (IOException e) {
1068: throw new QuercusModuleException(e);
1069: }
1070:
1071: return this ;
1072: }
1073:
1074: /**
1075: * Returns the buffer.
1076: */
1077: public char[] getBuffer() {
1078: return _buffer;
1079: }
1080:
1081: /**
1082: * Returns the offset.
1083: */
1084: public int getOffset() {
1085: return _length;
1086: }
1087:
1088: /**
1089: * Sets the offset.
1090: */
1091: public void setOffset(int offset) {
1092: _length = offset;
1093: }
1094:
1095: /**
1096: * Returns the current capacity.
1097: */
1098: public int getLength() {
1099: return _buffer.length;
1100: }
1101:
1102: //
1103: // Java generator code
1104: //
1105:
1106: /**
1107: * Prints the value.
1108: * @param env
1109: */
1110: public void print(Env env) {
1111: env.print(_buffer, 0, _length);
1112: }
1113:
1114: /**
1115: * Prints the value.
1116: * @param env
1117: */
1118: public void print(Env env, WriteStream out) {
1119: try {
1120: out.print(_buffer, 0, _length);
1121: } catch (IOException e) {
1122: throw new QuercusModuleException(e);
1123: }
1124: }
1125:
1126: /**
1127: * Serializes the value.
1128: */
1129: public void serialize(StringBuilder sb) {
1130: sb.append("s:");
1131: sb.append(_length);
1132: sb.append(":\"");
1133: sb.append(toString());
1134: sb.append("\";");
1135: }
1136:
1137: @Override
1138: public String toDebugString() {
1139: StringBuilder sb = new StringBuilder();
1140:
1141: int length = length();
1142:
1143: sb.append("binary(");
1144: sb.append(length);
1145: sb.append(") \"");
1146:
1147: int appendLength = length > 256 ? 256 : length;
1148:
1149: for (int i = 0; i < appendLength; i++)
1150: sb.append(charAt(i));
1151:
1152: if (length > 256)
1153: sb.append(" ...");
1154:
1155: sb.append('"');
1156:
1157: return sb.toString();
1158: }
1159:
1160: @Override
1161: public void varDumpImpl(Env env, WriteStream out, int depth,
1162: IdentityHashMap<Value, String> valueSet) throws IOException {
1163: int length = length();
1164:
1165: if (length < 0)
1166: length = 0;
1167:
1168: out.print("string(");
1169: out.print(length);
1170: out.print(") \"");
1171:
1172: for (int i = 0; i < length; i++) {
1173: int ch = charAt(i);
1174:
1175: out.print((char) ch);
1176: }
1177:
1178: out.print("\"");
1179: }
1180:
1181: /**
1182: * Returns an OutputStream.
1183: */
1184: public OutputStream getOutputStream() {
1185: return new BuilderOutputStream();
1186: }
1187:
1188: public void ensureAppendCapacity(int newCapacity) {
1189: ensureCapacity(_length + newCapacity);
1190: }
1191:
1192: private void ensureCapacity(int newCapacity) {
1193: if (newCapacity <= _buffer.length)
1194: return;
1195: else if (newCapacity < 4096)
1196: newCapacity = 4 * newCapacity;
1197: else
1198: newCapacity = newCapacity + 4096;
1199:
1200: assert newCapacity > _buffer.length : "cannot set new capacity to "
1201: + newCapacity;
1202:
1203: char[] buffer = new char[newCapacity];
1204: System.arraycopy(_buffer, 0, buffer, 0, _length);
1205:
1206: _buffer = buffer;
1207: }
1208:
1209: /**
1210: * Returns the hash code.
1211: */
1212: @Override
1213: public int hashCode() {
1214: int hash = _hashCode;
1215:
1216: if (hash != 0)
1217: return hash;
1218:
1219: hash = 37;
1220:
1221: int length = _length;
1222:
1223: char[] buffer = _buffer;
1224: for (int i = length - 1; i >= 0; i--) {
1225: hash = 65521 * hash + buffer[i];
1226: }
1227:
1228: _hashCode = hash;
1229:
1230: return hash;
1231: }
1232:
1233: /**
1234: * Returns true for equality
1235: */
1236: @Override
1237: public boolean eq(Value rValue) {
1238: ValueType typeB = rValue.getValueType();
1239:
1240: if (typeB.isNumber()) {
1241: double l = toDouble();
1242: double r = rValue.toDouble();
1243:
1244: return l == r;
1245: } else if (typeB.isBoolean()) {
1246: return toBoolean() == rValue.toBoolean();
1247: }
1248:
1249: ValueType typeA = getValueType();
1250: if (typeA.isNumberCmp() && typeB.isNumberCmp()) {
1251: double l = toDouble();
1252: double r = rValue.toDouble();
1253:
1254: return l == r;
1255: }
1256:
1257: rValue = rValue.toValue();
1258:
1259: if (rValue instanceof StringBuilderValue) {
1260: StringBuilderValue value = (StringBuilderValue) rValue;
1261:
1262: int length = _length;
1263:
1264: if (length != value._length)
1265: return false;
1266:
1267: char[] bufferA = _buffer;
1268: char[] bufferB = value._buffer;
1269:
1270: for (int i = length - 1; i >= 0; i--) {
1271: if (bufferA[i] != bufferB[i])
1272: return false;
1273: }
1274:
1275: return true;
1276: } else {
1277: return toString().equals(rValue.toString());
1278: }
1279: }
1280:
1281: @Override
1282: public boolean equals(Object o) {
1283: if (o instanceof StringBuilderValue) {
1284: StringBuilderValue value = (StringBuilderValue) o;
1285:
1286: int length = _length;
1287:
1288: if (length != value._length)
1289: return false;
1290:
1291: char[] bufferA = _buffer;
1292: char[] bufferB = value._buffer;
1293:
1294: for (int i = length - 1; i >= 0; i--) {
1295: if (bufferA[i] != bufferB[i])
1296: return false;
1297: }
1298:
1299: return true;
1300: }
1301: /*
1302: else if (o instanceof UnicodeValue) {
1303: UnicodeValue value = (UnicodeValue)o;
1304:
1305: return value.equals(this);
1306: }
1307: */
1308: else
1309: return false;
1310: }
1311:
1312: @Override
1313: public boolean eql(Value o) {
1314: o = o.toValue();
1315:
1316: if (o instanceof StringBuilderValue) {
1317: StringBuilderValue value = (StringBuilderValue) o;
1318:
1319: int length = _length;
1320:
1321: if (length != value._length)
1322: return false;
1323:
1324: char[] bufferA = _buffer;
1325: char[] bufferB = value._buffer;
1326:
1327: for (int i = length - 1; i >= 0; i--) {
1328: if (bufferA[i] != bufferB[i])
1329: return false;
1330: }
1331:
1332: return true;
1333: } else
1334: return false;
1335: }
1336:
1337: //
1338: // Java generator code
1339: //
1340:
1341: /**
1342: * Generates code to recreate the expression.
1343: *
1344: * @param out the writer to the Java source code.
1345: */
1346: @Override
1347: public void generate(PrintWriter out) throws IOException {
1348: out.print("new StringBuilderValue(\"");
1349: printJavaString(out, this );
1350: out.print("\")");
1351: }
1352:
1353: //
1354: // Java serialization code
1355: //
1356:
1357: private void writeObject(ObjectOutputStream out) throws IOException {
1358: out.writeInt(_length);
1359:
1360: for (int i = 0; i < _length; i++)
1361: out.write(_buffer[i]);
1362: }
1363:
1364: private void readObject(ObjectInputStream in)
1365: throws ClassNotFoundException, IOException {
1366: _length = in.readInt();
1367: _buffer = new char[_length];
1368:
1369: for (int i = 0; i < _length; i++)
1370: _buffer[i] = (char) in.read();
1371: }
1372:
1373: class BinaryInputStream extends InputStream {
1374: private int _offset;
1375:
1376: /**
1377: * Reads the next byte.
1378: */
1379: @Override
1380: public int read() {
1381: if (_offset < _length)
1382: return _buffer[_offset++];
1383: else
1384: return -1;
1385: }
1386:
1387: /**
1388: * Reads into a buffer.
1389: */
1390: @Override
1391: public int read(byte[] buffer, int offset, int length) {
1392: int sublen = _length - _offset;
1393:
1394: if (length < sublen)
1395: sublen = length;
1396:
1397: if (sublen <= 0)
1398: return -1;
1399:
1400: System.arraycopy(_buffer, _offset, buffer, offset, sublen);
1401:
1402: _offset += sublen;
1403:
1404: return sublen;
1405: }
1406: }
1407:
1408: class BuilderInputStream extends InputStream {
1409: private int _index;
1410:
1411: /**
1412: * Reads the next byte.
1413: */
1414: @Override
1415: public int read() {
1416: if (_index < _length)
1417: return _buffer[_index++] & 0xff;
1418: else
1419: return -1;
1420: }
1421:
1422: /**
1423: * Reads into a buffer.
1424: */
1425: @Override
1426: public int read(byte[] buffer, int offset, int length) {
1427: int sublen = _length - _index;
1428:
1429: if (length < sublen)
1430: sublen = length;
1431:
1432: if (sublen <= 0)
1433: return -1;
1434:
1435: for (int i = 0; i < sublen; i++)
1436: buffer[offset + i] = (byte) _buffer[_index + i];
1437:
1438: _index += sublen;
1439:
1440: return sublen;
1441: }
1442: }
1443:
1444: class BuilderOutputStream extends OutputStream {
1445: /**
1446: * Writes the next byte.
1447: */
1448: @Override
1449: public void write(int ch) {
1450: append(ch);
1451: }
1452:
1453: /**
1454: * Reads into a buffer.
1455: */
1456: @Override
1457: public void write(byte[] buffer, int offset, int length) {
1458: append(buffer, offset, length);
1459: }
1460: }
1461:
1462: static {
1463: CHAR_STRINGS = new StringBuilderValue[256];
1464:
1465: for (int i = 0; i < CHAR_STRINGS.length; i++)
1466: CHAR_STRINGS[i] = new StringBuilderValue((char) i);
1467: }
1468: }
|