Converted StringManager to use vectors

This commit is contained in:
caheckman 2020-04-20 17:31:02 -04:00
parent 0eb48e441f
commit 1529e635fc
11 changed files with 161 additions and 111 deletions

View file

@ -19,6 +19,7 @@
#include "ghidra_translate.hh" #include "ghidra_translate.hh"
#include "typegrp_ghidra.hh" #include "typegrp_ghidra.hh"
#include "comment_ghidra.hh" #include "comment_ghidra.hh"
#include "string_ghidra.hh"
#include "cpool_ghidra.hh" #include "cpool_ghidra.hh"
#include "inject_ghidra.hh" #include "inject_ghidra.hh"
@ -346,6 +347,12 @@ void ArchitectureGhidra::buildCommentDB(DocumentStorage &store)
commentdb = new CommentDatabaseGhidra(this); commentdb = new CommentDatabaseGhidra(this);
} }
void ArchitectureGhidra::buildStringManager(DocumentStorage &store)
{
stringManager = new GhidraStringManager(this,2048);
}
void ArchitectureGhidra::buildConstantPool(DocumentStorage &store) void ArchitectureGhidra::buildConstantPool(DocumentStorage &store)
{ {
@ -615,7 +622,7 @@ void ArchitectureGhidra::getBytes(uint1 *buf,int4 size,const Address &inaddr)
readResponseEnd(sin); readResponseEnd(sin);
} }
uint4 ArchitectureGhidra::getStringData(uint1 *buf,const Address &addr,Datatype *ct,int4 maxBytes) void ArchitectureGhidra::getStringData(vector<uint1> &buffer,const Address &addr,Datatype *ct,int4 maxBytes)
{ {
sout.write("\000\000\001\004",4); sout.write("\000\000\001\004",4);
@ -633,32 +640,28 @@ uint4 ArchitectureGhidra::getStringData(uint1 *buf,const Address &addr,Datatype
readToResponse(sin); readToResponse(sin);
int4 type = readToAnyBurst(sin); int4 type = readToAnyBurst(sin);
uint4 size = 0;
if (type == 12) { if (type == 12) {
int4 c = sin.get(); int4 c = sin.get();
size ^= (c-0x20); uint4 size = (c-0x20);
c = sin.get(); c = sin.get();
size ^= ((c-0x20)<<6); size ^= ((c-0x20)<<6);
buffer.reserve(size);
uint1 *dblbuf = new uint1[size * 2]; uint1 *dblbuf = new uint1[size * 2];
sin.read((char *)dblbuf,size*2); sin.read((char *)dblbuf,size*2);
for (int4 i=0; i < size; i++) { for (int4 i=0; i < size; i++) {
buf[i] = ((dblbuf[i*2]-'A') << 4) | (dblbuf[i*2 + 1]-'A'); buffer.push_back(((dblbuf[i*2]-'A') << 4) | (dblbuf[i*2 + 1]-'A'));
} }
delete [] dblbuf; delete [] dblbuf;
type = readToAnyBurst(sin);
if (type != 13)
throw JavaError("alignment","Expecting byte alignment end");
type = readToAnyBurst(sin);
} }
else if ((type&1)==1) { if ((type&1)==1) {
ostringstream errmsg; // Leave the buffer empty
errmsg << "GHIDRA has no string in the loadimage at " << addr.getShortcut();
addr.printRaw(errmsg);
throw DataUnavailError(errmsg.str());
} }
else else
throw JavaError("alignment","Expecting bytes or end of query response"); throw JavaError("alignment","Expecting end of query response");
type = readToAnyBurst(sin);
if (type != 13)
throw JavaError("alignment","Expecting byte alignment end");
readResponseEnd(sin);
return size;
} }
/// \brief Retrieve p-code to inject for a specific context /// \brief Retrieve p-code to inject for a specific context

View file

@ -74,6 +74,7 @@ class ArchitectureGhidra : public Architecture {
virtual PcodeInjectLibrary *buildPcodeInjectLibrary(void); virtual PcodeInjectLibrary *buildPcodeInjectLibrary(void);
virtual void buildTypegrp(DocumentStorage &store); virtual void buildTypegrp(DocumentStorage &store);
virtual void buildCommentDB(DocumentStorage &store); virtual void buildCommentDB(DocumentStorage &store);
virtual void buildStringManager(DocumentStorage &store);
virtual void buildConstantPool(DocumentStorage &store); virtual void buildConstantPool(DocumentStorage &store);
virtual void buildContext(DocumentStorage &store); virtual void buildContext(DocumentStorage &store);
virtual void buildSpecFile(DocumentStorage &store); virtual void buildSpecFile(DocumentStorage &store);
@ -124,7 +125,7 @@ public:
bool getSendParamMeasures(void) const { return sendParamMeasures; } ///< Get the current setting for emitting parameter info bool getSendParamMeasures(void) const { return sendParamMeasures; } ///< Get the current setting for emitting parameter info
virtual uint4 getStringData(uint1 *buf,const Address &addr,Datatype *ct,int4 maxBytes); virtual void getStringData(vector<uint1> &buffer,const Address &addr,Datatype *ct,int4 maxBytes);
virtual void printMessage(const string &message) const; virtual void printMessage(const string &message) const;
static void segvHandler(int4 sig); ///< Handler for a segment violation (SIGSEGV) signal static void segvHandler(int4 sig); ///< Handler for a segment violation (SIGSEGV) signal

View file

@ -127,6 +127,7 @@ void IfaceDecompCapability::registerCommands(IfaceStatus *status)
status->registerCom(new IfcCallFixup(),"fixup","call"); status->registerCom(new IfcCallFixup(),"fixup","call");
status->registerCom(new IfcCallOtherFixup(),"fixup","callother"); status->registerCom(new IfcCallOtherFixup(),"fixup","callother");
status->registerCom(new IfcVolatile(),"volatile"); status->registerCom(new IfcVolatile(),"volatile");
status->registerCom(new IfcReadonly(),"readonly");
status->registerCom(new IfcPreferSplit(),"prefersplit"); status->registerCom(new IfcPreferSplit(),"prefersplit");
status->registerCom(new IfcStructureBlocks(),"structure","blocks"); status->registerCom(new IfcStructureBlocks(),"structure","blocks");
status->registerCom(new IfcAnalyzeRange(), "analyze","range"); status->registerCom(new IfcAnalyzeRange(), "analyze","range");
@ -2304,6 +2305,22 @@ void IfcVolatile::execute(istream &s)
*status->optr << "Successfully marked range as volatile" << endl; *status->optr << "Successfully marked range as volatile" << endl;
} }
void IfcReadonly::execute(istream &s)
{
int4 size = 0;
if (dcp->conf == (Architecture *)0)
throw IfaceExecutionError("No load image present");
Address addr = parse_machaddr(s,size,*dcp->conf->types); // Read required address
if (size == 0)
throw IfaceExecutionError("Must specify a size");
Range range( addr.getSpace(), addr.getOffset(), addr.getOffset() + (size-1));
dcp->conf->symboltab->setPropertyRange(Varnode::readonly,range);
*status->optr << "Successfully marked range as readonly" << endl;
}
void IfcPreferSplit::execute(istream &s) void IfcPreferSplit::execute(istream &s)
{ // Mark a particular storage location as something we would prefer to split { // Mark a particular storage location as something we would prefer to split

View file

@ -531,6 +531,11 @@ public:
virtual void execute(istream &s); virtual void execute(istream &s);
}; };
class IfcReadonly : public IfaceDecompCommand {
public:
virtual void execute(istream &s);
};
class IfcPreferSplit : public IfaceDecompCommand { class IfcPreferSplit : public IfaceDecompCommand {
public: public:
virtual void execute(istream &s); virtual void execute(istream &s);

View file

@ -1216,20 +1216,23 @@ bool PrintC::doEmitWideCharPrefix(void) const
bool PrintC::printCharacterConstant(ostream &s,const Address &addr,Datatype *charType) const bool PrintC::printCharacterConstant(ostream &s,const Address &addr,Datatype *charType) const
{ {
const uint1 *buffer;
StringManager *manager = glb->stringManager; StringManager *manager = glb->stringManager;
try {
buffer = manager->getStringData(addr, charType); // Retrieve UTF8 version of string
} catch(DataUnavailError &err) { const vector<uint1> &buffer(manager->getStringData(addr, charType));
if (buffer.empty())
return false; return false;
}
if (doEmitWideCharPrefix() && charType->getSize() > 1) if (doEmitWideCharPrefix() && charType->getSize() > 1)
s << 'L'; // Print symbol indicating wide character s << 'L'; // Print symbol indicating wide character
s << '"'; s << '"';
if (!escapeCharacterData(s,buffer,manager->getMaximumBytes(),charType->getSize(),glb->translate->isBigEndian())) if (!escapeCharacterData(s,buffer.data(),buffer.size(),1,glb->translate->isBigEndian()))
s << "...\" /* TRUNCATED STRING LITERAL */"; s << "...\" /* TRUNCATED STRING LITERAL */";
else else {
s << '"'; if (buffer.size() > manager->getMaximumBytes())
s << "...\" /* TRUNCATED STRING LITERAL */";
else
s << '"';
}
return true; return true;
} }

View file

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
#include "ghidra_string.hh" #include "string_ghidra.hh"
GhidraStringManager::GhidraStringManager(ArchitectureGhidra *g,int4 max) GhidraStringManager::GhidraStringManager(ArchitectureGhidra *g,int4 max)
: StringManager(max) : StringManager(max)
@ -28,14 +28,15 @@ GhidraStringManager::~GhidraStringManager(void)
delete [] testBuffer; delete [] testBuffer;
} }
const uint1 *GhidraStringManager::getStringData(const Address &addr,Datatype *charType) const vector<uint1> &GhidraStringManager::getStringData(const Address &addr,Datatype *charType)
{ {
map<Address,const uint1 *>::iterator iter; map<Address,vector<uint1> >::iterator iter;
iter = stringMap.find(addr); iter = stringMap.find(addr);
if (iter != stringMap.end()) if (iter != stringMap.end())
return (*iter).second; return (*iter).second;
int4 size = glb->getStringData(testBuffer, addr, charType, maximumBytes); vector<uint1> &buffer(stringMap[addr]);
return mapBuffer(addr, testBuffer, size); glb->getStringData(buffer, addr, charType, maximumBytes);
return buffer;
} }

