2032 lines
57 KiB
C++
2032 lines
57 KiB
C++
#include "java.hpp"
|
|
#include <diskio.hpp>
|
|
#include <entry.hpp>
|
|
#include "npooluti.hpp"
|
|
#include "oututil.hpp"
|
|
|
|
#ifndef NCPS
|
|
#define NCPS 0x110000
|
|
#endif
|
|
|
|
//-----------------------------------------------------------------------
|
|
NORETURN void errtrunc(void)
|
|
{
|
|
loader_failure("Premature end of file");
|
|
}
|
|
|
|
//-----------------------------------------------------------------------
|
|
GCC_DIAG_OFF(format-nonliteral);
|
|
void java_t::load_msg(const char *format, ...)
|
|
{ // this procedure prepares saving load-time message to base
|
|
char str[MAXSTR];
|
|
va_list va;
|
|
|
|
++errload;
|
|
va_start(va, format);
|
|
int cnt = qvsnprintf(str, sizeof(str), format, va);
|
|
va_end(va);
|
|
msg("%s", str);
|
|
for ( int i = cnt; i; )
|
|
{
|
|
if ( str[--i] <= ' ' ) // remove cr's
|
|
continue;
|
|
if ( ++i > MAXSPECSIZE )
|
|
{
|
|
i = MAXSPECSIZE;
|
|
memcpy(&str[MAXSPECSIZE-3], "...", 3);
|
|
}
|
|
|
|
netnode temp;
|
|
uval_t j;
|
|
if ( !curClass.msgNode )
|
|
{
|
|
temp.create();
|
|
curClass.msgNode = temp;
|
|
j = 0;
|
|
}
|
|
else
|
|
{
|
|
temp = curClass.msgNode;
|
|
j = temp.altval(0);
|
|
}
|
|
temp.supset(j, str, i);
|
|
temp.altset(0, j+1);
|
|
break;
|
|
}
|
|
}
|
|
GCC_DIAG_ON(format-nonliteral);
|
|
|
|
//-----------------------------------------------------------------------
|
|
const char *java_t::mk_diag(attr_parent_kind_t apk, char str[128]) const
|
|
{
|
|
static const char *const diag[] = { "Code in method", "Field", "Method" };
|
|
str[0] = '\0';
|
|
if ( apk < attr_parent_kind_class_file )
|
|
qsnprintf(str,
|
|
126,
|
|
" for %s#%u", diag[uchar(apk)],
|
|
apk == attr_parent_kind_field ? curField.id.Number : curSeg.id.Number);
|
|
return str;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------
|
|
void java_t::BadRef(ea_t ea, const char *to, ushort id, attr_parent_kind_t apk)
|
|
{
|
|
if ( ea != BADADDR )
|
|
remember_problem(PR_DISASM, ea);
|
|
|
|
char diastr[128];
|
|
load_msg("Illegal %s reference (%u)%s\n", to, id, mk_diag(apk, diastr));
|
|
}
|
|
|
|
//-----------------------------------------------------------------------
|
|
void java_t::mark_access(ea_t ea, ushort acc) const
|
|
{
|
|
char str[60];
|
|
|
|
str[0] = 0; // for module
|
|
if ( acc )
|
|
qsnprintf(str, sizeof(str), "Illegal access bits (0x%X)", acc);
|
|
mark_and_comment(ea, str);
|
|
}
|
|
|
|
//-------------------------------------------------------------------------
|
|
static const char *_constant_strings[CONSTANT_LAST+1] =
|
|
{
|
|
// 0
|
|
"<UNKNOWN>",
|
|
"Utf8",
|
|
"Unicode",
|
|
"Integer",
|
|
"Float",
|
|
// 5
|
|
"Long",
|
|
"Double",
|
|
"Class",
|
|
"String",
|
|
"Fieldref",
|
|
// 10
|
|
"Methodref",
|
|
"InterfaceMethodref",
|
|
"NameAndType",
|
|
"<UNUSED_13>",
|
|
"<UNUSED_14>",
|
|
// 15
|
|
"MethodHandle",
|
|
"MethodType",
|
|
"<UNUSED_17>",
|
|
"InvokeDynamic",
|
|
};
|
|
const char *constant_type_to_str(uchar ctype)
|
|
{
|
|
if ( ctype > CONSTANT_LAST )
|
|
ctype = 0;
|
|
return _constant_strings[ctype];
|
|
}
|
|
|
|
//-------------------------------------------------------------------------
|
|
void print_constant(
|
|
qstrvec_t *out,
|
|
const const_desc_t &cd,
|
|
ushort index,
|
|
bool strip_tags)
|
|
{
|
|
size_t anchor = out->size();
|
|
|
|
op_t x;
|
|
memset(&x, 0, sizeof(x));
|
|
copy_const_to_opnd(x, cd);
|
|
x.ref = 0; // as flag
|
|
x.cp_type = cd.type;
|
|
x.cp_ind = index;
|
|
if ( x.cp_type == CONSTANT_Class )
|
|
x.addr_shorts.high = (cd.flag & HAS_CLSNAME) != 0 ? fmt_fullname : fmt_ClassName;
|
|
out_java_t *ctx = (out_java_t *) create_outctx(BADADDR);
|
|
ctx->init_lines_array(out, 1000);
|
|
ctx->init_prompted_output();
|
|
ctx->OutConstant(x, /*include_descriptor=*/ true);
|
|
ctx->flush_outbuf();
|
|
|
|
if ( strip_tags )
|
|
{
|
|
for ( ; anchor < out->size(); ++anchor )
|
|
tag_remove(&out->at(anchor));
|
|
}
|
|
|
|
delete ctx;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------
|
|
void *myAlloc(uint size)
|
|
{
|
|
void *p = qalloc(size);
|
|
if ( p == NULL )
|
|
nomem("JavaLoader");
|
|
return p;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------
|
|
uchar *java_t::sm_realloc(uint size)
|
|
{
|
|
if ( size > curClass.maxSMsize )
|
|
{
|
|
curClass.maxSMsize = size;
|
|
qfree(smBuf);
|
|
smBuf = (uchar*)myAlloc(size+1);
|
|
}
|
|
return smBuf;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------
|
|
uchar *java_t::annotation_realloc(uint size)
|
|
{
|
|
if ( size > curClass.maxAnnSz )
|
|
{
|
|
curClass.maxAnnSz = size;
|
|
qfree(annBuf);
|
|
annBuf = (uchar*)myAlloc(size+1);
|
|
}
|
|
return annBuf;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------
|
|
// visible for converter only
|
|
ushort *java_t::append_tmp_buffer(uint size)
|
|
{
|
|
if ( (ushort)size > curClass.maxStrSz )
|
|
{
|
|
curClass.maxStrSz = (ushort)size;
|
|
qfree(tsPtr);
|
|
tsPtr = (ushort*)myAlloc(size*sizeof(ushort)*2+sizeof(ushort));
|
|
}
|
|
return tsPtr;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------
|
|
bool java_t::getblob(uval_t ind, void *p, uval_t sz)
|
|
{
|
|
if ( (ushort)sz > curClass.maxStrSz )
|
|
return false;
|
|
|
|
sz *= 2;
|
|
size_t ts = (size_t)sz + 1;
|
|
return ConstantNode.getblob(p, &ts, ind, BLOB_TAG) && (uint32)ts == sz;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------
|
|
bool java_t::getstr(qstring *out, ushort index)
|
|
{
|
|
bool ok = is_valid_string_index(index);
|
|
if ( ok )
|
|
{
|
|
// || !getblob(ind2, p2 = p1 + (size_t)siz1, siz2) )
|
|
// uval_t i1 = ConstantNode.altval(ind1);
|
|
uint32 raw_idx = (uint32)index << 16;
|
|
nodeidx_t sz = ushort(ConstantNode.altval(raw_idx));
|
|
ok = sz > 0;
|
|
if ( ok )
|
|
{
|
|
qvector<ushort> raw;
|
|
raw.resize(sz, 0);
|
|
msg("Reading %u bytes\n", uint32(sz));
|
|
ok = getblob(raw_idx, raw.begin(), sz);
|
|
if ( ok )
|
|
out->append((const char *) raw.begin(), sz);
|
|
}
|
|
}
|
|
return ok;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
NORETURN static void readerr(void)
|
|
{
|
|
loader_failure("Input file read error");
|
|
}
|
|
|
|
//-----------------------------------------------------------------------
|
|
ushort java_t::read2(void)
|
|
{
|
|
ushort data;
|
|
if ( FileSize < 2 )
|
|
errtrunc();
|
|
FileSize -= 2;
|
|
if ( fread2bytes(myFile, &data, 1) != 0 )
|
|
readerr();
|
|
return data;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------
|
|
uint32 java_t::read4(void)
|
|
{
|
|
uint32 data;
|
|
if ( FileSize < 4 )
|
|
errtrunc();
|
|
FileSize -= 4;
|
|
if ( fread4bytes(myFile, &data, 1) != 0 )
|
|
readerr();
|
|
return data;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------
|
|
uchar java_t::read1(void)
|
|
{
|
|
uchar data;
|
|
if ( !FileSize )
|
|
errtrunc();
|
|
--FileSize;
|
|
if ( qfread(myFile, &data, 1) != 1 )
|
|
readerr();
|
|
return data;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------
|
|
void java_t::readData(void *data, uint32 size)
|
|
{
|
|
if ( FileSize < size )
|
|
errtrunc();
|
|
FileSize -= size;
|
|
if ( qfread(myFile, data, size) != size )
|
|
readerr();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------
|
|
void java_t::skipData(uint32 size)
|
|
{
|
|
if ( FileSize < size )
|
|
errtrunc();
|
|
FileSize -= size;
|
|
qfseek(myFile, size, SEEK_CUR);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------
|
|
uchar java_t::set_parent_object(void)
|
|
{
|
|
if ( curClass.super.Name )
|
|
{
|
|
static const char object[] = "java.lang.Object";
|
|
if ( fmtName(curClass.super.Name, tmpbuf, sizeof(tmpbuf), fmt_fullname)
|
|
&& memcmp(tmpbuf, object, sizeof(object)) == 0 )
|
|
{
|
|
curClass.extflg |= XFL_C_SUPEROBJ;
|
|
return 1;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------
|
|
const uchar *java_t::get_annotation(uval_t node, uint *plen)
|
|
{
|
|
netnode temp(node);
|
|
size_t len = (size_t)temp.altval(0);
|
|
if ( len && len <= curClass.maxAnnSz )
|
|
{
|
|
*plen = (uint)len;
|
|
++len;
|
|
if ( temp.getblob(annBuf, &len, 0, BLOB_TAG) && len == *plen )
|
|
return annBuf;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------
|
|
bool java_t::sm_getinfo(const insn_t &insn, SMinfo *pinf)
|
|
{ // call ONLY when curSeg.smNode != 0
|
|
sm_info_t smr;
|
|
ea_t ea;
|
|
|
|
switch ( sm_node )
|
|
{
|
|
case smn_aa_not_finished:
|
|
goto noinfo;
|
|
|
|
case smn_ok:
|
|
sm_node = smn_no_use;
|
|
SMnode = curSeg.smNode;
|
|
{
|
|
size_t cnt = (size_t)SMnode.altval(-1);
|
|
if ( cnt < 2 || cnt > curClass.maxSMsize )
|
|
goto destroyed;
|
|
SMsize = (uint32)cnt;
|
|
++cnt;
|
|
if ( !SMnode.getblob(smBuf, &cnt, 0, BLOB_TAG) || cnt != SMsize )
|
|
goto destroyed;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
|
|
ea = pinf->ea;
|
|
if ( ea == BADADDR )
|
|
ea = insn.ea - 1;
|
|
ea = SMnode.supnext(ea);
|
|
if ( ea == BADNODE )
|
|
goto noinfo;
|
|
if ( get_item_head(ea) != insn.ea )
|
|
goto noinfo;
|
|
if ( SMnode.supval(ea, &smr, sizeof(smr)) != sizeof(smr) )
|
|
goto destroyed;
|
|
if ( smr.noff >= 2 && smr.eoff > smr.noff && smr.eoff <= SMsize )
|
|
{
|
|
pinf->ea = ea;
|
|
pinf->pb = smBuf + smr.noff;
|
|
pinf->pe = smBuf + smr.eoff;
|
|
pinf->fcnt = smr.fcnt;
|
|
return true;
|
|
}
|
|
|
|
destroyed:
|
|
DESTROYED("sm_getinfo");
|
|
|
|
noinfo:
|
|
return false;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------
|
|
static const char special_sym[] =
|
|
{
|
|
j_field_dlm, // classname (dot) ==> special point
|
|
j_clspath_dlm, // classname path (slash)
|
|
j_parm_list_start, j_parm_list_end, // function (for methods)
|
|
0
|
|
};
|
|
|
|
//-------------------------------------------------------------------------
|
|
void op_NameChars(namechar_op_t op)
|
|
{
|
|
switch ( op )
|
|
{
|
|
case ncop_disable:
|
|
for ( size_t i = 0; i < qnumber(special_sym); ++i )
|
|
set_cp_validity(UCDR_NAME, special_sym[i], BADCP, false);
|
|
break;
|
|
case ncop_enable:
|
|
for ( size_t i = 0; i < qnumber(special_sym); ++i )
|
|
set_cp_validity(UCDR_NAME, special_sym[i]);
|
|
break;
|
|
case ncop_enable_without_parens:
|
|
for ( size_t i = 0; i < 2; ++i )
|
|
set_cp_validity(UCDR_NAME, special_sym[i]);
|
|
break;
|
|
default: INTERR(10267);
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------
|
|
void make_NameChars(bool on_load)
|
|
{
|
|
static const char special_char[] =
|
|
{
|
|
'$', '_', // MUST present (historical/special)
|
|
j_sign, j_endsign, // special case for <init>, <clinit> :(
|
|
};
|
|
|
|
set_cp_validity(UCDR_NAME, 0, NCPS, false);
|
|
// in names accepted ONLY english chars (temporary?)
|
|
set_cp_validity(UCDR_NAME, 'A', 'Z'+1);
|
|
set_cp_validity(UCDR_NAME, 'a', 'z'+1);
|
|
set_cp_validity(UCDR_NAME, '0', '9'+1);
|
|
for ( size_t i = 0; i < qnumber(special_char); ++i )
|
|
set_cp_validity(UCDR_NAME, special_char[i]);
|
|
// fill national character's
|
|
set_cp_validity(UCDR_NAME, '\\'); // is valid for unicode escape sequnce only (special work)
|
|
// class/method path/call chars
|
|
op_NameChars(on_load ? ncop_enable : ncop_enable_without_parens); // for oldbase convertation
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
segment_t *java_t::getMySeg(ea_t ea, segment_t *seg)
|
|
{
|
|
segment_t *s = seg != NULL ? seg : getseg(ea);
|
|
|
|
if ( s == NULL )
|
|
goto compat_err;
|
|
|
|
if ( curSeg.start_ea != s->start_ea )
|
|
{
|
|
if ( sm_node > smn_ok )
|
|
sm_node = smn_ok;
|
|
if ( !s->orgbase )
|
|
{
|
|
if ( s->type != SEG_IMP && s->type != SEG_XTRN )
|
|
goto compat_err;
|
|
curSeg.start_ea = s->start_ea;
|
|
}
|
|
else
|
|
{
|
|
if ( ClassNode.supval(s->orgbase, &curSeg, sizeof(curSeg) ) != sizeof(curSeg) )
|
|
DESTROYED("getMySeg");
|
|
if ( -s->orgbase != curSeg.id.Number
|
|
|| s->start_ea != (s->type == SEG_BSS ? curSeg.DataBase : curSeg.start_ea) )
|
|
{
|
|
compat_err:
|
|
UNCOMPAT("getMySeg");
|
|
}
|
|
}
|
|
}
|
|
return s;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------
|
|
// visible for converter only
|
|
GCC_DIAG_OFF(format-nonliteral);
|
|
void out_java_t::trunc_name(uint num, uchar type)
|
|
{
|
|
static const char fnam[] = "...(Field_%u)";
|
|
static const char metnam[] = "...(Method_%u)";
|
|
static const char locnam[] = "...(locvar_%u)";
|
|
static const char xtrn[] = "...(extern_%u)";
|
|
static const char clsnam[] = "...";
|
|
static const char *const add_nam[5] = { xtrn, fnam, metnam, locnam, clsnam };
|
|
|
|
enableExt_NameChar();
|
|
size_t s = (sizeof(metnam) - 2 + 5 + 1);
|
|
size_t inplen = outbuf.length();
|
|
outbuf.resize(inplen - s);
|
|
outbuf.cat_sprnt(add_nam[type], num);
|
|
}
|
|
GCC_DIAG_ON(format-nonliteral);
|
|
|
|
//-----------------------------------------------------------------------
|
|
int java_t::CmpString(ushort index1, ushort index2)
|
|
{
|
|
DEB_ASSERT((!index1 || !index2), "cs-ind");
|
|
if ( index1 != index2 )
|
|
{
|
|
size_t i;
|
|
uval_t ind1 = (uint32)index1 << 16;
|
|
uval_t ind2 = (uint32)index2 << 16;
|
|
|
|
uval_t sz = ConstantNode.altval(ind1);
|
|
if ( sz == 0 || (i=(size_t)ConstantNode.altval(ind2)) == 0 )
|
|
{
|
|
BADIDB:
|
|
DESTROYED("CmpString");
|
|
}
|
|
|
|
if ( sz != i )
|
|
{
|
|
diff:
|
|
return 1;
|
|
}
|
|
|
|
i = (ushort)i;
|
|
if ( i == 0 )
|
|
return -1;
|
|
|
|
sz = i;
|
|
i *= sizeof(ushort);
|
|
uchar *p1 = (uchar *)tsPtr, *p2 = p1 + i;
|
|
if ( !getblob(ind1, p1, sz) || !getblob(ind2, p2, sz) )
|
|
goto BADIDB;
|
|
if ( memcmp(p1, p2, i) != 0 )
|
|
goto diff;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------
|
|
int java_t::cmpDscrString(ushort index1, uchar met, ushort index2, uchar self)
|
|
{
|
|
uval_t siz1, siz2;
|
|
ushort *p1, *p2;
|
|
|
|
uval_t ind1 = (uint32)index1 << 16;
|
|
uval_t ind2 = (uint32)index2 << 16;
|
|
uval_t i1 = ConstantNode.altval(ind1);
|
|
uval_t i2 = ConstantNode.altval(ind2);
|
|
if ( i1 == 0
|
|
|| i2 == 0
|
|
|| (siz1 = (ushort)i1) == 0
|
|
|| (siz2 = (ushort)i2) == 0
|
|
|| !getblob(ind1, p1 = tsPtr, siz1)
|
|
|| !getblob(ind2, p2 = p1 + (size_t)siz1, siz2) )
|
|
{
|
|
goto int_err;
|
|
}
|
|
|
|
if ( met )
|
|
{
|
|
#define _MCR ((_OP_ONECLS | _OP_VALPOS) << 16)
|
|
if ( (i1 & _MCR) != _MCR )
|
|
goto diff;
|
|
#undef _MCR
|
|
i1 = ConstantNode.altval(ind1+1);
|
|
if ( !i1 || (int32)(siz1 -= i1) <= 0 )
|
|
goto int_err; // never signature
|
|
p1 += (size_t)i1;
|
|
}
|
|
|
|
if ( self && !(i1 & (_OP_NODSCR << 16)) )
|
|
{
|
|
while ( *p1 == j_array )
|
|
{
|
|
if ( !--siz1 )
|
|
goto int_err;
|
|
++p1;
|
|
}
|
|
}
|
|
|
|
if ( (i1 ^ i2) & (_OP_NODSCR << 16) )
|
|
{
|
|
if ( i2 & (_OP_NODSCR << 16) )
|
|
{
|
|
if ( *p1 == j_class && p1[(size_t)siz1-1] == j_endclass )
|
|
{
|
|
++p1;
|
|
if ( (int)(siz1 -= 2) <= 0 )
|
|
goto int_err;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ( *p2 == j_class && p2[(size_t)siz2-1] == j_endclass )
|
|
{
|
|
++p2;
|
|
if ( (int)(siz2 -= 2) <= 0 )
|
|
goto int_err;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( siz1 != siz2 || memcmp(p1, p2, (size_t)siz1 * sizeof(ushort)) != 0 )
|
|
goto diff;
|
|
return 0;
|
|
int_err:
|
|
INTERNAL("cmpDscrString");
|
|
diff:
|
|
return 1;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------
|
|
ushort java_t::xtrnDscrSearch(ushort name, uchar met)
|
|
{
|
|
const_desc_t cr;
|
|
|
|
if ( curClass.This.Dscr
|
|
&& !cmpDscrString(name, met, curClass.This.Name, 1) )
|
|
{
|
|
return 0xFFFF;
|
|
}
|
|
|
|
for ( ushort j = curClass.xtrnLQE; j; j = (ushort)(XtrnNode.altval(j) >> 16) )
|
|
{
|
|
if ( ConstantNode.supval(j, &cr, sizeof(cr)) != sizeof(cr)
|
|
|| cr.type != CONSTANT_Class
|
|
|| (j = cr.ref_ip) == 0 )
|
|
{
|
|
INTERNAL("xtrnDscrSearch");
|
|
}
|
|
if ( !cmpDscrString(name, met, cr._name, 0) )
|
|
return j;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------
|
|
void java_t::mark_strange_name(ea_t ea) const
|
|
{
|
|
mark_and_comment(ea, "Strange name");
|
|
}
|
|
|
|
//-----------------------------------------------------------------------
|
|
void java_t::xtrnSet(
|
|
uint cin,
|
|
const_desc_t *co,
|
|
uint xip,
|
|
char *str,
|
|
size_t strsize,
|
|
bool full,
|
|
uchar rmod)
|
|
{
|
|
ea_t ea = curClass.xtrnEA + xip;
|
|
|
|
if ( !(rmod & 4) )
|
|
{
|
|
co->ref_ip = (ushort)xip;
|
|
StoreOpis(cin, *co);
|
|
uval_t rfa = cin;
|
|
if ( full )
|
|
{
|
|
rfa |= ((uval_t)curClass.xtrnLQE << 16);
|
|
curClass.xtrnLQE = (ushort)cin;
|
|
}
|
|
XtrnNode.altset(xip, rfa);
|
|
create_byte(ea, 1);
|
|
}
|
|
|
|
uint js = MAXNAMELEN - 1;
|
|
out_java_t *pctx = (out_java_t *)create_outctx(BADADDR);
|
|
name_chk = 0;
|
|
if ( full ) // fmt_fullname
|
|
{
|
|
uni_chk = 0;
|
|
if ( pctx->fmtString(*this, co->_name, js, fmt_fullname) )
|
|
{
|
|
endcls = MAXNAMELEN;
|
|
trnc:
|
|
pctx->trunc_name(xip);
|
|
pctx->outbuf.resize(MAXNAMELEN-1);
|
|
}
|
|
else
|
|
{
|
|
endcls = (uint)strlen(pctx->outbuf.c_str());
|
|
}
|
|
clunic = uni_chk;
|
|
}
|
|
else
|
|
{
|
|
uni_chk = clunic;
|
|
if ( endcls >= MAXNAMELEN - 2 )
|
|
{
|
|
pctx->outbuf.resize(MAXNAMELEN-1);
|
|
name_chk = 0; // no mark here
|
|
goto trnc;
|
|
}
|
|
pctx->outbuf.resize(pctx->outbuf.length() + (endcls + 1));
|
|
pctx->outbuf[endcls] = '.';
|
|
js -= (endcls + 1);
|
|
if ( pctx->fmtString(*this, co->_subnam, js, fmt_UnqualifiedName) )
|
|
goto trnc;
|
|
}
|
|
qstrncpy(str, pctx->outbuf.c_str(), strsize);
|
|
delete pctx;
|
|
if ( rmod & 1 )
|
|
{
|
|
// enableExt_NameChar();
|
|
force_name(ea, convert_clsname(str));
|
|
hide_name(ea);
|
|
// disableExt_NameChar();
|
|
}
|
|
if ( (char)uni_chk > 0 && (rmod & 2) )
|
|
ConstantNode.charset(ea, uni_chk, UR_TAG);
|
|
uni_chk = (uchar)-1;
|
|
if ( name_chk && !(rmod & 4) )
|
|
mark_strange_name(ea);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------
|
|
void java_t::SetName(ushort name, ea_t ea, ushort access_mode, uval_t number, uchar rmod)
|
|
{
|
|
uni_chk = name_chk = 0;
|
|
fmt_t fmt = number || curSeg.id.Number ? fmt_UnqualifiedName : fmt_fullname;
|
|
out_java_t *pctx = (out_java_t *)create_outctx(BADADDR);
|
|
if ( pctx->fmtString(*this, name, sizeof(tmpbuf) - 1, fmt) )
|
|
{
|
|
if ( !number )
|
|
pctx->trunc_name(curSeg.id.Number, uchar(3 + !curSeg.id.Number));
|
|
else if ( number <= (uval_t)curClass.FieldCnt )
|
|
pctx->trunc_name((uint)number, 1);
|
|
else
|
|
pctx->trunc_name((uint)number - curClass.FieldCnt, 2);
|
|
}
|
|
qstrncpy(tmpbuf, pctx->outbuf.c_str(), sizeof(tmpbuf));
|
|
delete pctx;
|
|
convert_clsname(tmpbuf);
|
|
|
|
if ( rmod & 1 )
|
|
{
|
|
switch ( access_mode & ACC_ACCESS_MASK )
|
|
{
|
|
case ACC_PUBLIC:
|
|
if ( rmod & 4 )
|
|
del_global_name(ea);
|
|
add_entry(number, ea, tmpbuf, 0);
|
|
break;
|
|
case 0:
|
|
if ( rmod & 4 )
|
|
del_global_name(ea);
|
|
add_entry(ea, ea, tmpbuf, 0);
|
|
break;
|
|
default:
|
|
force_name(ea, tmpbuf);
|
|
break;
|
|
}
|
|
}
|
|
// disableExt_NameChar();
|
|
if ( (char)uni_chk > 0 && (rmod & 2) )
|
|
ConstantNode.charset(ea, uni_chk, UR_TAG);
|
|
uni_chk = (uchar)-1;
|
|
if ( name_chk && !(rmod & 4) )
|
|
mark_strange_name(ea);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------
|
|
// as procedure for rename_unichars
|
|
void java_t::set_lv_name(ushort name, ea_t ea, uchar rmod)
|
|
{
|
|
uni_chk = name_chk = 0;
|
|
if ( fmtName(name, tmpbuf, sizeof(tmpbuf), fmt_UnqualifiedName) )
|
|
{
|
|
if ( rmod & 1 )
|
|
force_name(ea, tmpbuf);
|
|
hide_name(ea);
|
|
if ( (char)uni_chk > 0 && (rmod & 2) )
|
|
ConstantNode.charset(ea, uni_chk, UR_TAG);
|
|
if ( name_chk && !(rmod & 4) )
|
|
mark_strange_name(ea);
|
|
}
|
|
uni_chk = (uchar)-1;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
void java_t::rename_uninames(int32 mode)
|
|
{
|
|
nodeidx_t id = ConstantNode.charfirst(UR_TAG);
|
|
if ( id != BADNODE )
|
|
{
|
|
char str[MAXNAMELEN]; // for imports
|
|
|
|
show_wait_box("HIDECANCEL\nRenaming labels with national characters");
|
|
|
|
ushort lcls = 0; // for imports
|
|
uchar rmod = 7; // rename+save (+renamemode)
|
|
switch ( mode )
|
|
{
|
|
case 0: // change table but renaming not needed (recreate records only)
|
|
rmod = 2; // save only
|
|
break;
|
|
case -1: // change processor flag only
|
|
rmod = 5; // rename only
|
|
// no break
|
|
default: // change table and renaming needed
|
|
break;
|
|
}
|
|
do
|
|
{
|
|
adiff_t dif;
|
|
ea_t ea = id;
|
|
uchar type = ConstantNode.charval(ea, UR_TAG);
|
|
show_addr(ea);
|
|
if ( !type || type > 3 )
|
|
goto BADIDB;
|
|
if ( !(type & 2) && mode == -1 )
|
|
continue;
|
|
switch ( getMySeg(ea)->type )
|
|
{
|
|
default:
|
|
BADIDB:
|
|
DESTROYED("rename_uninames");
|
|
|
|
case SEG_BSS:
|
|
if ( !curSeg.varNode
|
|
|| (dif = ea - curSeg.DataBase) < 0
|
|
|| dif >= curSeg.DataSize
|
|
|| is_align(get_flags(ea)) )
|
|
{
|
|
goto BADIDB;
|
|
}
|
|
{
|
|
netnode tmp(curSeg.varNode);
|
|
LocVar lv;
|
|
if ( tmp.supval((nodeidx_t)dif, &lv, sizeof(lv)) != sizeof(lv) )
|
|
goto BADIDB;
|
|
set_lv_name(lv.var.Name, ea, rmod);
|
|
}
|
|
break;
|
|
|
|
case SEG_CODE:
|
|
if ( ea != curSeg.start_ea )
|
|
goto BADIDB;
|
|
SetName(curSeg.id.name, ea, curSeg.id.access,
|
|
curClass.FieldCnt + curSeg.id.Number, rmod);
|
|
break;
|
|
|
|
case SEG_IMP: // class/fields
|
|
dif = ea - curClass.start_ea;
|
|
if ( dif < 0 )
|
|
goto BADIDB;
|
|
if ( !dif ) // class
|
|
{
|
|
ushort sv = curSeg.id.Number;
|
|
curSeg.id.Number = 0;
|
|
SetName(curClass.This.Name, ea, curClass.AccessFlag, 0, rmod);
|
|
curSeg.id.Number = sv;
|
|
break;
|
|
}
|
|
if ( dif > curClass.FieldCnt )
|
|
goto BADIDB;
|
|
if ( ClassNode.supval((nodeidx_t)dif, &curField, sizeof(curField) ) != sizeof(curField) )
|
|
goto BADIDB;
|
|
SetName(curField.id.name, ea, curField.id.access, (int)dif, rmod);
|
|
break;
|
|
|
|
case SEG_XTRN:
|
|
dif = ea - curClass.xtrnEA;
|
|
if ( dif <= 0 || dif > curClass.xtrnCnt )
|
|
goto BADIDB;
|
|
{
|
|
uchar cmod = rmod;
|
|
const_desc_t co;
|
|
{
|
|
uint j = (uint)XtrnNode.altval((nodeidx_t)dif);
|
|
if ( j == 0 )
|
|
goto BADIDB;
|
|
if ( !LoadOpis(lm_normal, (ushort)j, 0, &co) )
|
|
goto BADIDB;
|
|
}
|
|
switch ( co.type )
|
|
{
|
|
default:
|
|
goto BADIDB;
|
|
|
|
case CONSTANT_Fieldref:
|
|
case CONSTANT_InterfaceMethodref:
|
|
case CONSTANT_Methodref:
|
|
if ( co._name != lcls )
|
|
{
|
|
cmod = 4; // set internal static variables only
|
|
LCLASS:
|
|
lcls = co._name;
|
|
xtrnSet(-1, &co, (uint)dif, str, sizeof(str), true, cmod);
|
|
if ( co.type == CONSTANT_Class )
|
|
break;
|
|
}
|
|
xtrnSet(-1, &co, (uint)dif, str, sizeof(str), false, rmod);
|
|
break;
|
|
case CONSTANT_Class:
|
|
goto LCLASS;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
while ( (id = ConstantNode.charnext(id, UR_TAG)) != BADNODE );
|
|
hide_wait_box();
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------
|
|
void java_t::xtrnRef(ea_t ea, const const_desc_t &opis) const
|
|
{
|
|
if ( (loadMode & MLD_EXTREF) && opis.ref_ip )
|
|
{
|
|
ea_t target = opis.ref_ip == 0xFFFF
|
|
? curClass.start_ea
|
|
: curClass.xtrnEA + opis.ref_ip;
|
|
add_dref(ea, target, dr_I);
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------
|
|
void java_t::xtrnRef_dscr(ea_t ea, const_desc_t *opis, uchar met)
|
|
{
|
|
if ( !met )
|
|
{
|
|
if ( !(loadMode & MLD_VARREF) )
|
|
return;
|
|
if ( (opis->flag & (HAS_CLSNAME | HAS_TYPEDSCR)) == HAS_CLSNAME )
|
|
return;
|
|
}
|
|
else if ( !(loadMode & MLD_METHREF) )
|
|
{
|
|
return;
|
|
}
|
|
|
|
const_desc_t cr(*opis);
|
|
opis = &cr;
|
|
opis->ref_ip = xtrnDscrSearch(opis->_name, met);
|
|
xtrnRef(ea, *opis);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------
|
|
void java_t::deltry(uint bg, uint ic, uint ui, const const_desc_t &pco)
|
|
{
|
|
for ( uint i = bg; (ushort)i <= curClass.xtrnCnt; i++ )
|
|
{
|
|
uint j = (uint)XtrnNode.altval(i, '0');
|
|
if ( j == 0 )
|
|
continue;
|
|
const_desc_t co;
|
|
ConstantNode.supval(j, &co, sizeof(co));
|
|
if ( co.type != pco.type
|
|
|| co.flag != pco.flag
|
|
|| co.ref_ip != (ushort)ic
|
|
|| CmpString(co._subnam, pco._subnam)
|
|
|| CmpString(co._dscr, pco._dscr) )
|
|
{
|
|
continue;
|
|
}
|
|
co.ref_ip = (ushort)ui;
|
|
StoreOpis(j, co);
|
|
XtrnNode.altdel(i, '0');
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------
|
|
GCC_DIAG_OFF(format-nonliteral);
|
|
segment_t *java_t::_add_seg(int caller)
|
|
{
|
|
static const char *const _cls[4] = { "xtrn", "met_", "_var", "head" };
|
|
static const char *const fm[4] = { "import", "met%03u", "var%03u", "_Class" };
|
|
|
|
uval_t size;
|
|
uchar type;
|
|
|
|
switch ( caller )
|
|
{
|
|
default:
|
|
INTERNAL("_add_seg");
|
|
|
|
case 1: // method
|
|
curSeg.start_ea = start_ea;
|
|
// fallthrough
|
|
case -1: // code
|
|
start_ea = curSeg.start_ea;
|
|
type = SEG_CODE;
|
|
size = curSeg.CodeSize;
|
|
break;
|
|
|
|
case 2: // data
|
|
curSeg.DataBase = start_ea;
|
|
size = curSeg.DataSize;
|
|
type = SEG_BSS;
|
|
break;
|
|
|
|
case 3: // class
|
|
curClass.start_ea = start_ea;
|
|
size = curClass.FieldCnt + 1;
|
|
type = SEG_IMP;
|
|
break;
|
|
|
|
case 0: // header
|
|
curClass.xtrnEA = start_ea = to_ea(inf_get_baseaddr(), 0);
|
|
if ( !curClass.xtrnCnt )
|
|
return NULL;
|
|
size = curClass.xtrnCnt;
|
|
type = SEG_XTRN;
|
|
break;
|
|
}
|
|
ea_t top = start_ea + size;
|
|
ea_t end = (top + (0xF + 1)) & ~0xF;
|
|
if ( top < start_ea )
|
|
loader_failure("Our of addressing space");
|
|
|
|
segment_t *S;
|
|
if ( caller < 0 )
|
|
{
|
|
S = getseg(start_ea);
|
|
if ( S == NULL || !set_segm_end(curSeg.start_ea, end, SEGMOD_KILL) )
|
|
qexit(1);
|
|
qoff64_t pos = qftell(myFile);
|
|
linput_t *li = make_linput(myFile);
|
|
file2base(li, pos, start_ea, top, FILEREG_PATCHABLE);
|
|
unmake_linput(li);
|
|
qfseek(myFile, pos + curSeg.CodeSize, SEEK_SET);
|
|
}
|
|
else
|
|
{
|
|
sel_t sel;
|
|
if ( start_ea > 0x100000 )
|
|
{
|
|
sel = cursel++;
|
|
set_selector(sel, start_ea>>4);
|
|
}
|
|
else
|
|
{
|
|
sel = (ushort)(start_ea >> 4);
|
|
}
|
|
if ( !add_segm(sel, start_ea, end, NULL, _cls[caller]) )
|
|
qexit(1);
|
|
S = getseg(start_ea);
|
|
S->orgbase = -(uval_t)curSeg.id.Number;
|
|
S->type = type;
|
|
if ( caller != 1 )
|
|
S->set_hidden_segtype(true); // no out comment of segment type
|
|
char sname[32];
|
|
qsnprintf(sname, sizeof(sname), fm[caller], curSeg.id.Number);
|
|
set_segm_name(S, sname);
|
|
if ( caller <= 1 )
|
|
goto end_create; // method/header
|
|
for ( uval_t i = 0; start_ea < top; start_ea++, i++ ) // data & class
|
|
{
|
|
create_byte(start_ea, 1);
|
|
if ( caller == 2 ) // data
|
|
{
|
|
char str[MAXNAMELEN];
|
|
qsnprintf(str, sizeof(str), "met%03u_slot%03" FMT_EA "u", curSeg.id.Number, i);
|
|
if ( force_name(start_ea, str) )
|
|
make_name_auto(start_ea);
|
|
else
|
|
hide_name(start_ea);
|
|
}
|
|
}
|
|
}
|
|
|
|
create_byte(top, end - top); // !header && !method
|
|
end_create:
|
|
start_ea = end;
|
|
return S;
|
|
}
|
|
GCC_DIAG_ON(format-nonliteral);
|
|
|
|
//-----------------------------------------------------------------------
|
|
void java_t::resizeLocVars(void) const
|
|
{
|
|
netnode temp(curSeg.varNode);
|
|
int slot = curSeg.DataSize;
|
|
|
|
for ( int32 cur, prev = 1; --slot >= 0; prev = cur )
|
|
{
|
|
cur = (int32)temp.altval(slot);
|
|
if ( cur < 0 && !prev )
|
|
{
|
|
del_items(curSeg.DataBase + slot+1, DELIT_SIMPLE);
|
|
create_word(curSeg.DataBase + slot, 2);
|
|
}
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------
|
|
const char *java_t::CopyAttrToFile(const char *astr, uint32 size, ushort id)
|
|
{
|
|
if ( FileSize < size )
|
|
errtrunc(); // here for alloc diagnostic
|
|
|
|
char fname[QMAXPATH];
|
|
qstrncpy(fname, get_path(PATH_TYPE_CMD), sizeof(fname));
|
|
char *ptr = (char *)get_file_ext(fname);
|
|
if ( ptr == NULL )
|
|
{
|
|
ptr = &fname[strlen(fname)];
|
|
*ptr++ = '.';
|
|
}
|
|
|
|
uint32 sz = uint32(ptr - fname);
|
|
|
|
uval_t *pnode = NULL;
|
|
if ( astr[0] == ' ' ) // SourceDebugExtension
|
|
{
|
|
if ( sz > sizeof(fname)-sizeof("SDE.utf8") )
|
|
{
|
|
too_long:
|
|
return "PathName too long";
|
|
}
|
|
memcpy(ptr, "SDE.utf8", sizeof("SDE.utf8"));
|
|
}
|
|
else
|
|
{
|
|
if ( sz > (sizeof(fname)-30) )
|
|
goto too_long;
|
|
|
|
switch ( (uchar)astr[0] )
|
|
{
|
|
default: // ARQ_FILE:
|
|
pnode = &curClass.genNode;
|
|
break;
|
|
case attr_parent_kind_field:
|
|
ptr += qsnprintf(ptr, 30, "fld%03u_", curField.id.Number);
|
|
pnode = &curField.genNode;
|
|
break;
|
|
case attr_parent_kind_code:
|
|
case attr_parent_kind_method:
|
|
pnode = &curSeg.genNodes[astr[0] == attr_parent_kind_code];
|
|
ptr += qsnprintf(ptr, 30, "%smet%03u.",
|
|
astr[0] == attr_parent_kind_code ? "code_" : "",
|
|
curSeg.id.Number);
|
|
break;
|
|
}
|
|
|
|
uchar err = 0;
|
|
for ( sz = 1; ptr < &fname[sizeof(fname) - sizeof(".attr")]; sz++ ) //lint !e440
|
|
{
|
|
uchar c = astr[sz];
|
|
switch ( c )
|
|
{
|
|
case 0:
|
|
goto full_copy;
|
|
default:
|
|
if ( c > CHP_MIN && c < CHP_MAX )
|
|
{
|
|
*ptr++ = c;
|
|
break;
|
|
}
|
|
// no break
|
|
case '/':
|
|
case '\\':
|
|
case '>':
|
|
case '<':
|
|
case '?':
|
|
case '*':
|
|
case '=':
|
|
err = 1;
|
|
break;
|
|
}
|
|
}
|
|
ptr[-1] = '!'; // as marker of truncated name
|
|
full_copy:
|
|
memcpy(ptr, ".attr", sizeof(".attr"));
|
|
if ( err )
|
|
msg("Convert unprintable filename for attribute '%s'\n", &astr[1]);
|
|
}
|
|
ptr = fname;
|
|
while ( (ptr=strchr(ptr, '\\')) != NULL )
|
|
*ptr = '/';
|
|
|
|
ptr = (char *)myAlloc(size + 1); // +1 for zero_size extension!
|
|
readData(ptr, size);
|
|
|
|
FILE *f = qfopen(fname, "wb");
|
|
if ( f == NULL )
|
|
{
|
|
qfree(ptr);
|
|
return "Can't create file for storing";
|
|
}
|
|
|
|
uchar err = 0;
|
|
if ( qfwrite(f, ptr, size) != size )
|
|
++err;
|
|
qfree(ptr);
|
|
if ( qfclose(f) && !err )
|
|
{
|
|
qunlink(fname);
|
|
return "Error writing";
|
|
}
|
|
if ( pnode )
|
|
{
|
|
netnode temp;
|
|
uint32 pos = 0;
|
|
if ( *pnode )
|
|
{
|
|
temp = *pnode;
|
|
}
|
|
else
|
|
{
|
|
temp.create();
|
|
*pnode = temp;
|
|
pos = (uint32)temp.altval(0);
|
|
}
|
|
++pos;
|
|
temp.altset(pos, id);
|
|
temp.supset(pos, fname, strlen(fname));
|
|
temp.altset(0, pos);
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------
|
|
bool java_t::fmtName(ushort index, char *buf, size_t bufsize, fmt_t fmt)
|
|
{
|
|
out_java_t *pctx = (out_java_t *)create_outctx(BADADDR);
|
|
int i = pctx->fmtString(*this, index, bufsize-1, fmt);
|
|
qstrncpy(buf, pctx->outbuf.c_str(), bufsize);
|
|
delete pctx;
|
|
return !i && buf[0];
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
// Procedures for "press Enter on any name"
|
|
int java_t::is_locvar_name(const insn_t &insn, const char *name)
|
|
{
|
|
LocVar lv;
|
|
uint32 idx = (uint32)insn.Op1.addr;
|
|
|
|
if ( insn.Op1.type == o_mem )
|
|
{
|
|
if ( insn.Op1.ref )
|
|
goto bad;
|
|
}
|
|
else if ( insn.Op1.type == o_void )
|
|
{
|
|
if ( (char)insn.Op1.ref < 0 || (int32)(idx -= (uint32)curSeg.DataBase) < 0 )
|
|
goto bad;
|
|
}
|
|
|
|
if ( netnode(curSeg.varNode).supval(idx, &lv, sizeof(lv)) == sizeof(lv)
|
|
&& fmtName(lv.var.Name, tmpbuf, sizeof(tmpbuf), fmt_UnqualifiedName)
|
|
&& streq(name, tmpbuf) )
|
|
{
|
|
return idx;
|
|
}
|
|
bad:
|
|
return -1;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------
|
|
static bool is_get_ref_addr_visible_cp(wchar32_t cp)
|
|
{
|
|
return cp == j_field_dlm || cp == j_clspath_dlm || is_visible_cp(cp);
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
ea_t java_t::get_ref_addr(ea_t ea, const char *name, size_t pos)
|
|
{
|
|
if ( strlen(name) <= pos || getseg(ea) == NULL )
|
|
{
|
|
NOT_FOUND:
|
|
return BADADDR;
|
|
}
|
|
|
|
uchar clv = getMySeg(ea)->type;
|
|
switch ( clv ) // also set curSeg
|
|
{
|
|
case SEG_XTRN:
|
|
if ( !jasmin() )
|
|
goto NOT_FOUND; // short form. Can't search by text
|
|
// no break
|
|
default:
|
|
break;
|
|
case SEG_CODE:
|
|
if ( strstrpos(name, ash.cmnt) <= pos )
|
|
clv |= 0x80; // flag for 'modified autocomment' (see make_locvar_cmt)
|
|
break;
|
|
}
|
|
|
|
ssize_t r = pos;
|
|
if ( !is_get_ref_addr_visible_cp(uchar(name[r])) )
|
|
goto NOT_FOUND;
|
|
|
|
while ( r > 0 && is_get_ref_addr_visible_cp(uchar(name[r-1])) )
|
|
--r;
|
|
ssize_t start = r;
|
|
for ( r = pos+1; name[r]; r++ )
|
|
if ( !is_get_ref_addr_visible_cp(uchar(name[r])) )
|
|
break;
|
|
if ( name[r] == '\\' && !name[r+1] )
|
|
goto NOT_FOUND; //\\+++ not work with prompt?
|
|
char buf[MAXSTR*2];
|
|
memcpy(buf, &name[start], r);
|
|
buf[r] = '\0';
|
|
switch ( clv & ~0x80 )
|
|
{
|
|
case SEG_CODE:
|
|
case SEG_BSS:
|
|
r = check_special_label(buf, r);
|
|
if ( r >= 0 )
|
|
return curSeg.start_ea + r;
|
|
// no break
|
|
default:
|
|
break;
|
|
}
|
|
insn_t insn;
|
|
decode_insn(&insn, ea);
|
|
if ( (clv&0x80) && curSeg.varNode && (start = is_locvar_name(insn, buf)) >= 0 )
|
|
return curSeg.DataBase + start;
|
|
// append(new)
|
|
ea_t rea = get_name_ea(BADADDR, convert_clsname(buf));
|
|
if ( rea == BADADDR && jasmin() && (clv&~0x80) == SEG_CODE ) // fieldnames
|
|
{
|
|
char *p = strrchr(buf, j_field_dlm);
|
|
if ( p )
|
|
{
|
|
*p++ = '\0';
|
|
if ( get_name_ea(BADADDR, buf) == curClass.start_ea )
|
|
rea = get_name_ea(BADADDR, p);
|
|
}
|
|
}
|
|
return rea;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------
|
|
// for IDF_SHOWBADSTR (index my be not string :)
|
|
bool java_t::is_valid_string_index(ushort index) const
|
|
{
|
|
return index > 0
|
|
&& index <= curClass.maxCPindex
|
|
&& ConstantNode.altval(((uint32)index) << 16);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------
|
|
/* signatures encoding
|
|
*
|
|
* methodOrFieldSignature ::= type
|
|
* classSignature ::= [ typeparams ] supertype { interfacetype }
|
|
*
|
|
* type ::= ... | classtype | methodtype | typevar
|
|
* classtype ::= classsig { '.' classsig }
|
|
* classig ::= 'L' name [typeargs] ';'
|
|
* methodtype ::= [ typeparams ] '(' { type } ')' type
|
|
* typevar ::= 'T' name ';'
|
|
* typeargs ::= '<' type { type } '>'
|
|
* typeparams ::= '<' typeparam { typeparam } '>'
|
|
* typeparam ::= name ':' type
|
|
*/
|
|
|
|
//-------------------------------------------------------------------------
|
|
int out_java_t::fmtString(java_t &pm, ushort index, ssize_t size, fmt_t mode, _PRMPT_ putproc)
|
|
{
|
|
ushort *tp = NULL;
|
|
|
|
if ( size < 0 )
|
|
FMTSTR_INTERR:
|
|
INTERNAL("fmtString");
|
|
|
|
if ( !index )
|
|
BADIDB:
|
|
DESTROYED("fmtString");
|
|
|
|
uint32 strind = ((uint32)index) << 16;
|
|
uint32 ostsz = uint32(pm.ConstantNode.altval(strind));
|
|
if ( ostsz == 0 )
|
|
goto BADIDB;
|
|
CASSERT(offsetof(_STROP_, size) == 0 && sizeof(((_STROP_ *)0)->size) == sizeof(ushort));
|
|
if ( !(pm.uni_chk & 1) && (ostsz & (_OP_UNICHARS<<16)) )
|
|
++pm.uni_chk; // rename unicode
|
|
if ( ostsz & (_OP_BADFIRST<<16) )
|
|
pm.name_chk = 1;
|
|
if ( mode & FMT_ENC_RESERVED ) // support jasmin reserved words
|
|
{
|
|
CASSERT((fmt_fullname+1) == fmt_UnqualifiedName && (fmt_UnqualifiedName+1 ) == fmt__ENDENUM);
|
|
mode = (fmt_t)(mode ^ FMT_ENC_RESERVED);
|
|
if ( mode < fmt_fullname )
|
|
goto FMTSTR_INTERR;
|
|
if ( (ostsz & (_OP_JSMRES_ << 16)) && (pm.idpflags & IDM_OUTASM) )
|
|
mode = fmt_string_single_quotes;
|
|
}
|
|
ostsz = (ushort)ostsz;
|
|
if ( ostsz != 0 && !pm.getblob(strind, tp = pm.tsPtr, ostsz) )
|
|
goto BADIDB;
|
|
|
|
uint32 off_ReturnType = 0;
|
|
uint32 off_ThrowsSignature_and_TypeSignature = 0;
|
|
if ( fmt_expects_call_descriptor(mode) ) // method part out
|
|
{
|
|
off_ReturnType = (uint32)pm.ConstantNode.altval(strind+1); // offset to return type
|
|
off_ThrowsSignature_and_TypeSignature = (uint32)pm.ConstantNode.altval(strind+2); // lng of <...:...> + throw off
|
|
}
|
|
|
|
return pm.format_utf16_string(tp, ostsz, off_ReturnType, off_ThrowsSignature_and_TypeSignature, size, mode, this, putproc);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------
|
|
//-----------------------------------------------------------------------
|
|
// this function is called only from the loader
|
|
uchar java_t::LoadUtf8(ushort index, const_desc_t *co)
|
|
{
|
|
_STROP_ _opstr;
|
|
uint32 Flags = 0;
|
|
uint32 ind = ((uint32)index) << 16;
|
|
uchar result = 0, is_sde = 0, unicode = 0;
|
|
uint size;
|
|
|
|
if ( index == (ushort)-1 ) // SourceDebugExtension
|
|
{
|
|
CASSERT(offsetof(_STROP_, size) == 0 && sizeof(_opstr.size) == sizeof(ushort));
|
|
*(uint32*)&_opstr = (ushort)(size_t)co;
|
|
co = NULL;
|
|
is_sde = 1;
|
|
}
|
|
else
|
|
{
|
|
_opstr.flags = _OP_UTF8_;
|
|
_opstr.size = read2();
|
|
}
|
|
size = _opstr.size;
|
|
if ( size != 0 )
|
|
{
|
|
ushort *po = append_tmp_buffer(size);
|
|
union
|
|
{
|
|
ushort cw;
|
|
uchar cs;
|
|
};
|
|
uchar c;
|
|
do
|
|
{
|
|
--size;
|
|
cw = (uchar)read1();
|
|
if ( cw == 0 || cs >= 0xf0 )
|
|
goto errcoding;
|
|
if ( (char)cs < 0 )
|
|
{
|
|
if ( !size )
|
|
goto errchar;
|
|
--size;
|
|
--_opstr.size;
|
|
c = cs;
|
|
cs &= 0x1F;
|
|
cw <<= 6;
|
|
{
|
|
uchar c2 = read1();
|
|
if ( (c2 & 0xC0) != 0x80 )
|
|
goto errchar;
|
|
cs |= (c2 & 0x3F);
|
|
}
|
|
if ( (c & 0xE0) != 0xC0 )
|
|
{
|
|
if ( !size
|
|
|| (c & 0xF0) != 0xE0
|
|
|| ((c = read1()) & 0xC0) != 0x80 )
|
|
{
|
|
errchar:
|
|
if ( is_sde )
|
|
goto done;
|
|
loader_failure("Illegal byte in CONSTANT_Utf8 (%u)", index);
|
|
}
|
|
--size;
|
|
--_opstr.size;
|
|
cw <<= 6;
|
|
cs |= (c & 0x3F);
|
|
if ( cw < 0x800 )
|
|
goto errcoding;
|
|
}
|
|
else if ( cw < 0x80 && cs )
|
|
{
|
|
errcoding:
|
|
if ( is_sde )
|
|
goto done;
|
|
loader_failure("Illegal symbol encoding in CONSTANT_Utf8 (%u)", index);
|
|
}
|
|
} // end encoding
|
|
*po++ = cw;
|
|
if ( !is_sde )
|
|
{
|
|
if ( cw >= CHP_MAX )
|
|
{
|
|
if ( !javaIdent(cw) )
|
|
goto extchar;
|
|
unicode = 1;
|
|
}
|
|
else if ( cs <= CHP_MIN )
|
|
{
|
|
extchar:
|
|
Flags |= _OP_EXTSYM_;
|
|
unicode = (uchar)-1;
|
|
}
|
|
}
|
|
}
|
|
while ( size );
|
|
|
|
if ( !is_sde
|
|
&& _opstr.size == 1
|
|
&& (loadMode & MLD_STRIP)
|
|
&& (cw >= 0x80 || get_base_typename(cs) == NULL) )
|
|
{
|
|
// Symantec error (strip) #3
|
|
char str[16];
|
|
uchar *ps = (uchar *)str;
|
|
|
|
_opstr.size = (ushort)qsnprintf(str, sizeof(str), "_?_%04X", cw);
|
|
po = append_tmp_buffer(_opstr.size);
|
|
do
|
|
*po++ = *ps++;
|
|
while ( *ps );
|
|
Flags |= _OP_NODSCR | _OP_NOSIGN;
|
|
co->flag = HAS_CLSNAME | HAS_FLDNAME;
|
|
unicode = 0; // PARANOYA
|
|
}
|
|
result = !Flags;
|
|
ConstantNode.setblob(tsPtr, (uchar *)po - (uchar *)tsPtr, ind, BLOB_TAG);
|
|
}
|
|
if ( !is_sde )
|
|
{
|
|
if ( unicode == 1 )
|
|
Flags |= _OP_UNICHARS;
|
|
_opstr.flags |= (ushort)Flags;
|
|
co->_Sopstr = *(int32 *)&_opstr;
|
|
}
|
|
ConstantNode.altset(ind, *(uint32 *)&_opstr);
|
|
done:
|
|
return result;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------
|
|
void java_t::parse_const_desc(ushort index, const_desc_t *co)
|
|
{
|
|
// all nexts used only here (for parsing)
|
|
#define _op_PARAM_ 0x00010000 // start paramlist '('
|
|
#define _op_PAREND_ 0x00020000 // last char is end of paramlist ')'
|
|
#define _op_RETTYPE_ 0x00040000 // have valid position for call return type
|
|
#define _op_FRSPRM_ 0x00080000 // not first descriptor (parameter)
|
|
#define _op_CLSBEG_ 0x00100000 // begin 'L...;' detected
|
|
#define _op_TYPBEG_ 0x00200000 // begin 'T...;' (signtype) detected
|
|
#define _op_NAME_ 0x00400000 // non empty class/typeref-name
|
|
#define _op_ARRAY_ 0x00800000 // previous char is '['
|
|
// next needed for 'complex' classnames
|
|
#define _op_ISARRAY_ 0x01000000 // have any '[' in name
|
|
#define _op_PRIMSIG_ 0x02000000 // <...:...> signature presnt
|
|
#define _op_INPRSIG_ 0x04000000 // currently parse <...:...> signature
|
|
#define _op_MUSTNAM_ 0x08000000 // part must be name (before ':')
|
|
|
|
#define _op_isTAG_ (_op_CLSBEG_ | _op_NAME_ | _op_TYPBEG_)
|
|
|
|
uint Flags = 0;
|
|
uint size = co->_Ssize;
|
|
uint32 off_ReturnType = 0;
|
|
uint32 off_ThrowsSignature_and_TypeSignature = 0;
|
|
ushort *po = tsPtr; // ATT: call ONLY after LoadUtf8, size!=0
|
|
uchar sgnlev = 0, prim = 0, *pprim = NULL;
|
|
uchar cs; // for prev
|
|
|
|
if ( *po == j_sign ) // check <...:...> signature and <init>/<clinit>
|
|
{
|
|
while ( ++off_ReturnType < size )
|
|
{
|
|
if ( !javaIdent(po[off_ReturnType]) )
|
|
{
|
|
if ( off_ReturnType != 1 )
|
|
{
|
|
size -= off_ReturnType+1; // +1 => balance for while, or align for <init>
|
|
switch ( po[off_ReturnType] )
|
|
{
|
|
case j_tag:
|
|
if ( size < 7 )
|
|
break; // Lx;>Lx; or Lx;>( )V => only_string
|
|
Flags |= _OP_FULLNM | _OP_NOFNM | _OP_NODSCR
|
|
| _op_PRIMSIG_ | _op_INPRSIG_;
|
|
po += off_ReturnType;
|
|
off_ReturnType &= 0;
|
|
++sgnlev;
|
|
goto accept_tag;
|
|
|
|
case j_endsign:
|
|
if ( !size ) // <init>/<clinit>
|
|
{
|
|
Flags |= _OP_NODSCR | _OP_NOSIGN;
|
|
goto SET_FLAGS;
|
|
}
|
|
// no break
|
|
default:
|
|
break; // only_string
|
|
} // switch
|
|
} // off_ReturnType != 1
|
|
break;
|
|
} // special_char
|
|
}
|
|
goto only_string;
|
|
} // first '<'
|
|
|
|
if ( *po == j_parm_list_start ) // check method descriptor/signature
|
|
{
|
|
to_func:
|
|
if ( --size < 2 )
|
|
goto only_string; // )V
|
|
++po;
|
|
Flags |= _op_PARAM_;
|
|
}
|
|
else
|
|
{
|
|
pprim = &prim;
|
|
}
|
|
do
|
|
{
|
|
--size;
|
|
cs = 0; // as flag (for wide characters)
|
|
CASSERT(CHP_MAX < 0x100);
|
|
if ( *po < CHP_MAX )
|
|
cs = (uchar)*po; // for 'L', 'T'...
|
|
if ( javaIdent(*po, pprim) ) // letter/digit/$_
|
|
{
|
|
if ( pprim )
|
|
{
|
|
if ( !prim )
|
|
Flags |= _OP_BADFIRST;
|
|
pprim = NULL;
|
|
}
|
|
goto norm_char;
|
|
}
|
|
pprim = NULL; // for speed
|
|
if ( cs <= CHP_MIN )
|
|
goto only_string; // also >= CHP_MAX
|
|
|
|
if ( Flags & _op_MUSTNAM_ ) // only in <...:...> signature (formal name)
|
|
{
|
|
if ( cs != j_tag )
|
|
goto only_string;
|
|
Flags &= ~_op_MUSTNAM_;
|
|
if ( size < 7 )
|
|
goto only_string; // Lx;>Lx; or Lx;>()V
|
|
accept_tag:
|
|
if ( po[1] == j_tag )
|
|
{ // iface
|
|
--size;
|
|
++po;
|
|
}
|
|
goto only_tag;
|
|
}
|
|
switch ( cs ) // validate special chars
|
|
{
|
|
case j_parm_list_end: // always can be present in in name
|
|
if ( sgnlev )
|
|
goto only_string;
|
|
if ( (Flags & (_op_PARAM_ | _op_ARRAY_ | _op_isTAG_)) != _op_PARAM_ )
|
|
goto only_string;
|
|
Flags ^= (_op_PARAM_ | _op_PAREND_);
|
|
continue;
|
|
|
|
case j_array: // class name can be full qualified array :(
|
|
if ( !sgnlev && !(Flags & (_op_isTAG_ | _OP_NOSIGN)) )
|
|
{
|
|
Flags |= _OP_FULLNM;
|
|
break;
|
|
}
|
|
// no break
|
|
default:
|
|
goto only_string;
|
|
|
|
case j_clspath_dlm: // '/'
|
|
case j_field_dlm: // '.'
|
|
Flags |= _OP_FULLNM;
|
|
continue;
|
|
|
|
case j_sign:
|
|
if ( size < 3 // *>;
|
|
|| (Flags & (_op_NAME_ | _OP_NOSIGN)) != _op_NAME_
|
|
|| ++sgnlev >= 30 )
|
|
{
|
|
goto only_string;
|
|
}
|
|
CASSERT((int32)(2 << 30) < 0); // "fmtString check method"
|
|
Flags |= _OP_FULLNM | _OP_NOFNM | _OP_NODSCR;
|
|
Flags &= ~_op_isTAG_;
|
|
--size;
|
|
switch ( *++po )
|
|
{
|
|
case j_wild:
|
|
if ( *++po != j_endsign )
|
|
goto only_string;
|
|
--size;
|
|
goto end_signW;
|
|
|
|
case j_wild_s:
|
|
case j_wild_e:
|
|
goto only_tag;
|
|
|
|
default:
|
|
goto skipped_only_tag;
|
|
}
|
|
|
|
case j_endsign:
|
|
if ( !size || !sgnlev )
|
|
goto only_string;
|
|
end_signW:
|
|
// end of <...:...> signature must resolve in endclass
|
|
if ( !--sgnlev && (Flags & _op_INPRSIG_) )
|
|
goto only_string;
|
|
if ( *++po != j_endclass )
|
|
goto only_string;
|
|
--size;
|
|
Flags |= _op_NAME_; // restore
|
|
// no break
|
|
case j_endclass:
|
|
if ( (Flags & (_op_NAME_ | _op_PAREND_ | _op_ARRAY_)) != _op_NAME_ )
|
|
goto only_string;
|
|
|
|
if ( !size && (Flags & (_op_CLSBEG_ | _OP_NOSIGN)) == _op_CLSBEG_ )
|
|
Flags |= _OP_ONECLS;
|
|
Flags &= ~_op_isTAG_;
|
|
|
|
if ( sgnlev == 1 && (Flags & _op_INPRSIG_) ) // parse <...:...>
|
|
{
|
|
if ( size < 4 )
|
|
goto only_string; // >Lx; or >( )V
|
|
switch ( po[1] )
|
|
{
|
|
default:
|
|
Flags |= _op_MUSTNAM_; // next substitution
|
|
continue;
|
|
case j_tag:
|
|
goto only_string;
|
|
case j_endsign: // end of <...:...>
|
|
break;
|
|
}
|
|
++po; // skip ';'
|
|
--size; // balance next '>'
|
|
sgnlev = 0;
|
|
Flags &= ~_op_INPRSIG_;
|
|
if ( po[1] != j_parm_list_start )
|
|
goto only_tag; // superclass{ifaces}
|
|
++po; // skip '>' (go=> before do-while)
|
|
off_ThrowsSignature_and_TypeSignature = (uint32)(po - tsPtr);
|
|
goto to_func;
|
|
} // end resolve end of <...:...>
|
|
|
|
if ( sgnlev )
|
|
{
|
|
if ( po[1] == j_endsign )
|
|
continue;
|
|
if ( size > 2 )
|
|
goto only_tag; // Lx;
|
|
goto only_string;
|
|
}
|
|
Flags |= _OP_FULLNM;
|
|
// class name can be full qualified array :(
|
|
if ( (Flags&(_op_ISARRAY_|_op_PARAM_|_op_RETTYPE_)) != _op_ISARRAY_ )
|
|
{
|
|
if ( Flags & _OP_NOSIGN )
|
|
goto only_string; // speed only
|
|
Flags |= _OP_NOFNM;
|
|
}
|
|
if ( Flags & (_op_RETTYPE_ | _op_PRIMSIG_) )
|
|
{
|
|
Flags &= ~_op_FRSPRM_;
|
|
if ( Flags & _op_RETTYPE_ )
|
|
goto check_throw;
|
|
}
|
|
continue;
|
|
} // switch ( specchar ) FULLNM
|
|
norm_char:
|
|
if ( Flags & (_OP_NOSIGN | _op_MUSTNAM_ | _op_NAME_) )
|
|
continue;
|
|
|
|
if ( Flags & _op_isTAG_ )
|
|
{
|
|
Flags |= _op_NAME_;
|
|
continue;
|
|
}
|
|
if ( sgnlev )
|
|
continue;
|
|
|
|
if ( Flags & _op_PAREND_ )
|
|
{
|
|
off_ReturnType = (uint32)(po - tsPtr);
|
|
Flags &= ~(_op_PAREND_ | _op_FRSPRM_);
|
|
Flags |= _op_RETTYPE_;
|
|
if ( cs == j_void_ret )
|
|
goto check_throw;
|
|
}
|
|
|
|
// chkdscr
|
|
if ( (Flags & (_op_PARAM_ | _op_FRSPRM_)) == _op_FRSPRM_ )
|
|
goto nodscsg;
|
|
|
|
if ( cs == j_array )
|
|
{
|
|
Flags |= _op_ARRAY_ | _op_ISARRAY_;
|
|
continue;
|
|
}
|
|
|
|
Flags = (Flags & ~_op_ARRAY_) | _op_FRSPRM_;
|
|
switch ( cs )
|
|
{
|
|
case j_class: // 'L'
|
|
Flags |= _op_CLSBEG_;
|
|
continue;
|
|
case j_typeref: // 'T'
|
|
Flags |= _op_TYPBEG_;
|
|
continue;
|
|
default:
|
|
break;
|
|
}
|
|
if ( !cs || get_base_typename(cs) == NULL )
|
|
{
|
|
nodscsg:
|
|
if ( Flags & (_OP_FULLNM | _op_RETTYPE_) )
|
|
goto only_string;
|
|
Flags |= _OP_NODSCR | _OP_NOSIGN;
|
|
}
|
|
else if ( Flags & _op_RETTYPE_ )
|
|
{
|
|
check_throw:
|
|
if ( !size )
|
|
break;
|
|
if ( size < 4 || po[1] != j_throw )
|
|
goto only_string; // ^Lx;
|
|
Flags |= _OP_FULLNM | _OP_NOFNM | _OP_NODSCR;
|
|
++po; // skip rettype/previous-';'
|
|
--size;
|
|
if ( off_ThrowsSignature_and_TypeSignature < 0x10000 )
|
|
off_ThrowsSignature_and_TypeSignature |= ((uint32)(po - tsPtr) << 16);
|
|
only_tag:
|
|
--size;
|
|
++po;
|
|
skipped_only_tag:
|
|
switch ( *po )
|
|
{
|
|
default:
|
|
goto only_string;
|
|
case j_class: // never set CLSBEG (no ONECLS)
|
|
case j_typeref:
|
|
Flags |= _op_TYPBEG_;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
while ( ++po, size );
|
|
|
|
if ( (Flags & (_op_PARAM_ | _op_PAREND_ | _op_ARRAY_)) || sgnlev )
|
|
{
|
|
only_string:
|
|
Flags |= (_OP_NODSCR | _OP_NOSIGN | _OP_NOFNM | _OP_FULLNM);
|
|
}
|
|
else
|
|
{
|
|
if ( Flags & (_op_CLSBEG_ | _op_TYPBEG_) )
|
|
{
|
|
Flags |= _OP_NODSCR | _OP_NOSIGN;
|
|
}
|
|
else if ( !(Flags & _OP_NOSIGN) )
|
|
{
|
|
if ( off_ReturnType )
|
|
{
|
|
Flags |= _OP_VALPOS;
|
|
if ( off_ThrowsSignature_and_TypeSignature )
|
|
Flags |= _OP_METSIGN;
|
|
}
|
|
else if ( off_ThrowsSignature_and_TypeSignature )
|
|
{
|
|
Flags |= _OP_CLSSIGN;
|
|
}
|
|
}
|
|
// check for reserved words
|
|
if ( !(Flags & _OP_NOWORD) )
|
|
ResW_validate((uint32 *)&Flags, po);
|
|
}
|
|
if ( (ushort)Flags )
|
|
{
|
|
SET_FLAGS: // <init>/<cinit>/V nor reserved :)
|
|
uint32 ind = ((uint32)index) << 16;
|
|
co->_Sflags |= (ushort)Flags;
|
|
ConstantNode.altset(ind, co->_Sopstr);
|
|
CASSERT(_OP_VALPOS < 0x10000u);
|
|
if ( Flags & _OP_VALPOS )
|
|
{
|
|
ConstantNode.altset(ind+1, off_ReturnType);
|
|
if ( Flags & _OP_METSIGN )
|
|
ConstantNode.altset(ind+2, off_ThrowsSignature_and_TypeSignature);
|
|
if ( !(Flags & _OP_NODSCR) )
|
|
co->flag |= HAS_CALLDSCR;
|
|
return;
|
|
}
|
|
}
|
|
|
|
cs = 0;
|
|
if ( !(Flags & _OP_NODSCR) )
|
|
cs |= HAS_TYPEDSCR;
|
|
if ( !(Flags & _OP_NOFNM) )
|
|
cs |= HAS_CLSNAME;
|
|
if ( !(Flags & _OP_FULLNM) )
|
|
cs |= HAS_FLDNAME;
|
|
co->flag |= cs;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
//---------------------------------------------------------------------------
|
|
// generated by JDK1.5 (checked with beta of 1.6) -- previously version have
|
|
// some 'skipped' letters(?). See 'addonces\jvunigen.cpp' (and move headers)
|
|
uchar javaIdent(ushort v, uchar *isStart)
|
|
{
|
|
static const uchar cpchtb[256] =
|
|
{
|
|
2, 3, 4, 5, 6, 7, 8, 9, 0, 10, 11, 12, 13, 14, 15, 16,
|
|
17, 18, 19, 20, 21, 3, 22, 23, 24, 25, 0, 0, 0, 26, 27, 28,
|
|
29, 30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
31, 32, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
|
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 33, 3, 3,
|
|
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
|
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
|
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
|
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
|
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 34,
|
|
3, 3, 3, 3, 35, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3,
|
|
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
|
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
|
3, 3, 3, 3, 3, 3, 3, 36, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 37, 38, 3, 39, 40, 41 };
|
|
|
|
static const uchar idxtb[42][32] =
|
|
{
|
|
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
|
|
{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
|
|
{ 0, 0, 0, 0, 1, 0,192,215, 38, 26, 26, 49, 38, 26, 26, 86,
|
|
0, 0, 0, 0, 2, 3,111, 3, 26, 26,110, 26, 26, 26,110, 26 },
|
|
{ 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
|
|
26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26 },
|
|
{ 26, 26, 26, 26, 26, 26,110, 0, 0, 0, 26, 26, 26, 26, 26, 26,
|
|
26, 26, 26, 26, 26, 26, 26, 26, 28, 26, 37, 0, 40, 83, 0, 0 },
|
|
{ 192,192,192,192,192,192,192,192,192,192,192,222,192,192, 0, 3,
|
|
83, 4, 26, 26, 65, 26, 26, 26, 26,110, 26, 26, 26, 26, 71, 55 },
|
|
{ 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
|
|
155, 5, 26, 26, 26, 26, 26, 26, 26,110, 26, 26, 26, 26, 96, 37 },
|
|
{ 26, 26, 0, 0, 0, 0, 38, 26, 26, 26,110, 97, 38, 26, 26, 26,
|
|
26, 0,217,192,193,192,192,194,195, 0, 26, 26, 26, 86, 86, 0 },
|
|
{ 0, 0,224, 0, 38, 26, 26, 86, 26,154,192,228,192,156,157, 26,
|
|
26, 26, 26, 26, 26, 26, 26, 26, 26, 26,158,196,159,160,192,191 },
|
|
{ 0, 0,190, 26, 26, 26,192,192,192,163, 0, 0, 0, 0, 0, 0,
|
|
26, 26, 26, 26,164,192,165, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
|
|
{ 166, 26, 26, 26, 26, 26, 26,189,192,224,168, 26,169,192, 0, 0,
|
|
170, 63, 6, 26, 26, 32, 7,189,196,197,237, 8,169,192, 55, 0 },
|
|
{ 170, 49, 6, 26, 26, 32, 9,171,198,197, 0, 10,216,192,172, 0,
|
|
170, 71, 65, 26, 26, 32, 11,189,199,200,100, 0,169,192, 97, 0 },
|
|
{ 170, 63, 6, 26, 26, 32, 11,189,201,197,216, 8,173,192, 97, 0,
|
|
188, 74, 75, 12,108, 74, 71,173,202,203,237, 0,237,192, 0, 97 },
|
|
{ 170, 76, 32, 26, 26, 32, 30,173,204,203,219, 0,173,192, 0, 0,
|
|
175, 76, 32, 26, 26, 32, 30,189,204,203,219, 83,173,192, 0, 0 },
|
|
{ 175, 76, 32, 26, 26, 32, 26,173,205,203,237, 0,173,192, 0, 0,
|
|
175, 26,110, 5, 26, 26, 65, 90,110,206,207,192, 0, 0,208, 0 },
|
|
{ 38, 26, 26, 26, 26, 26,187,177,178,238,192,215, 0, 0, 0, 0,
|
|
13, 14, 98, 38, 15, 47,187,179, 79,224,192,186, 0, 0, 0, 0 },
|
|
{ 100, 0, 0,215,192,215,221,209, 26, 38, 26, 26, 26, 86,217,192,
|
|
204, 55,192,217,192,192,192,210,211, 0, 0, 0, 0, 0, 0, 0 },
|
|
{ 26, 26, 26, 26, 65,185,202,215,192,215,164,215, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 26, 26, 26, 26, 96, 0, 26, 26, 26, 26, 26,100 },
|
|
{ 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 16, 26, 26, 26, 26,
|
|
26, 26, 26, 26, 86, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 37 },
|
|
{ 110, 26, 26, 26, 26, 26, 26, 26,110, 75,110, 75, 26, 26, 26, 26,
|
|
110, 75, 26, 26, 26,110, 75,110, 75,110,110, 26, 26,110, 26, 26 },
|
|
{ 26,110, 75,110, 26, 26, 26, 26,110, 26, 26, 86, 0,217,215, 0,
|
|
0, 0, 0, 0, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 40, 0 },
|
|
{ 38, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
|
|
26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26 },
|
|
{ 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 63,110, 0,
|
|
38, 26, 26, 86, 26, 26, 26, 26, 26, 26, 26, 26, 26, 74,100, 0 },
|
|
{ 26, 76,182, 0, 26, 26,182, 0, 26, 26,183, 0, 26, 76,184, 0,
|
|
26, 26, 26, 26, 26, 26,181,192,192,192,180,176,192,215, 0, 0 },
|
|
{ 0,212,192,215, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 0,
|
|
26, 26, 26, 26, 26,174, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
|
|
{ 26, 26, 26, 40,192,241,192,241,216,192, 26, 26, 26, 96, 40, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
|
|
{ 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 55, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
|
|
{ 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
|
|
26, 26, 26, 55, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 37 },
|
|
{ 26, 26, 96, 96, 26, 26, 26, 26, 96, 96, 26, 17, 26, 26, 26, 96,
|
|
26, 26, 26, 26, 26, 26, 76, 79, 18, 40, 41, 55, 26, 40, 18, 40 },
|
|
{ 0, 0, 0, 0, 0, 0, 0,109,100, 0, 1, 0, 0, 0, 97,109,
|
|
0, 0, 0, 0, 26, 26, 37, 0, 0, 0,192,210,213,214, 0, 0 },
|
|
{ 78, 5, 90, 19, 20, 21, 65, 22, 33, 37, 0, 0, 26, 26, 26, 26,
|
|
55, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
|
|
{ 33, 0, 0, 0, 38,167, 19, 40, 38, 26, 26, 26, 26, 26, 26, 26,
|
|
26, 26,110,162, 38, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26 },
|
|
{ 33, 26, 26, 26, 26, 40, 38, 26, 26, 26, 26, 26, 26, 26, 26, 26,
|
|
26,110, 0, 0, 26, 26, 26, 0, 0, 0, 0, 0, 0, 0, 26, 26 },
|
|
{ 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
|
|
26, 26, 26, 26, 26, 26, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
|
|
{ 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
|
|
26, 26, 26, 26, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
|
|
{ 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
|
|
26, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
|
|
{ 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
|
|
26, 26, 26, 26, 55, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
|
|
{ 26, 26, 26, 26, 26, 96, 26, 26, 26, 26, 26, 26, 26, 86, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
|
|
{ 110, 0, 23,161, 26, 32,110, 79, 24, 26, 26, 26, 26, 26, 26, 26,
|
|
26, 26, 26, 26, 26, 26, 37, 0, 0, 0, 23, 26, 26, 26, 26, 26 },
|
|
{ 26, 26, 26, 26, 26, 26, 26, 96, 0, 0, 26, 26, 26, 26, 26, 26,
|
|
26, 26, 5, 26, 26, 26, 26, 26, 26, 0, 0, 0, 0, 0, 26, 40 },
|
|
{ 192,192, 0, 0,241, 0,108, 0, 0, 33, 0, 0, 0, 97, 76, 26,
|
|
26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 40 },
|
|
{ 1, 0,192,215, 38, 26, 26, 49, 38, 26, 26, 86, 33, 26, 26, 26,
|
|
26, 26, 26, 26, 26, 26, 26,110, 5, 5, 5,104, 25, 0, 0, 0 }
|
|
};
|
|
|
|
static const uchar bittb[124] =
|
|
{
|
|
0x00, 0x10, 0x3C, 0x04, 0xD7, 0xFC, 0xF9, 0xC5, 0xB0, 0x6D, 0x5E, 0xED,
|
|
0xD6, 0x96, 0x25, 0xAE, 0x83, 0xAA, 0xDC, 0x3E, 0x50, 0xBD, 0xE3, 0xF8,
|
|
0xDB, 0x63, 0xFF, 0x7B, 0xC3, 0xFF, 0xEF, 0xFF, 0xFD, 0xE0, 0xE6, 0xE7,
|
|
0xFF, 0x03, 0xFE, 0xFF, 0x1F, 0xCF, 0xEE, 0xD3, 0x1F, 0xC3, 0x03, 0xEC,
|
|
0x38, 0x87, 0xFF, 0x3B, 0x8F, 0xCF, 0x1F, 0x0F, 0x0D, 0xF6, 0x33, 0xFF,
|
|
0xEC, 0xF3, 0xFF, 0x9F, 0xFF, 0xFB, 0xBB, 0x16, 0x9F, 0x39, 0x87, 0xBF,
|
|
0x3B, 0x8F, 0xC7, 0x3D, 0xDF, 0xCF, 0x84, 0x5F, 0x0C, 0xC2, 0x1F, 0x40,
|
|
0x38, 0xE2, 0x07, 0x03, 0xC0, 0xFE, 0x2F, 0x60, 0xC0, 0xA0, 0xE0, 0xE0,
|
|
0x3F, 0x02, 0xF0, 0x03, 0x01, 0x03, 0xE0, 0x03, 0x1C, 0x03, 0x01, 0xE0,
|
|
0x18, 0x80, 0x7F, 0x20, 0x80, 0x0F, 0x03, 0x03, 0x01, 0x06, 0x30, 0x0D,
|
|
0xE8, 0x23, 0xFD, 0x9C
|
|
};
|
|
|
|
uint ind = idxtb[cpchtb[v >> 8]][(((uchar)v) >> 3) & 31];
|
|
uchar bit = uchar(1 << (v & 7));
|
|
|
|
if ( !(bittb[ind & 0x7F] & bit) )
|
|
return 0;
|
|
if ( isStart )
|
|
*isStart = (!(ind & 0x80)
|
|
|| (!(ind & 0x40) && (bittb[ind - 68] & bit)));
|
|
return 1;
|
|
}
|
|
|