001 
002 /*
003  *  JScripter Simulation 1.0 - For Java To Script
004  *  Copyright (C) 2008-2011  J.J.Liu<jianjunliu@126.com> <http://www.jscripter.org>
005  *  
006  *  This program is free software: you can redistribute it and/or modify
007  *  it under the terms of the GNU Affero General Public License as published by
008  *  the Free Software Foundation, either version 3 of the License, or
009  *  (at your option) any later version.
010  *  
011  *  This program is distributed in the hope that it will be useful,
012  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
013  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
014  *  GNU Affero General Public License for more details.
015  *  
016  *  You should have received a copy of the GNU Affero General Public License
017  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
018  */
019 
020 package org.jscripter.sim;
021 
022 import java.io.IOException;
023 import java.io.InputStream;
024 import java.net.URLConnection;
025 import java.util.HashMap;
026 import java.util.Map;
027 import java.util.StringTokenizer;
028 
029 import js.Js;
030 import js.NumberLike;
031 
032 /**
033  * <p>A utility class with its static methods providing JS Simulation.</p>
034  * <p>This <b>internal</b> class is only used or extended internally in JS Simulation Library.</p>
035  *
036  * @author <a href="mailto:jianjunliu@126.com">J.J.Liu (Jianjun Liu)</a> at <a href="http://www.jscripter.org" target="_blank">http://www.jscripter.org</a>
037  * 
038  * @javascript Re-compilers must report error on resolving an <tt>internal</tt> class. 
039  */
040 public final class SimUtil
041 {
042     private SimUtil() {}
043 
044     private final static long LMAX =  9007199254740992L;
045     private final static long LMIN = -9007199254740992L;
046 
047     private final static long limit(long v) {
048         return v > LMAX ? LMAX : v < LMIN ? LMIN : v;
049     }
050 
051     private final static Map<Class<?>, Byte> tmap = new HashMap<Class<?>, Byte>();
052     private final static byte OTHER        = 0x00;
053     private final static byte CHARACTER    = 0x01;
054     private final static byte BYTE         = 0x03;
055     private final static byte SHORT        = 0x04;
056     private final static byte INTEGER      = 0x05;
057     private final static byte LONG         = 0x06;
058     private final static byte FLOAT        = 0x07;
059     private final static byte DOUBLE       = 0x08;
060 
061     static {
062         tmap.put(Character.class, CHARACTER);
063         tmap.put(Byte     .class, BYTE     );
064         tmap.put(Short    .class, SHORT    );
065         tmap.put(Integer  .class, INTEGER  );
066         tmap.put(Long     .class, LONG     );
067         tmap.put(Float    .class, FLOAT    );
068         tmap.put(Double   .class, DOUBLE   );
069     }
070 
071     private final static byte tid(Object o) {
072         if (o == null) return OTHER;
073         Byte tid = tmap.get(o.getClass());
074         return tid == null ? OTHER : tid;
075     }
076 
077     /**
078      * <p>Gets the number representation of the argument if it is numeric.</p>
079      * @param var Any variable
080      * @return the number representation of the argument.
081      * @since 1.0
082      * @javascript Re-compilers must report error on the invocation to an <b>internal</b> method. 
083      */
084     public final static Number getNumber(Object var) {
085         switch (tid(var))
086         {
087             case CHARACTER:
088                 return (short)((Character)var).charValue();
089             case BYTE:
090             case SHORT:
091             case INTEGER:
092             case LONG:
093             case FLOAT:
094             case DOUBLE:
095                 return (Number)var;
096             default:
097                 return getNumber(((NumberLike<?>)var).valueOf());
098         }
099     }
100 
101     /**
102      * <p>Performs unary negation, resembling the unary minus operator in JavaScript.</p>
103      * <p>This operation converts a positive value to an equivalently negative value, and 
104      * vice versa. If the operand is not a number, it attempts to convert it to one.</p>
105      * @param var Any numeric value.
106      * @return The negation of the numeric value.
107      * @since 1.0
108      * @javascript Re-compilers must report error on the invocation to an <b>internal</b> method. 
109      */
110     public final static Number neg(Object var) {
111         Number n = getNumber(var);
112         switch (tid(n))
113         {
114             case BYTE:
115                 return (byte )-((Byte   )n).byteValue  ();
116             case SHORT:
117                 return (short)-((Short  )n).shortValue ();
118             case INTEGER:
119                 return (int  )-((Integer)n).intValue   ();
120             case LONG:
121                 return (long )-((Long   )n).longValue  ();
122             case FLOAT:
123                 return (float)-((Float  )n).floatValue ();
124             default:
125                 return -((Double)n).doubleValue();
126         }
127     }
128 
129     /**
130      * <p>Adds numeric operands, resembling the addition operator in JavaScript.</p>
131      * <p>Object operands are converted to numbers. The conversion is performed by the 
132      * {@link Js#valueOf(Object)} operation on the object.</p>
133      * @param var Any numeric value.
134      * @param other Any numeric value.
135      * @return The sum of the two numeric values.
136      * @since 1.0
137      * @javascript Re-compilers must report error on the invocation to an <b>internal</b> method. 
138      */
139     public final static Number add(Number var, Number other) {
140         switch (tid(var))
141         {
142             case BYTE:
143                 return addByte((Byte)var, other);
144             case SHORT:
145                 return addShort((Short)var, other);
146             case INTEGER:
147                 return addInteger((Integer)var, other);
148             case LONG:
149                 return addLong((Long)var, other);
150             case FLOAT:
151                 return addFloat((Float)var, other);
152             default:
153                 return var.doubleValue() + other.doubleValue();
154         }
155     }
156 
157     private final static Number addByte(Byte var, Number other) {
158         switch (tid(other))
159         {
160             case BYTE:
161             {
162                 short v = (short)(var.shortValue() + other.shortValue());
163                 if ((byte)v != v) {
164                     return v;
165                 } else {
166                     return (byte)v;
167                 }
168             }
169             case SHORT:
170             {
171                 int v = var.intValue() + other.intValue();
172                 if ((short)v != v) {
173                     return v;
174                 } else {
175                     return (short)v;
176                 }
177             }
178             case INTEGER:
179             {
180                 long v = var.longValue() + other.longValue();
181                 if ((int)v != v) {
182                     return limit(v);
183                 } else {
184                     return (int)limit(v);
185                 }
186             }
187             case LONG:
188             {
189                 float v = var.floatValue() + other.floatValue();
190                 if ((long)v != v) {
191                     return v;
192                 } else {
193                     return (long)v;
194                 }
195             }
196             case FLOAT:
197             {
198                 double v = var.doubleValue() + other.doubleValue();
199                 if ((float)v != v) {
200                     return v;
201                 } else {
202                     return (float)v;
203                 }
204             }
205             default:
206                 return var.doubleValue() + other.doubleValue();
207         }
208     }
209 
210     private final static Number addShort(Short var, Number other) {
211         switch (tid(other))
212         {
213             case BYTE:
214             case SHORT:
215             {
216                 int v = var.intValue() + other.intValue();
217                 if ((short)v != v) {
218                     return v;
219                 } else {
220                     return (short)v;
221                 }
222             }
223             case INTEGER:
224             {
225                 long v = var.longValue() + other.longValue();
226                 if ((int)v != v) {
227                     return limit(v);
228                 } else {
229                     return (int)limit(v);
230                 }
231             }
232             case LONG:
233             {
234                 float v = var.floatValue() + other.floatValue();
235                 if ((long)v != v) {
236                     return v;
237                 } else {
238                     return (long)v;
239                 }
240             }
241             case FLOAT:
242             {
243                 double v = var.doubleValue() + other.doubleValue();
244                 if ((float)v != v) {
245                     return v;
246                 } else {
247                     return (float)v;
248                 }
249             }
250             default:
251                 return var.doubleValue() + other.doubleValue();
252         }
253     }
254 
255     private final static Number addInteger(Integer var, Number other) {
256         switch (tid(other))
257         {
258             case BYTE:
259             case SHORT:
260             case INTEGER:
261             {
262                 long v = var.longValue() + other.longValue();
263                 if ((int)v != v) {
264                     return limit(v);
265                 } else {
266                     return (int)limit(v);
267                 }
268             }
269             case LONG:
270             {
271                 float v = var.floatValue() + other.floatValue();
272                 if ((long)v != v) {
273                     return v;
274                 } else {
275                     return (long)v;
276                 }
277             }
278             case FLOAT:
279             {
280                 double v = var.doubleValue() + other.doubleValue();
281                 if ((float)v != v) {
282                     return v;
283                 } else {
284                     return (float)v;
285                 }
286             }
287             default:
288                 return var.doubleValue() + other.doubleValue();
289         }
290     }
291 
292     private final static Number addLong(Long var, Number other) {
293         switch (tid(other))
294         {
295             case BYTE:
296             case SHORT:
297             case INTEGER:
298             case LONG:
299             {
300                 float v = var.floatValue() + other.floatValue();
301                 if ((long)v != v) {
302                     return v;
303                 } else {
304                     return (long)v;
305                 }
306             }
307             case FLOAT:
308             {
309                 double v = var.doubleValue() + other.doubleValue();
310                 if ((float)v != v) {
311                     return v;
312                 } else {
313                     return (float)v;
314                 }
315             }
316             default:
317                 return var.doubleValue() + other.doubleValue();
318         }
319     }
320 
321     private final static Number addFloat(Float var, Number other) {
322         switch (tid(other))
323         {
324             case BYTE:
325             case SHORT:
326             case INTEGER:
327             case LONG:
328             case FLOAT:
329             {
330                 double v = var.doubleValue() + other.doubleValue();
331                 if ((float)v != v) {
332                     return v;
333                 } else {
334                     return (float)v;
335                 }
336             }
337             default:
338                 return var.doubleValue() + other.doubleValue();
339         }
340     }
341 
342     /**
343      * <p>Multiplies the two operands, resembling the multiplication operator in JavaScript.</p>
344      * <p>If used with non-numeric operands, this operation attempts to convert them to 
345      * numbers.</p>
346      * @param var Any numeric value.
347      * @param other Any numeric value.
348      * @return The product of the two operands.
349      * @since 1.0
350      * @javascript Re-compilers must report error on the invocation to an <b>internal</b> method. 
351      */
352     public final static Number mul(Number var, Number other) {
353         switch (tid(var))
354         {
355             case BYTE:
356                 return mulByte((Byte)var, other);
357             case SHORT:
358                 return mulShort((Short)var, other);
359             case INTEGER:
360                 return mulInteger((Integer)var, other);
361             case LONG:
362                 return mulLong((Long)var, other);
363             case FLOAT:
364                 return mulFloat((Float)var, other);
365             default:
366                 return var.doubleValue() * other.doubleValue();
367         }
368     }
369 
370     private final static Number mulByte(Byte var, Number other) {
371         switch (tid(other))
372         {
373             case BYTE:
374             {
375                 short v = (short)(var.shortValue() * other.shortValue());
376                 if ((byte)v != v) {
377                     return v;
378                 } else {
379                     return (byte)v;
380                 }
381             }
382             case SHORT:
383             {
384                 int v = var.intValue() * other.intValue();
385                 if ((short)v != v) {
386                     return v;
387                 } else {
388                     return (short)v;
389                 }
390             }
391             case INTEGER:
392             {
393                 long v = var.longValue() * other.longValue();
394                 if ((int)v != v) {
395                     return limit(v);
396                 } else {
397                     return (int)limit(v);
398                 }
399             }
400             case LONG:
401             {
402                 float v = var.floatValue() * other.floatValue();
403                 if ((long)v != v) {
404                     return v;
405                 } else {
406                     return (long)v;
407                 }
408             }
409             case FLOAT:
410             {
411                 double v = var.doubleValue() * other.doubleValue();
412                 if ((float)v != v) {
413                     return v;
414                 } else {
415                     return (float)v;
416                 }
417             }
418             default:
419                 return var.doubleValue() * other.doubleValue();
420         }
421     }
422 
423     private final static Number mulShort(Short var, Number other) {
424         switch (tid(other))
425         {
426             case BYTE:
427             case SHORT:
428             {
429                 int v = var.intValue() * other.intValue();
430                 if ((short)v != v) {
431                     return v;
432                 } else {
433                     return (short)v;
434                 }
435             }
436             case INTEGER:
437             {
438                 long v = var.longValue() * other.longValue();
439                 if ((int)v != v) {
440                     return limit(v);
441                 } else {
442                     return (int)limit(v);
443                 }
444             }
445             case LONG:
446             {
447                 float v = var.floatValue() * other.floatValue();
448                 if ((long)v != v) {
449                     return v;
450                 } else {
451                     return (long)v;
452                 }
453             }
454             case FLOAT:
455             {
456                 double v = var.doubleValue() * other.doubleValue();
457                 if ((float)v != v) {
458                     return v;
459                 } else {
460                     return (float)v;
461                 }
462             }
463             default:
464                 return var.doubleValue() * other.doubleValue();
465         }
466     }
467 
468     private final static Number mulInteger(Integer var, Number other) {
469         switch (tid(other))
470         {
471             case BYTE:
472             case SHORT:
473             case INTEGER:
474             {
475                 long v = var.longValue() * other.longValue();
476                 if ((int)v != v) {
477                     return limit(v);
478                 } else {
479                     return (int)limit(v);
480                 }
481             }
482             case LONG:
483             {
484                 float v = var.floatValue() * other.floatValue();
485                 if ((long)v != v) {
486                     return v;
487                 } else {
488                     return (long)v;
489                 }
490             }
491             case FLOAT:
492             {
493                 double v = var.doubleValue() * other.doubleValue();
494                 if ((float)v != v) {
495                     return v;
496                 } else {
497                     return (float)v;
498                 }
499             }
500             default:
501                 return var.doubleValue() * other.doubleValue();
502         }
503     }
504 
505     private final static Number mulLong(Long var, Number other) {
506         switch (tid(other))
507         {
508             case BYTE:
509             case SHORT:
510             case INTEGER:
511             case LONG:
512             {
513                 float v = var.floatValue() * other.floatValue();
514                 if ((long)v != v) {
515                     return v;
516                 } else {
517                     return (long)v;
518                 }
519             }
520             case FLOAT:
521             {
522                 double v = var.doubleValue() * other.doubleValue();
523                 if ((float)v != v) {
524                     return v;
525                 } else {
526                     return (float)v;
527                 }
528             }
529             default:
530                 return var.doubleValue() * other.doubleValue();
531         }
532     }
533 
534     private final static Number mulFloat(Float var, Number other) {
535         switch (tid(other))
536         {
537             case BYTE:
538             case SHORT:
539             case INTEGER:
540             case LONG:
541             case FLOAT:
542             {
543                 double v = var.doubleValue() * other.doubleValue();
544                 if ((float)v != v) {
545                     return v;
546                 } else {
547                     return (float)v;
548                 }
549             }
550             default:
551                 return var.doubleValue() * other.doubleValue();
552         }
553     }
554 
555     /**
556      * <p>Divides the first operand by the second, resembling the multiplication operator 
557      * in JavaScript.</p>
558      * <p>Used with non-numeric operands, this operation attempts to convert them to 
559      * numbers. If you are used to programming languages that distinguish between integer 
560      * and floating-point numbers, you might expect to get an integer result when you 
561      * divide one integer by another. In JavaScript, however, all numbers are floating-point, 
562      * so all division operations have floating-point results. Division by zero yields positive 
563      * or negative infinity, while <tt>0/0</tt> evaluates to <tt>NaN</tt>.</p>
564      * @param var Any numeric value.
565      * @param other Any numeric value.
566      * @return The quotient of the two operands.
567      * @since 1.0
568      * @javascript Re-compilers must report error on the invocation to an <b>internal</b> method. 
569      */
570     public final static Number div(Number var, Number other) {
571         byte tid = tid(other);
572         double d = var.doubleValue() / other.doubleValue();
573         switch (tid(var))
574         {
575             case BYTE:
576                 switch (tid)
577                 {
578                     case BYTE:
579                     case SHORT:
580                     case INTEGER:
581                     case LONG:
582                         byte v = (byte)(((Byte)var).byteValue() / limit(((Number)other).longValue()));
583                         if (v != d) {
584                             return d;
585                         } else {
586                             return v;
587                         }
588                 }
589             case SHORT:
590                 switch (tid)
591                 {
592                     case BYTE:
593                     case SHORT:
594                     case INTEGER:
595                     case LONG:
596                         short v = (short)(((Short)var).shortValue() / limit(((Number)other).longValue()));
597                         if (v != d) {
598                             return d;
599                         } else {
600                             return v;
601                         }
602                 }
603             case INTEGER:
604                 switch (tid)
605                 {
606                     case BYTE:
607                     case SHORT:
608                     case INTEGER:
609                         long v = var.longValue() / other.longValue();
610                         if ((int)v != v) {
611                             return limit(v);
612                         } else {
613                             return (int)limit(v);
614                         }
615                 }
616             case LONG:
617                 switch (tid)
618                 {
619                     case BYTE:
620                     case SHORT:
621                     case INTEGER:
622                     case LONG:
623                         float v = var.floatValue() / other.floatValue();
624                         if ((long)v != v) {
625                             return v;
626                         } else {
627                             return (long)v;
628                         }
629                 }
630             case FLOAT:
631                 switch (tid)
632                 {
633                     case BYTE:
634                     case SHORT:
635                     case INTEGER:
636                     case LONG:
637                     case FLOAT:
638                         double v = var.doubleValue() / other.doubleValue();
639                         if ((float)v != v) {
640                             return v;
641                         } else {
642                             return (float)v;
643                         }
644                 }
645             default:
646                 return d;
647         }
648     }
649 
650     /**
651      * <p>Computes the first operand modulo the second operand, resembling the modulo 
652      * operator in JavaScript.</p>
653      * <p>The operation returns the remainder when the first operand is divided by the 
654      * second operand a certain number of times. If used with non-numeric operands, the 
655      * operation attempts to convert them to numbers. The sign of the result is the same 
656      * as the sign of the first operand.</p>
657      * <p>This operation is typically used with integer operands, it also works for 
658      * floating-point values.</p>
659      * @param var Any numeric value.
660      * @param other Any numeric value.
661      * @return The remainder.
662      * @since 1.0
663      * @javascript Re-compilers must report error on the invocation to an <b>internal</b> method. 
664      */
665     public final static Number mod(Number var, Number other) {
666         byte tid = tid(other);
667         double d = var.doubleValue() % other.doubleValue();
668         switch (tid(var))
669         {
670             case BYTE:
671                 switch (tid)
672                 {
673                     case BYTE:
674                     case SHORT:
675                     case INTEGER:
676                     case LONG:
677                         byte v = (byte)(((Byte)var).byteValue() % limit(((Number)other).longValue()));
678                         if (v != d) {
679                             return d;
680                         } else {
681                             return v;
682                         }
683                 }
684             case SHORT:
685                 switch (tid)
686                 {
687                     case BYTE:
688                     case SHORT:
689                     case INTEGER:
690                     case LONG:
691                         short v = (short)(((Short)var).shortValue() % limit(((Number)other).longValue()));
692                         if (v != d) {
693                             return d;
694                         } else {
695                             return v;
696                         }
697                 }
698             case INTEGER:
699                 switch (tid)
700                 {
701                     case BYTE:
702                     case SHORT:
703                     case INTEGER:
704                         long v = var.longValue() % other.longValue();
705                         if ((int)v != v) {
706                             return limit(v);
707                         } else {
708                             return (int)limit(v);
709                         }
710                 }
711             case LONG:
712                 switch (tid)
713                 {
714                     case BYTE:
715                     case SHORT:
716                     case INTEGER:
717                     case LONG:
718                         float v = var.floatValue() % other.floatValue();
719                         if ((long)v != v) {
720                             return v;
721                         } else {
722                             return (long)v;
723                         }
724                 }
725             case FLOAT:
726                 switch (tid)
727                 {
728                     case BYTE:
729                     case SHORT:
730                     case INTEGER:
731                     case LONG:
732                     case FLOAT:
733                         double v = var.doubleValue() % other.doubleValue();
734                         if ((float)v != v) {
735                             return v;
736                         } else {
737                             return (float)v;
738                         }
739                 }
740             default:
741                 return d;
742         }
743     }
744 
745     static String getConnectionResponseHeaders(URLConnection c) {
746         int i = 0;
747         String value;
748         StringBuilder sb = new StringBuilder();
749         while ((value = c.getHeaderField(i)) != null) {
750             String key = c.getHeaderFieldKey(i);
751             sb.append(key);
752             sb.append(": ");
753             sb.append(value);
754             i++;
755         }
756         return sb.toString();
757     }
758 
759     static String getCharset(URLConnection connection) {
760         String contentType = connection == null ? null : connection.getContentType();
761         if (contentType != null) {
762             StringTokenizer tok = new StringTokenizer(contentType, ";");
763             if (tok.hasMoreTokens()) {
764                 tok.nextToken();
765                 while (tok.hasMoreTokens()) {
766                     String assignment = tok.nextToken().trim();
767                     int eqIdx = assignment.indexOf('=');
768                     if (eqIdx != -1) {
769                         String varName = assignment.substring(0, eqIdx).trim();
770                         if ("charset".equalsIgnoreCase(varName)) {
771                             String varValue = assignment.substring(eqIdx + 1);
772                             return unquote(varValue.trim());
773                         }
774                     }
775                 }
776             }
777         }
778         return null;
779     }
780 
781     static String unquote(String text) {
782         if (text.startsWith("\"") && text.endsWith("\"")) {
783             return text.substring(1, text.length() - 2);
784         }
785         return text;
786     }
787 
788     static byte[] loadStream(InputStream in, int initialBufferSize) throws IOException {
789         if (initialBufferSize == 0) {
790             initialBufferSize = 1;
791         }
792         byte[] buffer = new byte[initialBufferSize];
793         int offset = 0;
794         for (;;) {
795             int remain = buffer.length - offset;
796             if (remain <= 0) {
797                 int newSize = buffer.length * 2;
798                 byte[] newBuffer = new byte[newSize];
799                 System.arraycopy(buffer, 0, newBuffer, 0, offset);
800                 buffer = newBuffer;
801                 remain = buffer.length - offset;
802             }
803             int numRead = in.read(buffer, offset, remain);
804             if (numRead == -1) {
805                 break;
806             }
807             offset += numRead;
808         }
809         if (offset < buffer.length) {
810             byte[] newBuffer = new byte[offset];
811             System.arraycopy(buffer, 0, newBuffer, 0, offset);
812             buffer = newBuffer;
813         }
814         return buffer;
815     }
816 }