View file

@ -33,7 +33,7 @@ class GhidraStringManager : public StringManager {
public: public:
GhidraStringManager(ArchitectureGhidra *g,int4 max); ///< Constructor GhidraStringManager(ArchitectureGhidra *g,int4 max); ///< Constructor
virtual ~GhidraStringManager(void); virtual ~GhidraStringManager(void);
virtual const uint1 *getStringData(const Address &addr,Datatype *charType); virtual const vector<uint1> &getStringData(const Address &addr,Datatype *charType);
}; };
#endif #endif

View file

@ -16,21 +16,6 @@
#include "stringmanage.hh" #include "stringmanage.hh"
#include "architecture.hh" #include "architecture.hh"
/// Before calling, we must check that there is no other buffer stored at the address.
/// \param addr is the Address to store the buffer at
/// \param buf is the buffer to be copied into storage
/// \param size is the number of bytes in the buffer
/// \return the new permanent copy of the buffer
const uint1 *StringManager::mapBuffer(const Address &addr,const uint1 *buf,int4 size)
{
uint1 *storeBuf = new uint1[size + 1];
stringMap[addr] = storeBuf;
memcpy(storeBuf,buf,size);
storeBuf[size] = 0;
return storeBuf;
}
/// \param max is the maximum number of bytes to allow in a decoded string /// \param max is the maximum number of bytes to allow in a decoded string
StringManager::StringManager(int4 max) StringManager::StringManager(int4 max)
@ -44,16 +29,6 @@ StringManager::~StringManager(void)
clear(); clear();
} }
void StringManager::clear(void)
{
map<Address,const uint1 *>::iterator iter;
for(iter=stringMap.begin();iter!=stringMap.end();++iter) {
delete [] (*iter).second;
}
}
/// Encode the given unicode codepoint as UTF8 (1, 2, 3, or 4 bytes) and /// Encode the given unicode codepoint as UTF8 (1, 2, 3, or 4 bytes) and
/// write the bytes to the stream. /// write the bytes to the stream.
/// \param s is the output stream /// \param s is the output stream
@ -103,14 +78,8 @@ void StringManager::writeUtf8(ostream &s,int4 codepoint)
bool StringManager::isString(const Address &addr,Datatype *charType) bool StringManager::isString(const Address &addr,Datatype *charType)
{ {
const uint1 *buffer = (const uint1 *)0; const vector<uint1> &buffer(getStringData(addr,charType));
try { return !buffer.empty();
buffer = getStringData(addr,charType);
}
catch(DataUnavailError &err) {
return false;
}
return (buffer != (const uint1 *)0);
} }
/// Write \<stringmanage> tag, with \<string> sub-tags. /// Write \<stringmanage> tag, with \<string> sub-tags.
@ -120,15 +89,14 @@ void StringManager::saveXml(ostream &s) const
{ {
s << "<stringmanage>\n"; s << "<stringmanage>\n";
map<Address,const uint1 *>::const_iterator iter1; map<Address,vector<uint1> >::const_iterator iter1;
for(iter1=stringMap.begin();iter1!=stringMap.end();++iter1) { for(iter1=stringMap.begin();iter1!=stringMap.end();++iter1) {
s << "<string>\n"; s << "<string>\n";
(*iter1).first.saveXml(s); (*iter1).first.saveXml(s);
const uint1 *buf = (*iter1).second; const vector<uint1> &vec( (*iter1).second );
s << " <bytes>\n" << setfill('0'); s << " <bytes>\n" << setfill('0');
for(int4 i=0;;++i) { for(int4 i=0;vec.size();++i) {
if (buf[i] == 0) break; s << hex << setw(2) << (int4)vec[i];
s << hex << setw(2) << (int4)buf[i];
if (i%20 == 19) if (i%20 == 19)
s << "\n "; s << "\n ";
} }
@ -148,7 +116,7 @@ void StringManager::restoreXml(const Element *el,const AddrSpaceManager *m)
iter = list.begin(); iter = list.begin();
Address addr = Address::restoreXml(*iter, m); Address addr = Address::restoreXml(*iter, m);
++iter; ++iter;
vector<uint1> vec; vector<uint1> &vec(stringMap[addr]);
istringstream is((*iter)->getContent()); istringstream is((*iter)->getContent());
int4 val; int4 val;
char c1, c2; char c1, c2;
@ -174,7 +142,6 @@ void StringManager::restoreXml(const Element *el,const AddrSpaceManager *m)
c1 = is.get(); c1 = is.get();
c2 = is.get(); c2 = is.get();
} }
mapBuffer(addr,vec.data(),vec.size());
} }
/// \param buffer is the byte buffer /// \param buffer is the byte buffer
@ -300,49 +267,61 @@ StringManagerUnicode::~StringManagerUnicode(void)
delete [] testBuffer; delete [] testBuffer;
} }
const uint1 *StringManagerUnicode::getStringData(const Address &addr,Datatype *charType) const vector<uint1> &StringManagerUnicode::getStringData(const Address &addr,Datatype *charType)
{ {
map<Address,const uint1 *>::iterator iter; map<Address,vector<uint1> >::iterator iter;
iter = stringMap.find(addr); iter = stringMap.find(addr);
if (iter != stringMap.end()) if (iter != stringMap.end())
return (*iter).second; return (*iter).second;
vector<uint1> &vec(stringMap[addr]); // Allocate (initially empty) byte vector
int4 curBufferSize = 0; int4 curBufferSize = 0;
int4 charsize = charType->getSize(); int4 charsize = charType->getSize();
bool foundTerminator = false; bool foundTerminator = false;
do { try {
int4 amount = 32; // Grab 32 bytes of image at a time do {
uint4 newBufferSize = curBufferSize + amount; int4 amount = 32; // Grab 32 bytes of image at a time
if (newBufferSize > maximumBytes) { uint4 newBufferSize = curBufferSize + amount;
newBufferSize = maximumBytes; if (newBufferSize > maximumBytes) {
amount = newBufferSize - curBufferSize; newBufferSize = maximumBytes;
if (amount == 0) break; amount = newBufferSize - curBufferSize;
} if (amount == 0)
glb->loader->loadFill(testBuffer+curBufferSize,amount,addr + curBufferSize); break;
foundTerminator = hasCharTerminator(testBuffer+curBufferSize,amount,charsize); }
curBufferSize = newBufferSize; glb->loader->loadFill(testBuffer + curBufferSize, amount,
} while (!foundTerminator); addr + curBufferSize);
foundTerminator = hasCharTerminator(testBuffer + curBufferSize, amount,
charsize);
curBufferSize = newBufferSize;
} while (!foundTerminator);
} catch (DataUnavailError &err) {
return vec; // Return the empty buffer
}
const uint1 *resBuffer;
if (charsize == 1) { if (charsize == 1) {
if (!isCharacterConstant(testBuffer,curBufferSize,charsize)) if (!isCharacterConstant(testBuffer,curBufferSize,charsize))
return (const uint1 *)0; return vec; // Return the empty buffer
resBuffer = mapBuffer(addr,testBuffer,curBufferSize); vec.reserve(curBufferSize);
vec.assign(testBuffer,testBuffer+curBufferSize);
} }
else { else {
// We need to translate to UTF8 // We need to translate to UTF8
ostringstream s; ostringstream s;
if (!writeUnicode(s, testBuffer, curBufferSize, charsize)) if (!writeUnicode(s, testBuffer, curBufferSize, charsize))
return (const uint1 *)0; return vec; // Return the empty buffer
string resString = s.str(); string resString = s.str();
int4 newSize = resString.size(); int4 newSize = resString.size();
if (newSize > maximumBytes) if (newSize > maximumBytes)
newSize = maximumBytes; newSize = maximumBytes;
resBuffer = mapBuffer(addr,(const uint1 *)resString.c_str(),newSize); vector<uint1> &vec(stringMap[addr]);
vec.reserve(newSize);
const uint1 *ptr = (const uint1 *)resString.c_str();
vec.assign(ptr,ptr+newSize);
} }
return resBuffer; return vec;
} }
/// If the string is encoded in UTF8 or ASCII, we get (on average) a bit of check /// If the string is encoded in UTF8 or ASCII, we get (on average) a bit of check

