Format "raw" string to Java UUID in PHP [duplicate] - java

This question already has answers here:
Format 32-character string with hyphens to become UUID
(3 answers)
Closed 7 months ago.
Is there a more effective, simplified means of converting a "formatted" Java UUID - without dashes - to a Java compatible format - with dashes - in PHP, and ultimately: How would I do it?
I have code that already performs this action, but it seems unprofessional and I feel that it could probably be done more effectively.
[... PHP code ...]
$uuido = $json['id'];
$uuidx = array();
$uuidx[0] = substr( $uuido, 0, 8 );
$uuidx[1] = substr( $uuido, 8, 4 );
$uuidx[2] = substr( $uuido, 12, 4);
$uuidx[3] = substr( $uuido, 16, 4);
$uuidx[4] = substr( $uuido, 20, 12);
$uuid = implode( "-", $uuidx );
[... PHP code ...]
Input: f9e113324bd449809b98b0925eac3141
Output: f9e11332-4bd4-4980-9b98-b0925eac3141
The data from $json['id'] is called from the following Mojang Profile API using the file_get_contents( $url ) function combined with a json_decode( $file ), which could alternatively be done through cURL - but since it would eventually be requesting anything up to 2048 profiles at once, I figured it would become slow.
I do have my code in use, and public, through the following ProjectRogue Server Ping API, which usually contains a list of online players.
Note: There are several questions related to this, but none apply to PHP as far as I am aware. I have looked.
I mention Java UUID as the parsed output should effectively translate to a Player UUID for use in a Java-Based plugin for Spigot or Craftbukkit after 1.7.X.

Your question doesn't make much sense but assuming you want to read the UUID in the correct format in Java you can do something like this:
import java.util.UUID;
class A
{
public static void main(String[] args){
String input = "f9e113324bd449809b98b0925eac3141";
String uuid_parse = input.replaceAll(
"(\\w{8})(\\w{4})(\\w{4})(\\w{4})(\\w{12})",
"$1-$2-$3-$4-$5");
UUID uuid = UUID.fromString(uuid_parse);
System.out.println(uuid);
}
}
Borrowed from maerics, see here: https://stackoverflow.com/a/18987428/4195825
Or in PHP you can do something like:
<?php
$UUID = "f9e113324bd449809b98b0925eac3141";
$UUID = substr($UUID, 0, 8) . '-' . substr($UUID, 8, 4) . '-' . substr($UUID, 12, 4) . '-' . substr($UUID, 16, 4) . '-' . substr($UUID, 20);
echo $UUID;
?>
Borrowed from fico7489: https://stackoverflow.com/a/33484855/4195825
And then you can send that to Java where you can create a UUID object using fromtString().

UUID is not a special java format. It is the Universal Unique Identifier.
A universally unique identifier (UUID) is an identifier standard used in software construction. A UUID is simply a 128-bit value.
What happen is that the conversion from the 128 bit value to a human readable version of the same value converting it to a string follow generally some conventions.
Basically the number is converted to the better human readable hexadecimal format with some hyphen to separate block of bits.
From a performance perspective you can use the several times the substr_replace function, instead of creating an array of strings using substr and applying implode to it.

Related

Validating user input UUID [duplicate]

