KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > caucho > quercus > env > StringValue


1 /*
2  * Copyright (c) 1998-2006 Caucho Technology -- all rights reserved
3  *
4  * This file is part of Resin(R) Open Source
5  *
6  * Each copy or derived work must preserve the copyright notice and this
7  * notice unmodified.
8  *
9  * Resin Open Source is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * Resin Open Source is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
17  * of NON-INFRINGEMENT. See the GNU General Public License for more
18  * details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with Resin Open Source; if not, write to the
22  *
23  * Free Software Foundation, Inc.
24  * 59 Temple Place, Suite 330
25  * Boston, MA 02111-1307 USA
26  *
27  * @author Scott Ferguson
28  */

29
30 package com.caucho.quercus.env;
31
32 import com.caucho.quercus.Quercus;
33 import com.caucho.quercus.QuercusModuleException;
34 import com.caucho.vfs.TempBuffer;
35 import com.caucho.vfs.TempCharBuffer;
36 import com.caucho.vfs.TempStream;
37 import com.caucho.vfs.WriteStream;
38
39 import java.io.ByteArrayInputStream JavaDoc;
40 import java.io.IOException JavaDoc;
41 import java.io.InputStream JavaDoc;
42 import java.io.InputStreamReader JavaDoc;
43 import java.io.Reader JavaDoc;
44 import java.io.UnsupportedEncodingException JavaDoc;
45 import java.util.IdentityHashMap JavaDoc;
46
47 /**
48  * Represents a Quercus string value.
49  */