View file

@ -30,27 +30,25 @@ class Architecture;
/// Stores the decoded string until its needed for presentation. /// Stores the decoded string until its needed for presentation.
class StringManager { class StringManager {
protected: protected:
map<Address,const uint1 *> stringMap; ///< Map from address to string (in UTF8 format) map<Address,vector<uint1> > stringMap; ///< Map from address to string (in UTF8 format)
int4 maximumBytes; ///< Maximum bytes (in UTF8 encoding) allowed int4 maximumBytes; ///< Maximum bytes (in UTF8 encoding) allowed
const uint1 *mapBuffer(const Address &addr,const uint1 *buf,int4 size); ///< Move a decoded buffer into storage
public: public:
StringManager(int4 max); ///< Constructor StringManager(int4 max); ///< Constructor
virtual ~StringManager(void); ///< Destructor virtual ~StringManager(void); ///< Destructor
int4 getMaximumBytes(void) const { return maximumBytes; } ///< Return the maximum bytes allowed in a string decoding int4 getMaximumBytes(void) const { return maximumBytes; } ///< Return the maximum bytes allowed in a string decoding
void clear(void); ///< Clear out any cached strings void clear(void) { stringMap.clear(); } ///< Clear out any cached strings
bool isString(const Address &addr,Datatype *charType); // Determine if data at the given address is a string bool isString(const Address &addr,Datatype *charType); // Determine if data at the given address is a string
/// \brief Retrieve string data at the given address as a UTF8 byte array /// \brief Retrieve string data at the given address as a UTF8 byte array
/// ///
/// If the address does not represent string data, null is returned. Otherwise, /// If the address does not represent string data, a zero length vector is returned. Otherwise,
/// the string data is fetched, converted to a UTF8 encoding, cached and returned. /// the string data is fetched, converted to a UTF8 encoding, cached and returned.
/// \param addr is the given address /// \param addr is the given address
/// \param charType is a character data-type indicating the encoding /// \param charType is a character data-type indicating the encoding
/// \return the byte array of UTF8 data (or null) /// \return the byte array of UTF8 data
virtual const uint1 *getStringData(const Address &addr,Datatype *charType)=0; virtual const vector<uint1> &getStringData(const Address &addr,Datatype *charType)=0;
void saveXml(ostream &s) const; ///< Save cached strings to a stream as XML void saveXml(ostream &s) const; ///< Save cached strings to a stream as XML
void restoreXml(const Element *el,const AddrSpaceManager *m); ///< Restore string cache from XML void restoreXml(const Element *el,const AddrSpaceManager *m); ///< Restore string cache from XML
@ -72,7 +70,7 @@ public:
StringManagerUnicode(Architecture *g,int4 max); ///< Constructor StringManagerUnicode(Architecture *g,int4 max); ///< Constructor
virtual ~StringManagerUnicode(void); virtual ~StringManagerUnicode(void);
virtual const uint1 *getStringData(const Address &addr,Datatype *charType); virtual const vector<uint1> &getStringData(const Address &addr,Datatype *charType);
bool isCharacterConstant(const uint1 *buf,int4 size,int4 charsize) const; ///< Return \b true if buffer looks like unicode bool isCharacterConstant(const uint1 *buf,int4 size,int4 charsize) const; ///< Return \b true if buffer looks like unicode
bool writeUnicode(ostream &s,uint1 *buffer,int4 size,int4 charsize); ///< Write unicode byte array to stream (as UTF8) bool writeUnicode(ostream &s,uint1 *buffer,int4 size,int4 charsize); ///< Write unicode byte array to stream (as UTF8)
}; };

