通过将以下Delphi代码转换为Java,我遇到了问题。 我在这里发布的代码只是我用来描述我的问题的完整代码的一小部分。
type
TSecureArray = Array of AnsiChar;
const
CodePosIdx = 10;
function ReadLenFromArray(aArray:TSecureArray):integer;
var
HS:integer;
begin
Hs:=0;
HS:=Hs+(ord(aArray[3]))*$1000000;
HS:=Hs+(ord(aArray[4]))*$10000;
HS:=Hs+(ord(aArray[5]))*$100;
HS:=Hs+(ord(aArray[6]));
result:=HS;
end;
function Decrypt(Source: Ansistring): Ansistring;
var
srclen, aArrayLength: integer;
aArray: TSecureArray;
cryptedstring:AnsiString;
begin
aArrayLength:=Length(Source); // length of source-String in my test case is 1046
for i:=1 to aArrayLength do
aArray[i]:=Source[i];
srclen:=ReadLenFromArray(aArray); // function returns 858862149 in my test case
cryptedString:='';
for i:=1 to srclen do
cryptedstring:=cryptedstring+aArray[aArraylength-srclen-ord(aArray[CodePosIdx])+i];
end;
在Java中我已经将这段Delphi代码实现为:
protected static int readLenFromArray(char secureArray[])
{
int arrayLength = secureArray.length;
int hs = 0;
if(2<arrayLength)
{
hs = hs + (int) secureArray[2] * 0x1000000;
}
if(3<arrayLength)
{
hs = hs + (int) secureArray[3] * 0x10000;
}
if(4<arrayLength)
{
hs = hs + (int) secureArray[4] * 0x100;
}
if(5<arrayLength)
{
hs = hs + (int) secureArray[5];
}
return hs;
}
protected static String deCrypt(String code)
{
int codePosIdx = 10;
char [] secureArray;
int srcLen;
int arrayLength;
arrayLength = source.length(); // 1046 in my test case
for (i=0; i<arrayLength; i++)
{
secureArray[i] = source.charAt(i);
}
srcLen = readLenFromArray(secureArray); // function returns 858862149 in my test case
StringBuilder tmpStr = new StringBuilder();
for(i=0; i<srcLen; i++)
{
tmpStr = tmpStr.append(secureArray[arrayLength - srcLen - 1 - (int) secureArray[codePosIdx - 1] + i]);
}
cryptCode = tmpStr.toString();
return cryptCode;
}
我的问题是在Java中检查for-Loop中的条件。
在我的测试用例aArray[i + (int) secureArray[codePosIdx - 1]]
中等于aArray[-858861172]
,与Delphi相反,它会导致IndexOutOfBound
异常。我通过if语句在Java readLineFromArray
函数中避免了它。但是我如何在decrypt
函数中解决这个问题,以便为所有参数值保留函数的功能。
任何真正适用的建议!
答案 0 :(得分:6)
问题是你声明的Delphi和Java中的数组是不一样的
您在Delphi中使用AnsiChar
,这是一个字节
Java始终是unicode,因此char
类型是两个字节
您需要将Java数组声明为byte aArray[]
。
第二个例程失败,因为Java String
由两个字节chars
组成,因此永远不会有效。
您需要再次传递byte aArray[]
并进行处理。
因为您不再使用字符串,所以不能依赖.length()
函数来获取输入的长度,您必须自己进行测试以查看终止零字节的位置是,或传递长度作为参数。
答案 1 :(得分:1)
为了我无法在评论中获得的代码格式化,这是一个答案。
我想我可以使用非初始化(即零或随机垃圾)数据来查找函数中的基本控制流问题。你的功能如下:
function Decrypt(Source: Ansistring): Ansistring;
var
srclen, aArrayLength: integer;
aArray: TSecureArray;
cryptedstring:AnsiString;
begin
aArrayLength:=Length(Source); // length of source-String in my test case is 1046
....然后突然......
srclen:=ReadLenFromArray(aArray); // function returns 858862149 in my test case
for i:=1 to aArrayLength do
aArray[i]:=Source[i];
这是坚果!你没有初始化aArray
无处,也没有初始化容器(长度又名大小又称卷)和数据本身,但你将nil = NULL指针传递给ReadLenFromArray
!!!
我想你想要这样的东西:
function Decrypt(const Source: Ansistring): Ansistring;
....
begin
aArrayLength := Length(Source);
SetLength(aArray, aArrayLength); // !!!!! init the container
for i := 1 to aArrayLength do
aArray[i - 1] := Source[i]; // !!!!! init the data in the container
srclen := ReadLenFromArray(aArray); // now and only now can you use the array
.....rest of function
你应该注意,由于历史原因(我认为你不是很感兴趣),Delphi中的字符串被索引1到Length,动态数组被索引0到Length-1 - 所以我纠正了for循环中的索引
据我所知,你也忘了在Java中初始化secureArray
- 你永远不要设置它的长度,所以我只能想知道在赋值循环期间数据的位置。
基本上你的ReadLengthFromArray
函数只占用数组的切片,并且(在Intel-endian机器上)反转字节顺序。
更明显和简化的代码就像
function ReadLenFromArray(const aArray:TSecureArray): integer;
var
HS : LongRec absolute Result;
begin
if (High(aArray) < 6) or (Low(aArray) > 3) then
raise EAccessViolation.Create('The passed aArray does not have required data!');
HS.Bytes[3] := ord(aArray[3]);
HS.Bytes[2] := ord(aArray[4]);
HS.Bytes[1] := ord(aArray[5]);
HS.Bytes[0] := ord(aArray[6]);
end;
http://docwiki.embarcadero.com/Libraries/Berlin/en/System.SysUtils.LongRec