50 abstract public class StringValue extends Value implements CharSequence JavaDoc {
51   public static final StringValue EMPTY = new StringValueImpl("");
52
53   private final static StringValue []CHAR_STRINGS;
54
55   protected static final int IS_STRING = 0;
56   protected static final int IS_LONG = 1;
57   protected static final int IS_DOUBLE = 2;
58
59   /**
60    * Creates the string.
61    */

62   public static Value create(String JavaDoc value)
63   {
64     if (value == null)
65       return NullValue.NULL;
66     else
67       return new StringValueImpl(value);
68   }
69
70   /**
71    * Creates the string.
72    */

73   public static StringValue create(char value)
74   {
75     if (value < CHAR_STRINGS.length)
76       return CHAR_STRINGS[value];
77     else
78       return new StringValueImpl(String.valueOf(value));
79   }
80
81   /**
82    * Creates the string.
83    */

84   public static Value create(Object JavaDoc value)
85   {
86     if (value == null)
87       return NullValue.NULL;
88     else
89       return new StringValueImpl(value.toString());
90   }
91
92   //
93
// Predicates and relations
94
//
95

96   /**
97    * Returns the type.
98    */

99   public String JavaDoc getType()
100   {
101     return "string";
102   }
103
104   /**
105    * Returns true for a long
106    */

107   public boolean isLongConvertible()
108   {
109     int len = length();
110
111     if (len == 0)
112       return true;
113
114     int i = 0;
115     char ch = charAt(0);
116
117     if (ch == '-' || ch == '+')
118       i++;
119
120     for (; i < len; i++) {
121       ch = charAt(i);
122
123       if (! ('0' <= ch && ch <= '9'))
124         return false;
125     }
126
127     return true;
128   }
129
130   /**
131    * Returns true for a double
132    */

133   public boolean isDoubleConvertible()
134   {
135     return getNumericType() == IS_DOUBLE;
136   }
137
138   /**
139    * Returns true for a number
140    */

141   public boolean isNumber()
142   {
143     return getNumericType() != IS_STRING;
144   }
145
146   /**
147    * Returns true for is_numeric
148    */

149   @Override JavaDoc
150   public boolean isNumeric()
151   {
152     // php/120y
153

154     return getNumericType() != IS_STRING;
155   }
156
157   /**
158    * Returns true for a scalar
159    */

160   public boolean isScalar()
161   {
162     return true;
163   }
164
165   /**
166    * Returns true for StringValue
167    */

168   @Override JavaDoc
169   public boolean isString()
170   {
171     return true;
172   }
173
174   /**
175    * Returns true for equality
176    */

177   public boolean eq(Value rValue)
178   {
179     rValue = rValue.toValue();
180
181     if (rValue instanceof BooleanValue) {
182       return toBoolean() == rValue.toBoolean();
183     }
184
185     int type = getNumericType();
186
187     if (type == IS_STRING) {
188       if (rValue instanceof StringValue)
189         return equals(rValue);
190       else if (rValue.isLongConvertible())
191         return toLong() == rValue.toLong();
192       else if (rValue instanceof BooleanValue)
193         return toLong() == rValue.toLong();
194       else
195         return equals(rValue.toStringValue());
196     }
197     else if (rValue.isNumberConvertible())
198       return toDouble() == rValue.toDouble();
199     else
200       return equals(rValue.toStringValue());
201   }
202
203   /**
204    * Returns true for equality
205    */

206   public int cmp(Value rValue)
207   {
208     if (isNumberConvertible() || rValue.isNumberConvertible()) {
209       double l = toDouble();
210       double r = rValue.toDouble();
211
212       if (l == r)
213     return 0;
214       else if (l < r)
215     return -1;
216       else
217     return 1;
218     }
219     else
220       return toString().compareTo(rValue.toString());
221   }
222
223   /**
224    * Returns true for equality
225    */

226   public boolean eql(Value rValue)
227   {
228     rValue = rValue.toValue();
229
230     if (! (rValue instanceof StringValue))
231       return false;
232
233     String JavaDoc rString = rValue.toString();
234
235     return toString().equals(rString);
236   }
237
238   /**
239    * Compare two strings
240    */

241   public int cmpString(StringValue rValue)
242   {
243     if (isNumberConvertible() && rValue.isNumberConvertible()) {
244       
245       double thisDouble = toDouble();
246       
247       double rDouble = rValue.toDouble();
248       
249       if (thisDouble < rDouble)
250     return -1;
251       else if (thisDouble > rDouble)
252     return 1;
253       else
254     return 0;
255     }
256     return toString().compareTo(rValue.toString());
257   }
258
259   /**
260    * Returns a code for the numeric type of the string
261    */

262   protected int getNumericType()
263   {
264     int len = length();
265
266     if (len == 0)
267       return IS_STRING;
268
269     int i = 0;
270     int ch = 0;
271     boolean hasPoint = false;
272
273     if (i < len && ((ch = charAt(i)) == '+' || ch == '-')) {
274       i++;
275     }
276
277     if (len <= i)
278       return IS_STRING;
279
280     ch = charAt(i);
281
282     if (ch == '.') {
283       for (i++; i < len && '0' <= (ch = charAt(i)) && ch <= '9'; i++) {
284         return IS_DOUBLE;
285       }
286
287       return IS_STRING;
288     }
289     else if (! ('0' <= ch && ch <= '9'))
290       return IS_STRING;
291
292     for (; i < len && '0' <= (ch = charAt(i)) && ch <= '9'; i++) {
293     }
294
295     if (len <= i)
296       return IS_LONG;
297     else if (ch == '.' || ch == 'e' || ch == 'E') {
298       for (i++;
299            i < len && ('0' <= (ch = charAt(i)) && ch <= '9' ||
300                        ch == '+' || ch == '-' || ch == 'e' || ch == 'E');
301            i++) {
302       }
303
304       if (i < len)
305         return IS_STRING;
306       else
307         return IS_DOUBLE;
308     }
309     else
310       return IS_STRING;
311   }
312
313   // Conversions
314

315   /**
316    * Converts to a string value.
317    */

318   public StringValue toStringValue()
319   {
320     return this;
321   }
322
323   /**
324    * Converts to a long.
325    */

326   public static long toLong(String JavaDoc string)
327   {
328     if (string.equals(""))
329       return 0;
330
331     int len = string.length();
332
333     long value = 0;
334     long sign = 1;
335
336     int i = 0;
337     char ch = string.charAt(0);
338
339     if (ch == '-') {
340       sign = -1;
341       i = 1;
342     }
343     else if (ch == '+')
344       i = 1;
345
346     for (; i < len; i++) {
347       ch = string.charAt(i);
348
349       if ('0' <= ch && ch <= '9')
350         value = 10 * value + ch - '0';
351       else
352         return sign * value;
353     }
354
355     return value;
356   }
357
358   /**
359    * Converts to a double.
360    */

361   public double toDouble()
362   {
363     int len = length();
364     int i = 0;
365     int ch = 0;
366
367     if (i < len && ((ch = charAt(i)) == '+' || ch == '-')) {
368       i++;
369     }
370
371     for (; i < len && '0' <= (ch = charAt(i)) && ch <= '9'; i++) {
372     }
373
374     if (ch == '.') {
375       for (i++; i < len && '0' <= (ch = charAt(i)) && ch <= '9'; i++) {
376       }
377     }
378
379     if (ch == 'e' || ch == 'E') {
380       int e = i++;
381
382       if (i < len && (ch = charAt(i)) == '+' || ch == '-') {
383         i++;
384       }
385
386       for (; i < len && '0' <= (ch = charAt(i)) && ch <= '9'; i++) {
387       }
388
389       if (i == e + 1)
390         i = e;
391     }
392
393     if (i == 0)
394       return 0;
395     else if (i == len)
396       return Double.parseDouble(toString());
397     else
398       return Double.parseDouble(substring(0, i).toString());
399   }
400
401   /**
402    * Converts to a boolean.
403    */

404   public boolean toBoolean()
405   {
406     int length = length();
407
408     if (length == 0)
409       return false;
410     else if (length > 1)
411       return true;
412     else
413       return charAt(0) != '0';
414   }
415
416   /**
417    * Converts to a key.
418    */

419   public Value toKey()
420   {
421     int len = length();
422
423     if (len == 0)
424       return this;
425
426     int sign = 1;
427     long value = 0;
428
429     int i = 0;
430     char ch = charAt(i);
431     if (ch == '-') {
432       sign = -1;
433       i++;
434     }
435
436     for (; i < len; i++) {
437       ch = charAt(i);
438
439       if ('0' <= ch && ch <= '9')
440         value = 10 * value + ch - '0';
441       else
442         return this;
443     }
444
445     return LongValue.create(sign * value);
446   }
447
448   /**
449    * Converts to a Java object.
450    */

451   public Object JavaDoc toJavaObject()
452   {
453     return toString();
454   }
455
456   /**
457    * Takes the values of this array, unmarshalls them to objects of type
458    * <i>elementType</i>, and puts them in a java array.
459    */

460   @Override JavaDoc
461   public Object JavaDoc valuesToArray(Env env, Class JavaDoc elementType)
462   {
463     if (char.class.equals(elementType)) {
464       return toUnicodeValue(env).toCharArray();
465     }
466     else if (Character JavaDoc.class.equals(elementType)) {
467       char[] chars = toUnicodeValue(env).toCharArray();
468       
469       int length = chars.length;
470       
471       Character JavaDoc[] charObjects = new Character JavaDoc[length];
472       
473       for (int i = 0; i <length; i++) {
474         charObjects[i] = Character.valueOf(chars[i]);
475       }
476       
477       return charObjects;
478     }
479     else if (byte.class.equals(elementType)) {
480       return toBinaryValue(env).toBytes();
481     }
482     else if (Byte JavaDoc.class.equals(elementType)) {
483       byte[] bytes = toBinaryValue(env).toBytes();
484       
485       int length = bytes.length;
486       
487       Byte JavaDoc[] byteObjects = new Byte JavaDoc[length];
488       
489       for (int i = 0; i <length; i++) {
490         byteObjects[i] = Byte.valueOf(bytes[i]);
491       }
492       
493       return byteObjects;
494     }
495     else {
496       env.error(L.l("Can't assign {0} with type {1} to {2}", this, this.getClass(), elementType));
497       return null;
498     }
499   }
500   
501   /**
502    * Converts to an array if null.
503    */

504   public Value toAutoArray()
505   {
506     if (length() == 0)
507       return new ArrayValueImpl();
508     else
509       return this;
510   }
511
512   // Operations
513

514   /**
515    * Returns the character at an index
516    */

517   public Value get(Value key)
518   {
519     return charValueAt(key.toLong());
520   }
521
522   /**
523    * Returns the character at an index
524    */

525   public Value getArg(Value key)
526   {
527     // php/03ma
528
return charValueAt(key.toLong());
529   }
530
531   /**
532    * Returns the character at an index
533    */

534   public Value getRef(Value key)
535   {
536     return charValueAt(key.toLong());
537   }
538
539   /**
540    * Returns the character at an index
541    */

542   @Override JavaDoc
543   public Value charValueAt(long index)
544   {
545     int len = length();
546
547     if (index < 0 || len <= index)
548       return StringValue.EMPTY;
549     else {
550       return StringValue.create(charAt((int) index));
551     }
552   }
553
554   /**
555    * sets the character at an index
556    */

557   @Override JavaDoc
558   public Value setCharValueAt(long index, String JavaDoc value)
559   {
560     int len = length();
561
562     if (index < 0 || len <= index)
563       return this;
564     else {
565       return (new StringBuilderValue()
566           .append(this, 0, (int) index)
567           .append(value)
568           .append(this, (int) (index + 1), length()));
569     }
570   }
571
572   /**
573    * Pre-increment the following value.
574    */

575   public Value preincr(int incr)
576   {
577     return postincr(incr);
578   }
579
580   /**
581    * Post-increment the following value.
582    */

583   public Value postincr(int incr)
584   {
585     // php/03i6
586
if (length() == 0)
587       return LongValue.create(incr);
588
589     if (incr > 0) {
590       StringBuilder JavaDoc tail = new StringBuilder JavaDoc();
591
592       for (int i = length() - 1; i >= 0; i--) {
593         char ch = charAt(i);
594
595         if (ch == 'z') {
596           if (i == 0)
597             return new StringBuilderValue().append("aa").append(tail);
598           else
599             tail.insert(0, 'a');
600         }
601         else if ('a' <= ch && ch < 'z') {
602           return (new StringBuilderValue()
603           .append(this, 0, i)
604           .append((char) (ch + 1))
605           .append(tail));
606         }
607         else if (ch == 'Z') {
608           if (i == 0)
609             return new StringBuilderValue().append("AA").append(tail);
610           else
611             tail.insert(0, 'A');
612         }
613         else if ('A' <= ch && ch < 'Z') {
614           return (new StringBuilderValue()
615           .append(this, 0, i)
616           .append((char) (ch + 1))
617           .append(tail));
618         }
619         else if ('0' <= ch && ch <= '9' && i == length() - 1) {
620           return LongValue.create(toLong() + 1);
621         }
622       }
623
624       return new StringBuilderValue(tail.toString());
625     }
626     else if (isLongConvertible()) {
627       return LongValue.create(toLong() - 1);
628     }
629     else {
630       return this;
631     }
632   }
633
634   /**
635    * Adds to the following value.
636    */

637   public Value add(long rValue)
638   {
639     if (isLongConvertible())
640       return LongValue.create(toLong() + rValue);
641     
642     return DoubleValue.create(toDouble() + rValue);
643   }
644
645   /**
646    * Serializes the value.
647    */

648   @Override JavaDoc
649   public void serialize(StringBuilder JavaDoc sb)
650   {
651     sb.append("s:");
652     sb.append(length());
653     sb.append(":\"");
654     sb.append(toString());
655     sb.append("\";");
656   }
657
658   //
659
// append code
660
//
661

662   /**
663    * Append a Java string to the value.
664    */

665   public StringValue append(String JavaDoc s)
666   {
667     throw new UnsupportedOperationException JavaDoc(getClass().getName());
668   }
669
670   /**
671    * Append a Java string to the value.
672    */

673   public StringValue append(String JavaDoc s, int start, int end)
674   {
675     throw new UnsupportedOperationException JavaDoc(getClass().getName());
676   }
677
678   /**
679    * Append a Java buffer to the value.
680    */

681   public StringValue append(char []buf, int offset, int length)
682   {
683     throw new UnsupportedOperationException JavaDoc(getClass().getName());
684   }
685
686   /**
687    * Append a Java double to the value.
688    */

689   public final StringValue append(char []buf)
690   {
691     return append(buf, 0, buf.length);
692   }
693
694   /**
695    * Append a Java buffer to the value.
696    */

697   public StringValue append(CharSequence JavaDoc buf, int head, int tail)
698   {
699     throw new UnsupportedOperationException JavaDoc(getClass().getName());
700   }
701
702   /**
703    * Append a Java buffer to the value.
704    */

705   public StringValue append(StringBuilderValue sb, int head, int tail)
706   {
707     throw new UnsupportedOperationException JavaDoc(getClass().getName());
708   }
709
710   /**
711    * Append a Java char to the value.
712    */

713   public StringValue append(char v)
714   {
715     throw new UnsupportedOperationException JavaDoc(getClass().getName());
716   }
717
718   /**
719    * Append a Java long to the value.
720    */

721   public StringValue append(byte v)
722   {
723     throw new UnsupportedOperationException JavaDoc(getClass().getName());
724   }
725
726   /**
727    * Append a Java boolean to the value.
728    */

729   public StringValue append(boolean v)
730   {
731     return append(v ? "true" : "false");
732   }
733
734   /**
735    * Append a Java long to the value.
736    */

737   public StringValue append(long v)
738   {
739     return append(String.valueOf(v));
740   }
741
742   /**
743    * Append a Java double to the value.
744    */

745   public StringValue append(double v)
746   {
747     return append(String.valueOf(v));
748   }
749
750   /**
751    * Append a Java value to the value.
752    */

753   public StringValue append(Object JavaDoc v)
754   {
755     return append(String.valueOf(v));
756   }
757
758   /**
759    * Append a Java value to the value.
760    */

761   public StringValue append(Value v)
762   {
763     throw new UnsupportedOperationException JavaDoc(getClass().getName());
764   }
765   
766   /**
767    * Append to a string builder.
768    */

769   @Override JavaDoc
770   public void appendTo(StringBuilderValue sb)
771   {
772     int length = length();
773
774     for (int i = 0; i < length; i++)
775       sb.append(charAt(i));
776   }
777
778   /**
779    * Exports the value.
780    */

781   @Override JavaDoc
782   public void varExport(StringBuilder JavaDoc sb)
783   {
784     sb.append("'");
785
786     String JavaDoc value = toString();
787     int len = value.length();
788     for (int i = 0; i < len; i++) {
789       char ch = value.charAt(i);
790
791       switch (ch) {
792       case '\'':
793         sb.append("\\'");
794         break;
795       case '\\':
796         sb.append("\\\\");
797         break;
798       default:
799         sb.append(ch);
800       }
801     }
802     sb.append("'");
803   }
804
805   /**
806    * Interns the string.
807    */

808   public InternStringValue intern(Quercus quercus)
809   {
810     return quercus.intern(toString());
811   }
812
813   //
814
// CharSequence
815
//
816

817   /**
818    * Returns the length of the string.
819    */

820   public int length()
821   {
822     return toString().length();
823   }
824
825   /**
826    * Returns the character at a particular location
827    */

828   public char charAt(int index)
829   {
830     return toString().charAt(index);
831   }
832
833   /**
834    * Returns a subsequence
835    */

836   public CharSequence JavaDoc subSequence(int start, int end)
837   {
838     return new StringValueImpl(toString().substring(start, end));
839   }
840
841   //
842
// java.lang.String methods
843
//
844

845   /**
846    * Returns the first index of the match string, starting from the head.
847    */

848   public final int indexOf(CharSequence JavaDoc match)
849   {
850     return indexOf(match, 0);
851   }
852     
853   /**
854    * Returns the first index of the match string, starting from the head.
855    */

856   public int indexOf(CharSequence JavaDoc match, int head)
857   {
858     int length = length();
859     int matchLength = match.length();
860
861     if (matchLength <= 0)
862       return -1;
863     else if (head < 0)
864       return -1;
865     
866     int end = length - matchLength;
867     char first = match.charAt(0);
868
869     loop:
870     for (; head <= end; head++) {
871       if (charAt(head) != first)
872     continue;
873
874       for (int i = 1; i < matchLength; i++) {
875     if (charAt(head + i) != match.charAt(i))
876       continue loop;
877       }
878
879       return head;
880     }
881
882     return -1;
883   }
884     
885   /**
886    * Returns the last index of the match string, starting from the head.
887    */

888   public int indexOf(char match)
889   {
890     return lastIndexOf(match, 0);
891   }
892     
893   /**
894    * Returns the last index of the match string, starting from the head.
895    */

896   public int indexOf(char match, int head)
897   {
898     int length = length();
899     
900     for (; head < length; head++) {
901       if (charAt(head) == match)
902     return head;
903     }
904
905     return -1;
906   }
907     
908   /**
909    * Returns the last index of the match string, starting from the head.
910    */

911   public final int lastIndexOf(char match)
912   {
913     return lastIndexOf(match, Integer.MAX_VALUE);
914   }
915     
916   /**
917    * Returns the last index of the match string, starting from the head.
918    */

919   public int lastIndexOf(char match, int tail)
920   {
921     int length = length();
922
923     if (tail >= length)
924       tail = length - 1;
925     
926     for (; tail >= 0; tail--) {
927       if (charAt(tail) == match)
928     return tail;
929     }
930
931     return -1;
932   }
933
934   /**
935    * Returns the last index of the match string, starting from the tail.
936    */

937   public int lastIndexOf(CharSequence JavaDoc match)
938   {
939     return lastIndexOf(match, Integer.MAX_VALUE);
940   }
941
942   /**
943    * Returns the last index of the match string, starting from the tail.
944    */

945   public int lastIndexOf(CharSequence JavaDoc match, int tail)
946   {
947     int length = length();
948     int matchLength = match.length();
949
950     if (matchLength <= 0)
951       return -1;
952     if (tail < 0)
953       return -1;
954
955     if (tail > length - matchLength)
956       tail = length - matchLength;
957
958     char first = match.charAt(0);
959
960     loop:
961     for (; tail >= 0; tail--) {
962       if (charAt(tail) != first)
963         continue;
964
965       for (int i = 1; i < matchLength; i++) {
966         if (charAt(tail + i) != match.charAt(i))
967           continue loop;
968       }
969
970       return tail;
971     }
972
973     return -1;
974   }
975
976   /**
977    * Returns a StringValue substring.
978    */

979   public StringValue substring(int head)
980   {
981     return (StringValue) subSequence(head, length());
982   }
983
984   /**
985    * Returns a StringValue substring.
986    */

987   public StringValue substring(int begin, int end)
988   {
989     return (StringValue) subSequence(begin, end);
990   }
991
992   /**
993    * Returns a character array
994    */

995   public char []toCharArray()
996   {
997     int length = length();
998     
999     char []array = new char[length()];
1000
1001    getChars(0, array, 0, length);
1002
1003    return array;
1004  }
1005
1006  /**
1007   * Copies the chars
1008   */

1009  public void getChars(int stringOffset, char []buffer, int offset, int length)
1010  {
1011    for (int i = 0; i < length; i++)
1012      buffer[offset + i] = charAt(stringOffset + i);
1013  }
1014
1015  /**
1016   * Convert to lower case.
1017   */

1018  public StringValue toLowerCase()
1019  {
1020    int length = length();
1021    
1022    StringBuilderValue string = new StringBuilderValue(length);
1023    
1024    char []buffer = string.getBuffer();
1025    getChars(0, buffer, 0, length);
1026
1027    for (int i = 0; i < length; i++) {
1028      char ch = buffer[i];
1029      
1030      if ('A' <= ch && ch <= 'Z')
1031    buffer[i] = (char) (ch + 'a' - 'A');
1032      else if (ch < 0x80) {
1033      }
1034      else if (Character.isUpperCase(ch))
1035    buffer[i] = Character.toLowerCase(ch);
1036    }
1037
1038    string.setLength(length);
1039
1040    return string;
1041  }
1042  
1043  /**
1044   * Convert to lower case.
1045   */

1046  public StringValue toUpperCase()
1047  {
1048    int length = length();
1049    
1050    StringBuilderValue string = new StringBuilderValue(length);
1051
1052    char []buffer = string.getBuffer();
1053    getChars(0, buffer, 0, length);
1054
1055    for (int i = 0; i < length; i++) {
1056      char ch = buffer[i];
1057      
1058      if ('a' <= ch && ch <= 'z')
1059        buffer[i] = (char) (ch + 'A' - 'a');
1060      else if (ch < 0x80) {
1061      }
1062      else if (Character.isLowerCase(ch))
1063        buffer[i] = Character.toUpperCase(ch);
1064    }
1065
1066    string.setLength(length);
1067
1068    return string;
1069  }
1070
1071  /**
1072   * Returns a byteArrayInputStream for the value.
1073   * See TempBufferStringValue for how this can be overriden
1074   *
1075   * @return InputStream
1076   */

1077  public InputStream JavaDoc toInputStream()
1078  {
1079    return new StringValueInputStream();
1080  }
1081
1082  /**
1083   * Returns a byte stream of chars.
1084   * @param charset to encode chars to
1085   */

1086  public InputStream JavaDoc toInputStream(String JavaDoc charset)
1087    throws UnsupportedEncodingException JavaDoc
1088  {
1089    return new ByteArrayInputStream JavaDoc(toString().getBytes(charset));
1090  }
1091
1092  /**
1093   * Returns a char stream.
1094   * XXX: when decoding fails
1095   *
1096   * @param charset to decode bytes by
1097   */

1098  public Reader JavaDoc toReader(String JavaDoc charset)
1099    throws UnsupportedEncodingException JavaDoc
1100  {
1101    return new InputStreamReader JavaDoc(
1102        new ByteArrayInputStream JavaDoc(toString().getBytes()), charset);
1103  }
1104
1105  /**
1106   * Converts to a BinaryValue in desired charset.
1107   *
1108   * @param env
1109   * @param charset
1110   */

1111  public BinaryValue toBinaryValue(Env env, String JavaDoc charset)
1112  {
1113    TempBuffer tb = TempBuffer.allocate();
1114    byte[] buffer = tb.getBuffer();
1115
1116    try {
1117      InputStream JavaDoc in = toInputStream(charset);
1118      TempStream out = new TempStream();
1119
1120      int sublen = in.read(buffer, 0, buffer.length);
1121
1122      while (sublen >= 0) {
1123        out.write(buffer, 0, sublen, false);
1124        sublen = in.read(buffer, 0, buffer.length);
1125      }
1126
1127      out.flush();
1128      return new TempBufferStringValue(out.getHead());
1129
1130    } catch (IOException JavaDoc e) {
1131      throw new QuercusModuleException(e.getMessage());
1132    } finally {
1133      TempBuffer.free(tb);
1134    }
1135  }
1136
1137  /**
1138   * Decodes from charset and returns UnicodeValue.
1139   *
1140   * @param env
1141   * @param charset
1142   */

1143  public UnicodeValue toUnicodeValue(Env env, String JavaDoc charset)
1144  {
1145    StringBuilderValue sb = new StringBuilderValue();
1146
1147    TempCharBuffer tb = TempCharBuffer.allocate();
1148    char[] charBuf = tb.getBuffer();
1149
1150    try {
1151      Reader JavaDoc in = toReader(charset);
1152
1153      int sublen;
1154      while ((sublen = in.read(charBuf, 0, charBuf.length)) >= 0) {
1155        sb.append(charBuf, 0, sublen);
1156      }
1157
1158    } catch (IOException JavaDoc e) {
1159      throw new QuercusModuleException(e.getMessage());
1160
1161    } finally {
1162      TempCharBuffer.free(tb);
1163    }
1164
1165    return sb;
1166  }
1167
1168  //
1169
// java.lang.Object methods
1170
//
1171

1172  /**
1173   * Returns the hash code.
1174   */

1175  public int hashCode()
1176  {
1177    int hash = 37;
1178
1179    int length = length();
1180
1181    for (int i = 0; i < length; i++) {
1182      hash = 65521 * hash + charAt(i);
1183    }
1184
1185    return hash;
1186  }
1187
1188  /**
1189   * Test for equality
1190   */

1191  public boolean equals(Object JavaDoc o)
1192  {
1193    if (this == o)
1194      return true;
1195    else if (! (o instanceof StringValue))
1196      return false;
1197
1198    StringValue s = (StringValue) o;
1199
1200    int aLength = length();
1201    int bLength = s.length();
1202
1203    if (aLength != bLength)
1204      return false;
1205
1206    for (int i = aLength - 1; i >= 0; i--) {
1207      if (charAt(i) != s.charAt(i))
1208    return false;
1209    }
1210
1211    return true;
1212  }
1213
1214  public void varDumpImpl(Env env,
1215                          WriteStream out,
1216                          int depth,
1217                          IdentityHashMap JavaDoc<Value, String JavaDoc> valueSet)
1218    throws IOException JavaDoc
1219  {
1220    String JavaDoc s = toString();
1221
1222    out.print("string(" + s.length() + ") \"" + s + "\"");
1223  }
1224
1225  class StringValueInputStream extends java.io.InputStream JavaDoc {
1226    private final int _length;
1227    private int _index;
1228
1229    StringValueInputStream()
1230    {
1231      _length = length();
1232    }
1233    
1234    /**
1235     * Reads the next byte.
1236     */

1237    public int read()
1238    {
1239      if (_index < _length)
1240    return charAt(_index++);
1241      else
1242    return -1;
1243    }
1244
1245    /**
1246     * Reads into a buffer.
1247     */

1248    public int read(byte []buffer, int offset, int length)
1249    {
1250      int sublen = _length - _index;
1251
1252      if (length < sublen)
1253    sublen = length;
1254
1255      if (sublen <= 0)
1256    return -1;
1257
1258      int index = _index;
1259
1260      for (int i = 0; i < sublen; i++)
1261    buffer[offset + i] = (byte) charAt(index + i);
1262
1263      _index += sublen;
1264
1265      return sublen;
1266    }
1267  }
1268
1269  static {
1270    CHAR_STRINGS = new StringValue[256];
1271
1272    for (int i = 0; i < CHAR_STRINGS.length; i++)
1273      CHAR_STRINGS[i] = new StringValueImpl(String.valueOf((char) i));
1274  }
1275}
1276
1277
Popular Tags