How to check if variable contains valid UUID/GUID identifier?
I'm currently interested only in validating types 1 and 4, but it should not be a limitation to your answers.
Currently, UUID's are as specified in RFC4122. An often neglected edge case is the NIL UUID, noted here. The following regex takes this into account and will return a match for a NIL UUID. See below for a UUID which only accepts non-NIL UUIDs. Both of these solutions are for versions 1 to 5 (see the first character of the third block).
Therefore to validate a UUID...
/^[0-9a-f]{8}-[0-9a-f]{4}-[0-5][0-9a-f]{3}-[089ab][0-9a-f]{3}-[0-9a-f]{12}$/i
...ensures you have a canonically formatted UUID that is Version 1 through 5 and is the appropriate Variant as per RFC4122.
NOTE: Braces { and } are not canonical. They are an artifact of some systems and usages.
Easy to modify the above regex to meet the requirements of the original question.
HINT: regex group/captures
To avoid matching NIL UUID:
/^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i
If you want to check or validate a specific UUID version, here are the corresponding regexes.
Note that the only difference is the version number, which is explained in 4.1.3. Version chapter of UUID 4122 RFC.
The version number is the first character of the third group : [VERSION_NUMBER][0-9A-F]{3} :
UUID v1 :
/^[0-9A-F]{8}-[0-9A-F]{4}-[1][0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i
UUID v2 :
/^[0-9A-F]{8}-[0-9A-F]{4}-[2][0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i
UUID v3 :
/^[0-9A-F]{8}-[0-9A-F]{4}-[3][0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i
UUID v4 :
/^[0-9A-F]{8}-[0-9A-F]{4}-[4][0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i
UUID v5 :
/^[0-9A-F]{8}-[0-9A-F]{4}-[5][0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i
regex to the rescue
/^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/.test('01234567-9ABC-DEF0-1234-56789ABCDEF0');
or with brackets
/^\{?[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}‌​\}?$/
If you are using Node.js for development, it is recommended to use a package called Validator. It includes all the regexes required to validate different versions of UUID's plus you get various other functions for validation.
Here is the npm link: Validator
var a = 'd3aa88e2-c754-41e0-8ba6-4198a34aa0a2'
v.isUUID(a)
true
v.isUUID('abc')
false
v.isNull(a)
false
If you use the uuid package, this package brings a boolean validation function where it tells you if a uuid is valid or not.
Example:
import { validate as isValidUUID } from 'uuid';
if (!isValidUUID(tx.originId)) {
return Promise.reject('Invalid OriginID');
}
thanks to #usertatha with some modification
function isUUID ( uuid ) {
let s = "" + uuid;
s = s.match('^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$');
if (s === null) {
return false;
}
return true;
}
Beside Gambol's answer that will do the job in nearly all cases, all answers given so far missed that the grouped formatting (8-4-4-4-12) is not mandatory to encode GUIDs in text. It's used extremely often but obviously also a plain chain of 32 hexadecimal digits can be valid.[1] regexenh:
/^[0-9a-f]{8}-?[0-9a-f]{4}-?[1-5][0-9a-f]{3}-?[89ab][0-9a-f]{3}-?[0-9a-f]{12}$/i
[1] The question is about checking variables, so we should include the user-unfriendly form as well.
Why are there dashes in a .NET GUID? - Stack Overflow plus Accepted answer
Test and validate a GUID (guid.us)
Guid.ToString Method (String) (MSDN)
All type-specific regexes posted so far are failing on the "type 0" Nil UUID, defined in 4.1.7 of the RFC as:
The nil UUID is special form of UUID that is specified to have all 128 bits set to zero: 00000000-0000-0000-0000-000000000000
To modify Wolf's answer:
/^[0-9a-f]{8}-?[0-9a-f]{4}-?[0-5][0-9a-f]{3}-?[089ab][0-9a-f]{3}-?[0-9a-f]{12}$/i
Or, to properly exclude a "type 0" without all zeros, we have the following (thanks to Luke):
/^(?:[0-9a-f]{8}-?[0-9a-f]{4}-?[1-5][0-9a-f]{3}-?[89ab][0-9a‌​-f]{3}-?[0-9a-f]{12}‌​|00000000-0000-0000-‌​0000-000000000000)$/‌​i
if you use the uuid package, you can import the validate and pass the id into it
const { v4: uuidv4, validate } = require('uuid');
const { id } = request.params;
validate(id) ? true : false;
I think Gambol's answer is almost perfect, but it misinterprets the RFC 4122 § 4.1.1. Variant section a bit.
It covers Variant-1 UUIDs (10xx = 8..b), but does not cover Variant-0 (0xxx = 0..7) and Variant-2 (110x = c..d) variants which are reserved for backward compatibility, so they are technically valid UUIDs. Variant-4 (111x = e..f) is indeed reserved for future use, so they are not valid currently.
Also, 0 type is not valid, that "digit" is only allowed to be 0 if it's a NIL UUID (like mentioned in Evan's answer).
So I think the most accurate regex that complies with current RFC 4122 specification is (including hyphens):
/^([0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[0-9a-d][0-9a-f]{3}-[0-9a-f]{12}|00000000-0000-0000-0000-000000000000)$/i
^ ^^^^^^
(0 type is not valid) (only e..f variant digit is invalid currently)
A slightly modified version of the above answers written in a more concise way. This will validate any GUID with hyphens (however easily modified to make hyphens optional). This will also support upper and lower case characters which has become the convention regardless of the specification:
/^([0-9a-fA-F]{8})-(([0-9a-fA-F]{4}\-){3})([0-9a-fA-F]{12})$/i
The key here is the repeating part below
(([0-9a-fA-F]{4}\-){3})
Which simply repeats the 4 char patterns 3 times
If someone is using yup , JavaScript schema validator library, This functionality can be achieved with below code.
const schema = yup.object().shape({
uuid: yup.string().uuid()
});
const isValid = schema.isValidSync({uuid:"string"});
Use the .match() method to check whether String is UUID.
public boolean isUUID(String s){
return s.match("^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$");
}
A good way to do it in Node is to use the ajv package (https://github.com/epoberezkin/ajv).
const Ajv = require('ajv');
const ajv = new Ajv({ allErrors: true, useDefaults: true, verbose: true });
const uuidSchema = { type: 'string', format: 'uuid' };
ajv.validate(uuidSchema, 'bogus'); // returns false
ajv.validate(uuidSchema, 'd42a8273-a4fe-4eb2-b4ee-c1fc57eb9865'); // returns true with v4 GUID
ajv.validate(uuidSchema, '892717ce-3bd8-11ea-b77f-2e728ce88125'); // returns true with a v1 GUID
Versions 1 to 5, without using a multi-version regex when version is omitted.
const uuid_patterns = {
1: /^[0-9A-F]{8}-[0-9A-F]{4}-1[0-9A-F]{3}-[0-9A-F]{4}-[0-9A-F]{12}$/i,
2: /^[0-9A-F]{8}-[0-9A-F]{4}-2[0-9A-F]{3}-[0-9A-F]{4}-[0-9A-F]{12}$/i,
3: /^[0-9A-F]{8}-[0-9A-F]{4}-3[0-9A-F]{3}-[0-9A-F]{4}-[0-9A-F]{12}$/i,
4: /^[0-9A-F]{8}-[0-9A-F]{4}-4[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i,
5: /^[0-9A-F]{8}-[0-9A-F]{4}-5[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i
};
const isUUID = (input, version) => {
if(typeof input === "string"){
if(Object.keys(uuid_patterns).includes(typeof version === "string" ? version : String(version))){
return uuid_patterns[version].test(input);
} else {
return Object.values(uuid_patterns).some(pattern => pattern.test(input));
}
}
return false;
}
// Testing
let valid = [
'A987FBC9-4BED-3078-CF07-9141BA07C9F3',
'A987FBC9-4BED-4078-8F07-9141BA07C9F3',
'A987FBC9-4BED-5078-AF07-9141BA07C9F3',
];
let invalid = [
'',
'xxxA987FBC9-4BED-3078-CF07-9141BA07C9F3',
'A987FBC9-4BED-3078-CF07-9141BA07C9F3xxx',
'A987FBC94BED3078CF079141BA07C9F3',
'934859',
'987FBC9-4BED-3078-CF07A-9141BA07C9F3',
'AAAAAAAA-1111-1111-AAAG-111111111111',
];
valid.forEach(test => console.log("Valid case, result: "+isUUID(test)));
invalid.forEach(test => console.log("Invalid case, result: "+isUUID(test)));
I added a UUID validator to Apache Commons Validator. It's not yet been merged, but you can vote for it here:
https://github.com/apache/commons-validator/pull/68
I have this function, but it's essentially the same as the accepted answer.
export default function isUuid(uuid: string, isNullable: boolean = false): boolean {
return isNullable
? /^[0-9a-f]{8}-[0-9a-f]{4}-[0-5][0-9a-f]{3}-[089ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(uuid)
: /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(uuid);
}
I think a better way is using the static method fromString to avoid those regular expressions.
id = UUID.randomUUID();
UUID uuid = UUID.fromString(id.toString());
Assert.assertEquals(id.toString(), uuid.toString());
On the other hand
UUID uuidFalse = UUID.fromString("x");
throws java.lang.IllegalArgumentException: Invalid UUID string: x

How to parse such text?

id no, no2, list
id1 (3, 5, [t[0][66], y[5][626]])
id2 (3, 5, [t[0][66], y[5][626], z[5][626]])
id2 (3, 5, [t[0][66], y[5][626]])
id3 (32, 54, [t[0][66], y[5][626]])
id4 (3, 541, [t[0][66], y[5][626], u[5][626], y[25][6226]])
id5 (3, 52, [t[0][66], y[5][626]])
id6 (23, 5, [t[0][66], y[5][626]])
How would I go about parsing such text? I tried creating an object from it without much success. List can vary in size. Java code would be great, but any language or pseudo code, or regular language is fine.
Not your language but in Python
import sys, re
def regex(regex, str):
return [s for s in re.split(regex, str) if s]
def parse(fname):
data = []
with open(fname) as f:
data = f.read().splitlines()
header = regex('[, ]+', data[0]);
print header
for line in data[1:]:
fields = [regex('[(),]+', field)[0] # Remove ) ( ,
for field in line.split()]
fields[3] = fields[3][1:] # Remove [
fields[-1] = fields[-1][:-1] # Remove ]
print fields[0], fields[1], fields[2], fields[3:]
parse("file");
Output ('file' contains your text):
$ python parse.py
['id', 'no', 'no2', 'list']
id1 3 5 ['t[0][66]', 'y[5][626]']
id2 3 5 ['t[0][66]', 'y[5][626]', 'z[5][626]']
id2 3 5 ['t[0][66]', 'y[5][626]']
id3 32 54 ['t[0][66]', 'y[5][626]']
id4 3 541 ['t[0][66]', 'y[5][626]', 'u[5][626]', 'y[25][6226]']
id5 3 52 ['t[0][66]', 'y[5][626]']
id6 23 5 ['t[0][66]', 'y[5][626]']
I've tried to make a regex to extract data but I have no time to finish it.
here's what I have so far: "id(\\d) \\((\\d*), (\\d*),\\s*\\,*\\[(\\,*\\s*(\\D)\\[(\\d*)\\]\\[(\\d*)\\])*.*\\]\\)"
Use an online tester to make it work better...
1st group is the id#, 2nd group the no, 3rd group no2 and you should get the list items afterwards.
There is really no reason to create a parser by hand as there are multiple parser generators available, JavaCC being the most popular. A skeleton process is.
Define language using BNF
Translate the BNF to the input language the parser generator understands making sure to make it either left recursive or right recursive as appropriate. JavaCC requires right recursion.
Invoke the parser generator to create the parser classes.
Augment the generated sourcecode by inserting/refining the generator source.
There are many examples

Handling character encoding from Java to PHP to MySQL

In Java I pass a String to PHP.
In PHP I take that String and do a search for it with a MySQL query.
Here is php code:
$query = $database->escape_value(trim($_POST['query']));
$result = mysqli_query($dbconnection, Data::getSearchQuery($query));
while ($row = mysqli_fetch_assoc($result)) {
$output[] = $row;
}
print(json_encode($output));
mysqli_close($dbconnection);
public static function getSearchQuery($item_query) {
$query = "
SELECT i.item, i.item_id, c.category, c.cat_id
FROM items as i
LEFT JOIN master_cat AS c
ON (c.cat_id = i.cat_id)
WHERE i.item LIKE '%{$item_query}%'
ORDER BY i.item ASC;";
return $query;
}
This always works if I use regular characters on my U.S. keyboard. But the moment I start using irregular characters, the search turns empty.
I can verify that MySQL stores the data AS THE USER ENTERS IT. So if they typed Beyoncè, that is how database stores it.
But when I search for Beyoncè (or whatever) in the above code, it returns empty.
How should I handle the char. encoding here?
Three points to think of:
1) The $item_query variable could come in wrong encoding.
2) >>I can verify that MySQL stores the data AS THE USER ENTERS IT
This can get tricky. If one writes an iso8859-1 encoded string to an utf-8 database, the string is obviously stored incorrectly. If that string is read with a client (i. e. phpmyadmin or mysql command line tool) configured to iso8859-1, the string is correctly returned - although its representation in the database is clearly wrong.
3) The MySql settings:
Have your set utf-8 for the connection itself? What about charsets and collations for the database/the table?
https://dev.mysql.com/doc/refman/5.5/en/charset-syntax.html
UPDATE:
I assume you want everything to be UTF-8. Kind of quick hack to test:
Beyoncé has 7 characters (see MySQL CHAR_LENGTH function)
in UTF-8, it occupies 8 bytes (see MySQL LENGTH function). The eight bytes are, represented in a one-byte-per-character encoding like windows-1252, something like Beyoncé.
This leads to the following diagnostic tests ...
The PHP-issued SQL command
"SELECT CHAR_LENGTH($item_query), LENGTH($item_query);"
should then return a result of (7, 8) to show us that the $item_query variable is probably correctly encoded and the database likes UTF-8. (7, 7) would mean $item_query wasn't UTF-8, and (8, 8) would mean the database doesn't want to deal with UTF-8 yet. If the latter is the case, then perhaps issue a SET NAMES 'UTF8'; before the query.
Similarly, the PHP-issued SQL command
SELECT CHAR_LENGTH('Beyoncé'), LENGTH('Beyoncé');
should return the result (7, 8) to show us that your PHP editor is configured to edit UTF-8 php files.
Repeat the previous step with phpmyadmin (or any SQL client) to be sure that this client uses UTF-8, too.
No table was involved yet! The SQL command
SELECT CHAR_LENGTH(somecolumn), LENGTH(somecolumn) FROM sometable;
(with sometable having UTF-8 character encoding and somecolumn containing some diacritical characters) should tell you if UTF-8 was used when storing values to the table.
If all previous tests passed, test again with LIKE. Even 'Beyoncé' LIKE 'Beyonce' should work then. For more information, google MySQL collation.

Android and Java Uuid

I want to generate a uuid for my app i tried many things like wifi mac address , getting android id, serial number , creating pseudo uuid from device
android.os.Build properties .
i also came to know that java itself got Uuid creator class
java.util.UUID
by going through several articles and blogs i am little confused about this . i want to know that if two android device are creating uuid using this java class(java.util.UUID) will that be unique or is there any chance for duplication?
Also in some devices i was not able to find serial number using android.os.Build.SERIAL . is there alternative way to get serial number of device
Assuming you're using the java.util.UUID's randomUUID() function there's a theoretical chance of duplication, but it's incredibly remote. The ids generated are RFC4122 version-4 ids, which have 122 bits randomly set. That means there are 5.32 x 10^^36 possible values. For some perspective on that, if you had a billion devices, each generating a billion IDs per second, it would take roughly 168 billion years for them to finish (~10X the age of the universe).
So, yes, duplication is possible, but (assuming Java is using a high quality random number generator), the odds of it actually happening are so remote as to be meaningless.
to Get Device ID Use Telephoney U can use it here is it is
public static String deviceUDID(Context ctx) {
final TelephonyManager tm = (TelephonyManager) ctx.getSystemService(Context.TELEPHONY_SERVICE);
final String tmDevice, tmSerial, androidId;
tmDevice = "" + tm.getDeviceId();
tmSerial = "" + tm.getSimSerialNumber();
androidId = "" +android.provider.Settings.Secure.getString(ctx.getContentResolver(), android.provider.Settings.Secure.ANDROID_ID);
UUID deviceUuid = new UUID(androidId.hashCode(), ((long)tmDevice.hashCode() << 32) | tmSerial.hashCode());
String deviceId = deviceUuid.toString();
Log.d("Device Id", deviceId);
return deviceId;
}

Extract the results of a GWT service

Messy, complicated question, but here goes. I'm working on an integration project with Google Checkout, and there is a Google Checkout GWT service that returns the currency conversion rates used by the Checkout web interface to convert USD into local currencies. This endpoint is hosted at https://market.android.com/publish/gwt/, and staring at Firebug I see this going to the server:
7|0|6|https://market.android.com/publish/gwt/|FCCA4108CB89BFC2FEC78BA7363D4AF6|com.google.wireless.android.vending.developer.
shared.MerchantService|getCurrencyExchangeRates|com.google.common.money.CurrencyCode/112449834|java.util.ArrayList/4159755760
|1|2|3|4|2|5|6|5|235|6|13|5|18|5|81|5|53|5|72|5|102|5|121|5|177|5|175|5|205|5|204|5|55|5|86|-1|
and this being returned
//OK[235,3,'D0JA',2,86,3,'CXXg',2,55,3,'DW2A',2,204,3,'X9NA',2,205,3,'EuvA',2,175,3,'VIig',2,177,3,'E2Dw',2,121,3,'E4ziA',2,1
02,3,'do$Q',2,72,3,'T82w',2,53,3,'Ds0Q',2,81,3,'Cq5g',2,18,3,'Dlfg',2,13,1,["com.google.common.collect.RegularImmutableList/4
40499227","com.google.common.money.SimpleMoney/627983206","com.google.common.money.CurrencyCode/112449834"],0,7]
Forgive the odd formatting: can't quite get the code block to format right.
Wandering the web for hours on end I was able to determine that the RegularImmutableList class is in the Guava libraries (at http://code.google.com/p/guava-libraries/). What I'm looking for is:
I can't find the com.google.common.money.SimpleMoney or com.google.common.money.CurrencyCode classes anywhere: anyone seen them?
The GWT wire format appears to be an odd JSON string. I see various references to Google Groups messages talking about descriptions of the wire format, but can't find the underlying messages or any coherent reference that would let me reverse this: anyone have a handle on a handy reference? If I can at least understand WHAT the encoding is I might be able to get away without the class files from question 1 above.
I started wandering through the Android Market api library at http://code.google.com/p/android-market-api/, figuring they have to have done SOME of the Android Market communication integration, and they appear to have done so using protobufs. Is there any decent reference for the GWT/protobufs communication bits?
The underlying reason for this craziness is that I need to be able to take regular exchange rate values from Google Checkout so when I'm importing sales transactions in foreign currencies I can do the conversion at the prevailing rate at the time of the transaction. The current Checkout reporting formats do NOT provide this, so most folks end up using alternative sources of exchange rates that don't match what Google uses. It is clearly a shortcoming on the part of Google Checkout's integration interface, but if we got started on shortcomings of Google Checkout's interface we'd be here all week. My intention is to poll the Checkout interface for newly fulfilled orders and then request the appropriate exchange rate table so I can figure out in near real-time what the incoming payments are. I've got the polling bit down pat but can't quite get past the exchange rate bit.
While trying to create a script to bulk upload in-app products for my application (CSV upload constantly failed with obscure error messages), I have managed to understand the GWT AJAX protocol.
It's actually pretty simple, except it requires you to know structure of all used classes. Or guess it, as is the case with internal classes used by Google. :)
I'll use examples from the question to explain the protocol in detail.
Request format
7|0|6|https://market.android.com/publish/gwt/|FCCA4108CB89BFC2FEC78BA7363D4AF6|com.google.wireless.android.vending.developer.shared.MerchantService|getCurrencyExchangeRates|com.google.common.money.CurrencyCode/112449834|java.util.ArrayList/4159755760|1|2|3|4|2|5|6|5|235|6|13|5|18|5|81|5|53|5|72|5|102|5|121|5|177|5|175|5|205|5|204|5|55|5|86|-1|
The request is pipe-delimited list of tokens with the following meaning:
7 - protocol version
0 - flags. 1 is FLAG_ELIDE_TYPE_NAMES, 2 is FLAG_RPC_TOKEN_INCLUDED
6 - string token count
6 string tokens:
https://market.android.com/publish/gwt/
FCCA4108CB89BFC2FEC78BA7363D4AF6
com.google.wireless.android.vending.developer.shared.MerchantService
getCurrencyExchangeRates
com.google.common.money.CurrencyCode/112449834
java.util.ArrayList/4159755760
The actual encoded request, which references strings from the list above using 1-based indices:
1 - https://market.android.com/publish/gwt/ - base URL
2 - FCCA4108CB89BFC2FEC78BA7363D4AF6 - some hash, which is references as serializationPolicyStrongName in GWT sources.
3 - com.google.wireless.android.vending.developer.shared.MerchantService - service name
4 - getCurrencyExchangeRates - method name
2 - parameter count. Parameter types follow:
5 - com.google.common.money.CurrencyCode/112449834
6 - java.util.ArrayList/4159755760
Serialized parameters. Each object is represented either by its classname and list of serialized fields or by negative integer back-reference to previously encountered object. In our case we have two objects:
5 - com.google.common.money.CurrencyCode/112449834, which only has one integer field: 235
6 - java.util.ArrayList/4159755760, which has one integer length field 13, followed by 13 serialized list items. Note that 12 of them are CurrencyCode objects serialized just as the above one, and the last one is a backreference (-1) to the very first object we encountered while (de-)serializing this request, i.e. CurrencyCode(235)
Response format
//OK[235,3,'D0JA',2,86,3,'CXXg',2,55,3,'DW2A',2,204,3,'X9NA',2,205,3,'EuvA',2,175,3,'VIig',2,177,3,'E2Dw',2,121,3,'E4ziA',2,102,3,'do$Q',2,72,3,'T82w',2,53,3,'Ds0Q',2,81,3,'Cq5g',2,18,3,'Dlfg',2,13,1,["com.google.common.collect.RegularImmutableList/440499227","com.google.common.money.SimpleMoney/627983206","com.google.common.money.CurrencyCode/112449834"],0,7]
The response is very similar in format to the request except it's JS-formatted array (though not JSON, as it uses invalid single quotes), and it's in reverse order.
The field meaning is as follows:
7 - protocol version
0 - flags, same as for request
Array of string tokens:
com.google.common.collect.RegularImmutableList/440499227
com.google.common.money.SimpleMoney/627983206
com.google.common.money.CurrencyCode/112449834
And then goes one serialized object of type 1 - com.google.common.collect.RegularImmutableList/440499227 with one integer length field 13, followed by 13 serialized objects of class 2 - com.google.common.money.SimpleMoney/627983206. Each SimpleMoney object has two fields, for example:
'Dlfg' - long integer field encoded as base64 number. This particular one is 940000
3, 18 - CurrencyCode object with integer field 18
What you are looking at is GWT-RPC serialization format. Unfortunatelly it is not publicly documented. Fortunatelly GWT is open-source so you could look at the source to see how it is produced.
Note: This format might change between GWT versions (I known it did in 2.2). This is most likelly also a reason why Google does not document it - if they did they'd need to keep it backward compatible.
Class names that you see are Java classes that Google Checkout uses internally. When GWT is compiled to JS the names get mangled so you don't see them any more.
As noted this is GWT-RPC.
What you are trying to do is reverse-engineer Google internal APIs. I wouldn't do that because, a. It might change without notice, breaking your app and, b. I'm sure Goog wouldn't like it and it probably violates the service agreement (have you read it?).
I have some code made in VB that may be useful for you to realize how to parse GWT Serialized strings. "Datos" contains the string you received.
aAux = Split(Datos, ",[")
aAux(1) = Replace(aAux(1), "],0,7]", "")
aAux(0) = Replace(aAux(0), "//OK[", "")
aAux(0) = Replace(aAux(0), "'", "")
aDescripcion = Split(aAux(1), """,""")
aValor = Split(aAux(0), ",")
InvertirArray aValor
For X = 0 To UBound(aValor)
If Not IsNumeric(aValor(X)) Then
Exit For
End If
If adescripcion(Int(aValor(X))-1) = "gov.senasa.embalajemadera.shared.domain.Pais/3238585366" Then
For Y = X + 1 To UBound(aValor)
If Int(aValor(Y)) = "" Then '- Do what you want
end if
If adescripcion(Int(aValor(Y))) = "java.lang.Integer/3438268394" Then
'- Do what you want
Next Y
End If
Next X
Of course you have to adapt it to your needs and you will have to play a little bit with the arrays...
InvertirArray:
Public Sub InvertirArray(ByRef Arr() As String)
'- el array va tiene que empezar en 0
Dim X As Long
Dim Hasta As Long
Dim Tmp As String
If UBound(Arr) Mod 2 = 0 Then
'- Es impar
Hasta = UBound(Arr) + 1
Else
Hasta = UBound(Arr)
End If
For X = LBound(Arr) To UBound(Arr) \ 2
Tmp = Arr(X)
Arr(X) = Arr(UBound(Arr) - X)
Arr(UBound(Arr) - X) = Tmp
Next X
end sub
And of course you need to decode and encode Long Numbers and dates. So:
Public Function EncodeDateGwt(Numero As Double, Optional isDate As Boolean = False) As String
Dim s As String
Dim a As Double
Dim i As Integer
Dim u As Integer
Dim Base As String
Numero = IIf(isDate, Numero * 1000, Numero)
Base = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_$"
Do While Val(Numero) <> 0
a = Numero
i = 0
Do While a >= 64
i = i + 1
a = a / 64
Loop
If i <> u - 1 And u <> 0 Then EncodeDateGwt = EncodeDateGwt & String(u - i - 1, Left(Base, 1))
a = Int(a)
EncodeDateGwt = EncodeDateGwt + Mid(Base, a + 1, 1)
Numero = Numero - a * (64 ^ i)
u = i
Loop
EncodeDateGwt = EncodeDateGwt & String(i, Left(Base, 1))
End Function
Public Function DecodeDateGwt(Texto As String, Optional isDate As Boolean = False) As Long
Dim Base As String
Dim a As Integer
Base = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_$"
For a = 1 To Len(Texto)
DecodeDateGwt = DecodeDateGwt + (InStr(Base, Mid(Texto, a, 1)) - 1) * (Len(Base) ^ ((Len(Texto) - (a))))
Next
DecodeDateGwt = IIf(isDate, DecodeDateGwt / 1000, DecodeDateGwt)
'devuelve timestamp
End Function
If what you need to encode/decode is a date, then you need to do this before:
Call encodegwtdate(date2unix("20/02/2016"),true)
Public Function Date2Unix(ByVal vDate As Date) As Long
Date2Unix = DateDiff("s", Unix1970, vDate)
End Function
Public Function Unix2Date(vUnixDate As Long) As Date
Unix2Date = DateAdd("s", vUnixDate, Unix1970)
End Function
Hope you solve it. By the way, does anyone knows what negative numbers means?????

Categories

Resources