View file

@ -1181,6 +1181,35 @@ public class DecompileCallback {
return listing.getFunctionAt(addr); return listing.getFunctionAt(addr);
} }
/**
* Return true if there are no "replacement" characters in the string
* @param string is the string to test
* @return true if no replacements
*/
private boolean isValidChars(String string) {
char replaceChar = '\ufffd';
for (int i = 0; i < string.length(); ++i) {
char c = string.charAt(i);
if (c == replaceChar) {
return false;
}
}
return true;
}
/**
* Check for a string at an address and return a UTF8 encoded byte array.
* If there is already data present at the address, use this to determine the
* string encoding. Otherwise use the data-type info passed in to determine the encoding.
* Check that the bytes at the address represent a valid string encoding that doesn't
* exceed the maximum byte limit passed in. Return null if the string is invalid.
* Return the string translated into a UTF8 byte array otherwise. A (valid) empty
* string is returned as a zero length array.
* @param addrString is the XML encoded address and maximum byte limit
* @param dtName is the name of a character data-type
* @param dtId is the id associated with the character data-type
* @return the UTF8 encoded byte array or null
*/
public byte[] getStringData(String addrString, String dtName, String dtId) { public byte[] getStringData(String addrString, String dtName, String dtId) {
Address addr; Address addr;
int maxBytes; int maxBytes;
@ -1199,9 +1228,21 @@ public class DecompileCallback {
Settings settings = SettingsImpl.NO_SETTINGS; Settings settings = SettingsImpl.NO_SETTINGS;
AbstractStringDataType dataType = null; AbstractStringDataType dataType = null;
if (data != null) { if (data != null) {
settings = data;
if (data.getDataType() instanceof AbstractStringDataType) { if (data.getDataType() instanceof AbstractStringDataType) {
settings = data;
dataType = (AbstractStringDataType) data.getDataType(); dataType = (AbstractStringDataType) data.getDataType();
int len = data.getLength();
if (len > 0) {
long diff = addr.subtract(data.getAddress()) *
addr.getAddressSpace().getAddressableUnitSize();
if (diff < 0 || diff >= len) {
return null;
}
len -= diff;
if (len < maxBytes) {
maxBytes = len;
}
}
} }
} }
if (dataType == null) { if (dataType == null) {
@ -1228,17 +1269,17 @@ public class DecompileCallback {
} }
} }
MemoryBufferImpl buf = new MemoryBufferImpl(program.getMemory(), addr, 64); MemoryBufferImpl buf = new MemoryBufferImpl(program.getMemory(), addr, 64);
Object value = dataType.getValue(buf, settings, maxBytes); StringDataInstance stringInstance = dataType.getStringDataInstance(buf, settings, maxBytes);
if (!(value instanceof String)) { int len = stringInstance.getStringLength();
if (len < 0 || len > maxBytes) {
return null; return null;
} }
String stringVal = (String) value;
byte[] res = stringVal.getBytes(utf8Charset); String stringVal = stringInstance.getStringValue();
if (res.length > maxBytes) { if (!isValidChars(stringVal)) {
byte[] trim = new byte[maxBytes]; return null;
System.arraycopy(res, 0, trim, 0, maxBytes);
} }
return res; return stringVal.getBytes(utf8Charset);
} }
//================================================================================================== //==================================================================================================

