org.luaj.vm2.LuaString Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of luaj-jse Show documentation
Show all versions of luaj-jse Show documentation
Luaj 2.0 for the jse platform
/*******************************************************************************
* Copyright (c) 2009 Luaj.org. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
******************************************************************************/
package org.luaj.vm2;
import java.io.ByteArrayInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.ref.WeakReference;
import java.util.Hashtable;
import org.luaj.vm2.lib.MathLib;
import org.luaj.vm2.lib.StringLib;
public class LuaString extends LuaValue {
public static LuaValue s_metatable;
public final byte[] m_bytes;
public final int m_offset;
public final int m_length;
private static final Hashtable index_java = new Hashtable();
private final static LuaString index_get(Hashtable indextable, Object key) {
WeakReference w = (WeakReference) indextable.get(key);
return w!=null? (LuaString) w.get(): null;
}
private final static void index_set(Hashtable indextable, Object key, LuaString value) {
indextable.put(key, new WeakReference(value));
}
public static LuaString valueOf(String string) {
LuaString s = index_get( index_java, string );
if ( s != null ) return s;
char[] c = string.toCharArray();
byte[] b = new byte[lengthAsUtf8(c)];
encodeToUtf8(c, b, 0);
s = valueOf(b, 0, b.length);
index_set( index_java, string, s );
return s;
}
public static LuaString valueOf(byte[] bytes, int off, int len) {
return new LuaString(bytes, off, len);
}
public static LuaString valueOf(char[] bytes) {
int n = bytes.length;
byte[] b = new byte[n];
for ( int i=0; i0? LuaValue.TRUE: FALSE; }
public boolean lt_b( LuaValue rhs ) { return rhs.strcmp(this)>0; }
public boolean lt_b( int rhs ) { typerror("attempt to compare string with number"); return false; }
public boolean lt_b( double rhs ) { typerror("attempt to compare string with number"); return false; }
public LuaValue lteq( LuaValue rhs ) { return rhs.strcmp(this)>=0? LuaValue.TRUE: FALSE; }
public boolean lteq_b( LuaValue rhs ) { return rhs.strcmp(this)>=0; }
public boolean lteq_b( int rhs ) { typerror("attempt to compare string with number"); return false; }
public boolean lteq_b( double rhs ) { typerror("attempt to compare string with number"); return false; }
public LuaValue gt( LuaValue rhs ) { return rhs.strcmp(this)<0? LuaValue.TRUE: FALSE; }
public boolean gt_b( LuaValue rhs ) { return rhs.strcmp(this)<0; }
public boolean gt_b( int rhs ) { typerror("attempt to compare string with number"); return false; }
public boolean gt_b( double rhs ) { typerror("attempt to compare string with number"); return false; }
public LuaValue gteq( LuaValue rhs ) { return rhs.strcmp(this)<=0? LuaValue.TRUE: FALSE; }
public boolean gteq_b( LuaValue rhs ) { return rhs.strcmp(this)<=0; }
public boolean gteq_b( int rhs ) { typerror("attempt to compare string with number"); return false; }
public boolean gteq_b( double rhs ) { typerror("attempt to compare string with number"); return false; }
// concatenation
public LuaValue concat(LuaValue rhs) { return rhs.concatTo(this); }
public Buffer concat(Buffer rhs) { return rhs.concatTo(this); }
public LuaValue concatTo(LuaNumber lhs) { return concatTo(lhs.strvalue()); }
public LuaValue concatTo(LuaString lhs) {
byte[] b = new byte[lhs.m_length+this.m_length];
System.arraycopy(lhs.m_bytes, lhs.m_offset, b, 0, lhs.m_length);
System.arraycopy(this.m_bytes, this.m_offset, b, lhs.m_length, this.m_length);
return new LuaString(b, 0, b.length);
}
// string comparison
public int strcmp(LuaValue lhs) { return -lhs.strcmp(this); }
public int strcmp(LuaString rhs) {
for ( int i=0, j=0; i>5)+1; /* if string is too long, don't hash all its chars */
for (int l1=m_length; l1>=step; l1-=step) /* compute hash */
h = h ^ ((h<<5)+(h>>2)+(((int) m_bytes[m_offset+l1-1] ) & 0x0FF ));
return h;
}
// object comparison, used in key comparison
public boolean equals( Object o ) {
if ( o instanceof LuaString ) {
return raweq( (LuaString) o );
}
return false;
}
// equality w/ metatable processing
public LuaValue eq( LuaValue val ) { return val.raweq(this)? TRUE: FALSE; }
public boolean eq_b( LuaValue val ) { return val.raweq(this); }
// equality w/o metatable processing
public boolean raweq( LuaValue val ) {
return val.raweq(this);
}
public boolean raweq( LuaString s ) {
if ( this == s )
return true;
if ( s.m_length != m_length )
return false;
if ( s.m_bytes == m_bytes && s.m_offset == m_offset )
return true;
if ( s.hashCode() != hashCode() )
return false;
for ( int i=0; i=0 )
if ( a[i++]!=b[j++] )
return false;
return true;
}
public void write(DataOutputStream writer, int i, int len) throws IOException {
writer.write(m_bytes,m_offset+i,len);
}
public LuaValue len() {
return LuaInteger.valueOf(m_length);
}
public int length() {
return m_length;
}
public int luaByte(int index) {
return m_bytes[m_offset + index] & 0x0FF;
}
public int charAt( int index ) {
if ( index < 0 || index >= m_length )
throw new IndexOutOfBoundsException();
return luaByte( index );
}
public String checkjstring() {
return tojstring();
}
public LuaString checkstring() {
return this;
}
public InputStream toInputStream() {
return new ByteArrayInputStream(m_bytes, m_offset, m_length);
}
/**
* Copy the bytes of the string into the given byte array.
*/
public void copyInto( int strOffset, byte[] bytes, int arrayOffset, int len ) {
System.arraycopy( m_bytes, m_offset+strOffset, bytes, arrayOffset, len );
}
/** Java version of strpbrk, which is a terribly named C function. */
public int indexOfAny( LuaString accept ) {
final int ilimit = m_offset + m_length;
final int jlimit = accept.m_offset + accept.m_length;
for ( int i = m_offset; i < ilimit; ++i ) {
for ( int j = accept.m_offset; j < jlimit; ++j ) {
if ( m_bytes[i] == accept.m_bytes[j] ) {
return i - m_offset;
}
}
}
return -1;
}
public int indexOf( byte b, int start ) {
for ( int i=0, j=m_offset+start; i < m_length; ++i ) {
if ( m_bytes[j++] == b )
return i;
}
return -1;
}
public int indexOf( LuaString s, int start ) {
final int slen = s.length();
final int limit = m_offset + m_length - slen;
for ( int i = m_offset + start; i <= limit; ++i ) {
if ( equals( m_bytes, i, s.m_bytes, s.m_offset, slen ) ) {
return i;
}
}
return -1;
}
public int lastIndexOf( LuaString s ) {
final int slen = s.length();
final int limit = m_offset + m_length - slen;
for ( int i = limit; i >= m_offset; --i ) {
if ( equals( m_bytes, i, s.m_bytes, s.m_offset, slen ) ) {
return i;
}
}
return -1;
}
// --------------------- utf8 conversion -------------------------
/**
* Convert to Java String interpreting as utf8 characters
*/
public static String decodeAsUtf8(byte[] bytes, int offset, int length) {
int i,j,n,b;
for ( i=offset,j=offset+length,n=0; i=0||i>=j)? b:
(b<-32||i+1>=j)? (((b&0x3f) << 6) | (bytes[i++]&0x3f)):
(((b&0xf) << 12) | ((bytes[i++]&0x3f)<<6) | (bytes[i++]&0x3f)));
}
return new String(chars);
}
/**
* Count the number of bytes required to encode the string as UTF-8.
*/
public static int lengthAsUtf8(char[] chars) {
int i,b;
char c;
for ( i=b=chars.length; --i>=0; )
if ( (c=chars[i]) >=0x80 )
b += (c>=0x800)? 2: 1;
return b;
}
/**
* Encode the given Java string as UTF-8 bytes, writing the result to bytes
* starting at offset. The string should be measured first with lengthAsUtf8
* to make sure the given byte array is large enough.
*/
public static void encodeToUtf8(char[] chars, byte[] bytes, int off) {
final int n = chars.length;
char c;
for ( int i=0, j=off; i>6) & 0x1f));
bytes[j++] = (byte) (0x80 | ( c & 0x3f));
} else {
bytes[j++] = (byte) (0xE0 | ((c>>12) & 0x0f));
bytes[j++] = (byte) (0x80 | ((c>>6) & 0x3f));
bytes[j++] = (byte) (0x80 | ( c & 0x3f));
}
}
}
public boolean isValidUtf8() {
int i,j,n,b,e=0;
for ( i=m_offset,j=m_offset+m_length,n=0; i= 0 ) continue;
if ( ((c & 0xE0) == 0xC0)
&& i= 2 && base <= 36 ) {
int i=m_offset,j=m_offset+m_length;
while ( i=j )
return Double.NaN;
if ( ( base == 10 || base == 16 ) && ( m_bytes[i]=='0' && i+1='0'&&m_bytes[i]<='9')? '0':
m_bytes[i]>='A'&&m_bytes[i]<='Z'? ('A'-10): ('a'-10));
if ( digit < 0 || digit >= base )
return Double.NaN;
x = x * base + digit;
}
return neg? -x: x;
}
/**
* Scan and convert a double value, or return Double.NaN if not a double.
* @return DoubleValue, IntValue, or Double.NaN depending on what is found.
*/
private double scandouble(int start, int end) {
if ( end>start+64 ) end=start+64;
for ( int i=start; i