Reputation: 23587
While working with some code base, I am trying to understand piece of code so as can work and customize it , I am able to understand almost 90% of the code flow. Here is the overall flow
I am struck at the logic used to determine if the provided code is valid or not, here is that piece of code, I am generating 6 code as a sample, in this case alphanumeric code being generated and stored in the cache is
initial-alphabet : M9W6K3TENDGSFAL4
Code generated based on initial-alphabet
are
myList=[123-MK93-ES6D-36F3, 123-MK93-EFTW-D3LG, 123-MK93-EALK-TGLD, 123-MK93-ELKK-DN6S, 123-MK93-E4D9-3A6T, 123-MK93-EMTW-LNME]
protected int getVoucherNumber(String voucherCode){
int voucherNumberPos = voucherCode.length() - 12;
String voucherNumberHex = voucherCode.substring(voucherNumberPos, voucherNumberPos + 6);
int firstByte = getIntFromHexByte(voucherNumberHex.substring(0, 2), 0);
int secondByte = getIntFromHexByte(voucherNumberHex.substring(2, 4), 1);
int thirdByte = getIntFromHexByte(voucherNumberHex.substring(4, 6), 7);
return firstByte << 16 | secondByte << 8 | thirdByte;
}
private int getIntFromHexByte(String value, int offset){
return (getIntFromHexNibble(value.charAt(0), offset) << 4) + getIntFromHexNibble(value.charAt(1), offset + 4);
}
private int getIntFromHexNibble(char value, int offset){
int pos = getAlphabet().indexOf(value);
if (pos == -1) {// nothing found}
pos -= offset;
while (pos < 0) {
pos += 16;
}
return pos % 16;
}
Here is the code which is trying to validate code
int voucherNumber = getVoucherNumber(kyList.get(4));
In this case value of voucherNumber
is 4
i.e the fourth element from the list, in case I pass any value which is not part of the list getVoucherNumber
method is returning a higher value (greater than the list count).
One of the main thing which confusing me are these 2 lines
int voucherNumberPos = voucherCode.length() - 12;
String voucherNumberHex = voucherCode.substring(voucherNumberPos, voucherNumberPos + 6);
As per my understanding, they are first moving out the first 3 digit from the check which are customer supplied but again they have not used rest of the string but only specific part of the string.
Can any one help me to understand this
Upvotes: 0
Views: 215
Reputation: 1912
It appears you've inherited responsibility for some poorly written code. We've all been there so I'll try to answer in that spirit. I'm not positive this question is on-topic for this site, but it doesn't appear to be forbidden by the help center. In an attempt to stay on-topic I'll end with some general advice not limited to the highly-localized specifics of the question.
myList.get(4)
Arrays in Java are zero-based, so that's 123-MK93-E4D9-3A6T
. You probably know that, but it isn't clear from your question that you do.
initial-alphabet : M9W6K3TENDGSFAL4
I assume this is what's returned by the call to getAlphabet
in getIntFromHexNibble
. So the alphanumeric characters in the code are meant to be hexadecimal but using a nonstandard set of 16 characters for the digits.
protected int getVoucherNumber(String voucherCode){
Ignoring the hyphens and the customer-supplied first three digits, the code is 'MK93E4D93A6T'. Twelve hex digits encode 48 bits, but an int
in Java is only 32 bits long, so the code is already broken. Whatever it does, it isn't going to return the voucher number represented by the voucher code.
int voucherNumberPos = voucherCode.length() - 12;
String voucherNumberHex = voucherCode.substring(voucherNumberPos, voucherNumberPos + 6);
This is setting voucherNumberHex to a six-character long string, starting twelve from the end of voucherCode
, in this case 93-E4D
. It seems likely the author didn't expect the caller to include the hyphens when this code was first written. Even so the intent seems to be to ignore half the voucher code.
int firstByte = getIntFromHexByte(voucherNumberHex.substring(0, 2), 0);
int secondByte = getIntFromHexByte(voucherNumberHex.substring(2, 4), 1);
int thirdByte = getIntFromHexByte(voucherNumberHex.substring(4, 6), 7);
This looks straightforward at first, but the parameters 0
, 1
, and 7
are not offsets at all, despite the name of the argument. It's trying to turn each pair of hex digits into a byte, which would be sensible enough if not for the hyphen character. Now for the fun part:
private int getIntFromHexNibble(char value, int offset) {
int pos = getAlphabet().indexOf(value);
if (pos == -1) {// nothing found}
pos -= offset;
while (pos < 0) {
pos += 16;
}
return pos % 16;
}
The right curly brace after "found" is commented out, so the code you posted is actually incomplete. I'm going to assume there's another line or two that read
return pos;
}
So the basic idea is that M
becomes 0, 9
becomes 1, and so on via the call to indexOf
. But if this method sees a character not in the provided alphabet, like a hyphen, it uses the so-called offset
to calculate a default value (in this case 14, if I've done the math in my head right), and returns that as the hex nibble value.
The end result is that you get back a number in the range 0 (inclusive) to 2^24 (exclusive). But of the 2^24 possible values such a number should have, only 2^20 different values will ever be returned. So from a voucher code that looks like twelve digits of base-32, which would have an astronomical number of values, you're limited to slightly over a million different voucher numbers within each customer prefix.
General advice:
Upvotes: 5