View file

@ -789,19 +789,21 @@ public class DecompileProcess {
String dtId = readQueryString(); String dtId = readQueryString();
byte[] res = callback.getStringData(addr, dtName, dtId); byte[] res = callback.getStringData(addr, dtName, dtId);
write(query_response_start); write(query_response_start);
if ((res != null) && (res.length > 0)) { if (res != null) {
int sz = res.length; int sz = res.length + 1; // We add a null terminator character
int sz1 = (sz & 0x3f) + 0x20; int sz1 = (sz & 0x3f) + 0x20;
sz >>>= 6; sz >>>= 6;
int sz2 = (sz & 0x3f) + 0x20; int sz2 = (sz & 0x3f) + 0x20;
write(byte_start); write(byte_start);
write(sz1); write(sz1);
write(sz2); write(sz2);
byte[] dblres = new byte[res.length * 2]; byte[] dblres = new byte[res.length * 2 + 2];
for (int i = 0; i < res.length; i++) { for (int i = 0; i < res.length; i++) {
dblres[i * 2] = (byte) (((res[i] >> 4) & 0xf) + 65); dblres[i * 2] = (byte) (((res[i] >> 4) & 0xf) + 65);
dblres[i * 2 + 1] = (byte) ((res[i] & 0xf) + 65); dblres[i * 2 + 1] = (byte) ((res[i] & 0xf) + 65);
} }
dblres[res.length * 2] = 65; // Adding null terminator
dblres[res.length * 2 + 1] = 65;
write(dblres); write(dblres);
write(byte_end); write(byte_end);
} }