In JavaScript Google Flatbuffers, how does one write a ulong? - javascript

I have no problem with doing this in a C++ program, but I am stuck on writing a ulong in JS.
FB has no issue if I used the 32bit process.hrtime() value.
But how does do a createLong() for a 64bit ?
see: [ https://nodejs.org/api/process.html#process_process_hrtime_bigint ]
# commented line does not work
# let timeStamp = process.hrtime.bigint()
let timeStamp = process.hrtime()
let ts = builder.createLong(0, timeStamp)
PNT.Telemetry.startTelemetry(builder)
PNT.Telemetry.addSystemTime(builder, ts)
FB template file
// Simple Telemetry data from/to Sim and Sensor
namespace PNT;
enum DeviceType:byte { IMU, VAN, GPS, MAGNAV, SOOP }
struct PosVector {
lat:double;
lon:double;
alt:double;
}
table Telemetry {
source: string;
systemTime:ulong = 0;
systemTimeString: string;
description: string;
position: PosVector;
}
root_type Telemetry;

You can use this function, it works well for timestamp
var flatBufferTimeStamp = function(value) {
var bin = (value).toString(2);
var pad = new Array(64 - bin.length + 1 ).join('0');
bin = pad + bin;
return {
low: parseInt(bin.substring(32), 2),
high: parseInt(bin.substring(0, 32), 2)
};
}
var timeStamp = flatBufferTimeStamp(process.hrtime())
let ts = builder.createLong(timeStamp.low, timeStamp.high);
PNT.Telemetry.startTelemetry(builder)
PNT.Telemetry.addSystemTime(builder, ts)
Source: https://groups.google.com/forum/#!topic/flatbuffers/ieXNEsB_2wc

Use flatbuffers.Long, here is an example: https://github.com/google/flatbuffers/blob/master/tests/JavaScriptTest.js#L160
Sadly there is no code in FlatBuffers to convert a bigint to the 2 32-bit values, which would be good to add. For now you may need to do your own conversion.

Related

How do I get the actual size in bytes for a number and a string in JavaScript in a browser environment?

I am trying to get the actual size (in bytes) of a number and a string in browsers e.g. chrome.
I learned that in JavaScript numbers are represented in double precision takes up 64 bits and strings are UTF-16 code unit so it takes either 2 bytes or 4 bytes.
I first tried to use new Blob but it encodes string component characters as UTF-8 not UTF-16. And I know there is a Buffer.from API in Node but it is not available in a browser environment.
My question is how I can get the actual size of a number and a string in bytes from a browser, e.g. chrome?
You can do that natively with the help of TextEncoder
let str1 = 'Beta'; // 'Beta' text in English
let str2 = '贝塔'; // 'Beta' text in Chinese
const encoder = new TextEncoder();
const len1 = encoder.encode(str1).length;
const len2 = encoder.encode(str2).length;
console.log(len1); // 4
console.log(len2); // 6
First of all it is important to realize that the spec doesn't mandate any representation. Just behavior.
Strings are stored in UTF-16 but fortunately for your purpose each index represents 16 bits.
For example
console.log('😠'.length); // Should log 2 because emoji takes 2 16 bit parts
For numbers it depends. V8 represents small integer numbers as actual 32 bit ints.
With https://github.com/substack/node-browserify you can work with buffers in the Browser by using: https://github.com/toots/buffer-browserify.
//in your browsify js file:
require('buffer')
Buffer.byteLength(String.fromCharCode(55555), 'utf16')
Buffer.byteLength(String.fromCharCode(55555, 57000), 'utf16')
iconv-lite: Pure JS character encoding conversion
var iconv = require('iconv-lite');
var buf =iconv.encode("Hello World", 'utf16');
console.log(buf);
console.log(buf.length); // returns 24
Here is my answer to your problem :
function getBytesFromVar(theVar) {
if(theVar !== null && theVar !== undefined) {
switch (typeof theVar) {
case 'string' : {
var encoder = new TextEncoder();
encoder['encoding'] = "utf-16";
return encoder['encode'](theVar).length * 2;
}
case 'number' : {
return 8;
}
case 'boolean' : {
return 4;
}
case 'object' : {
if ( theVar instanceof String) {
var encoder = new TextEncoder();
encoder['encoding'] = "utf-16";
return encoder['encode'](theVar.toString()).length * 2;
} else {
return 0;
}
}
}
}
else {
return 0;
}
}
The getBytesFromVar function take a var and return the number of byte used.
Function use TextEncoder to get the string length and then calculate the bytes.
In case of a string created with:
let str = new String('Alain♥');
function will work with String objects.
ATTENTION: this can't be used to calculate memory footprint in browser as other mechanism of memory management can increase/decrease this values.
Vars can be allocated in different memory segment. For example, String object are created on the heap and string vars are created on string constant pool.
Also vars are manipulated through pointer.
For example, 2 strings vars that contain the same string are created on the string constant pool. First will be allocated, but the second one will be a pointer to the first one. So the size in memory byte will not be simply twice the size of the string.
Good post about that: https://levelup.gitconnected.com/bytefish-vs-new-string-bytefish-what-is-the-difference-a795f6a7a08b
Use case:
var myString='Alain♥';
var myNumber = 120;
var objString = new String('Alain♥');
var myFloat = 105.456;
console.log('%o is %o bytes', myString, getBytesFromVar(myString));
console.log('%o is %o bytes', myNumber, getBytesFromVar(myNumber));
console.log('%o is %o bytes', objString, getBytesFromVar(objString));
console.log('%o is %o bytes', myFloat, getBytesFromVar(myFloat));
I have used the npm module object-sizeof for this. You can use it to get the size of integer or string variables in bytes. This is a sample usage,
var sizeof = require('object-sizeof');
console.log(sizeof(123)); //prints 8
You can do that natively with the help of TextEncoder
let str1 = 'Beta'; // 'Beta' text in English
let str2 = '贝塔'; // 'Beta' text in Chinese
const encoder = new TextEncoder();
const len1 = encoder.encode(str1).length;
const len2 = encoder.encode(str2).length;
console.log(len1); // 4
console.log(len2); // 6

Typescript interface set values based on logic

I have a typescript interface which is defined as:
interface FutureProjection{
month1: number;
month2: number;
.
.
.
.
.
.
month12: number;
}
This data is used to show the grid on the UI.
I have a logic which is used to find out which month to set data:
calculateMonthNum(currentDate:String,futureDate: String):number{
//Calculate the month difference between future and current.
return monthDiff;
}
functionToSetMonthData(currentDate:String,futureDate: String, projection: FutureProjection, amount: number): FutureProjection{
const monthNum = calculateDiff(currentDate,futureDate);
****//How to do this?? vvvv **
projection.month+monthNum = amount; //. <---This assignment operation???
return projection;
}
You can always use bracket syntax to access a property of any javascript object.
// identical
projection['month1']
projection.month1
Which means you can build a string that is the property name and use that in brackets:
projection[`month${monthNum}`] = amount;
But in typescript that only get you half way there. This will get you a type error:
type 'string' can't be used to index type 'FutureProjection'.
The problem is that FutureProjection cannot be indexed by string, only specific strings are allowed. So typescript doesn't know that month${monthNum} is a specific string that is actually valid since monthNum could be any number (-5, 0, 100, 3.14159, etc).
The easiest way to solve that is cast the key string to a keyof FutureProjection. Note that in order for this to be safe you must ensure that calculateDiff() only ever returns integers 1 through 12.
That looks something like:
function setMonthData(currentDate:String,futureDate: String, projection: FutureProjection, amount: number): FutureProjection{
const monthNum = calculateDiff(currentDate, futureDate);
const monthKey = `month${monthNum}` as keyof FutureProjection
projection[monthKey] = amount;
return projection;
}
Working example on typescript playground
All that said, it may make your life easier to use an array instead.
You can achieve that like the following:
projection[`month${monthNum}`] = amount;
FYI, as an alternative to a string index signature like
interface FutureProjection {
[k: string]: number
}
which would accept any key whatsoever:
declare const f: FutureProjection
f.oopsiedaisy = 123; // no compiler error
one might consider using a template string pattern index signature as introduced in TypeScript 4.4 to accept only strings that start with "month" and are followed by a numeric-like string:
interface FutureProjection {
[k: `month${number}`]: number
}
declare const f: FutureProjection
f.oopsiedaisy = 123; // error
f.month11 = 456; // okay
f.month1234567 = 789; // this is also okay, any number is accepted
If you do it this way, then the compiler will automatically allow you to index into a FutureProjection with an appropriately constructed template literal string:
function functionToSetMonthData(currentDate: string, futureDate: string,
projection: FutureProjection, amount: number
): FutureProjection {
const monthNum = calculateMonthNum(currentDate, futureDate);
projection[`month${monthNum}`] = amount; // okay
return projection;
}
Note that this doesn't quite serve the purpose of only accepting month1 through month12. You could decide to replace number with a union of numeric literal types,
type MonthNumber = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12;
interface FutureProjection extends Record<`month${MonthNumber}`, number> { }
declare const f: FutureProjection
f.oopsiedaisy = 123; // error
f.month11 = 456; // okay
f.month1234567 = 789; // error
which is great; unfortunately you'd have a hard time convincing the compiler that any of your mathematical operations that produce number are really producing a MonthNumber, since it doesn't really do math at the type level (see microsoft/TypeScript#15645):
declare const i: MonthNumber;
const j: MonthNumber = 13 - i; // error, even though this must be safe
const k: MonthNumber = ((i + 6) % 12) || 12; // error, ditto
And so you'd find yourself doing unsafe assertions no matter what as well as some other workarounds:
function calculateMonthNum(currentDate: string, futureDate: string): MonthNumber {
return (((((new Date(futureDate).getMonth() - new Date(currentDate).getMonth())
% 12) + 12) % 12) || 12) as MonthNumber // <-- assert here
}
function functionToSetMonthData(currentDate: string, futureDate: string,
projection: FutureProjection, amount: number
): FutureProjection {
const monthNum = calculateMonthNum(currentDate, futureDate);
projection[`month${monthNum}` as const] = amount; // <-- const assert here
return projection;
}
const f = {} as FutureProjection; // assert here
for (let i = 1; i <= 12; i++) f[`month${i as MonthNumber}`] = 0; // assert here
So I'm kind of thinking you'd be better off with `month${number}`.
Playground link to code
I would do like this...
projection[`month${monthNum }`] = amount;
Try to define the interface like
interface FutureProjection {
[month: string]: number
}
then set values into the object using template strings
projection[`month${monthNum}`] = amount;

64bit Hex to Decimal in Javascript

Need to convert 64bit hex to decimal in node, preferably without 3rd party lib.
Input:
Hex: 0x3fe2da2f8bdec5f4
Hex: 0x402A000000000000
Output
Dec: .589134
Dec: 13
You can do this very easily in node.js without any libraries by using Buffer:
const hex = '3fe2da2f8bdec5f4';
const result = Buffer.from( hex, 'hex' ).readDoubleBE( 0 );
console.log( result );
WARNING: The offset of 0 is not optional. Several versions of the node.js API docs show examples of not supplying an offset for most Buffer functions and it being treated as an offset of 0, but due to a bug in node.js versions 9.4.0, 9.5.0, 9.6.0, 9.6.1, and 9.7 you will get slightly incorrect results (EG. 13.000001912238076 instead of exactly 13) if you do not specify an offset to readDoubleBE in those versions.
For those trying to do this in client side javscript
// Split the array by bytes
a = "3fe2da2f8bdec5f4"
b = a.match(/.{2}/g);
// Create byte array
let buffer = new ArrayBuffer(8)
let bytes = new Uint8Array(buffer)
// Populate array
for(let i = 0; i < 8; ++i) {
bytes[i] = parseInt(b[i], 16);
}
// Convert and print
let view = new DataView(buffer)
console.log(view.getFloat64(0, false));

C# SHA256 ComputeHash result different with CryptoJS SHA256 function

I have a C# function as below:
string stringvalue = "530500480530490480530480480520570480520510500490";
var encodedvalue= Encoding.Unicode.GetBytes(stringvalue);
using (HashAlgorithm ssp = System.Security.Cryptography.HashAlgorithm.Create("SHA256"))
{
var digest = ssp.ComputeHash(encodedvalue);
return BitConverter.ToString(digest);
}
I need to create a javascript function that match the code above so that the end result for both C# and JS is the same.
Currently in my JS code, I'm using this:
var hash = CryptoJS.SHA256("530500480530490480530480480520570480520510500490");
var hexhash = hash.toString(CryptoJS.enc.hex);
This is the result of my hexhash:
d956678c8f12c65299daf35019a9a1eb3e6eb9855fd850aeb5aafe46057d179e
But in my C# code, this line of var digest = ssp.ComputeHash(bPass); return the following array:
I don't know much about encoding. Please tell me what type of result is being populated in the c# code above? If I'm not mistaken, the ComputeHash is returning bytes but I need lots of reading to confirm that which is another long hour of studying
I tried many different ways of converting the JS Sha256 code but no luck. I'm stuck at this particular line for almost a day.
Please help. Thanks
EDIT:
Sorry for the code error. I had updated the C# code. ComputeHash accept an array
In my example I am using System.Security.Cryptography.SHA256Managed to get SHA256 in C#.
The method SHA256Managed.ComputeHash takes a byte array as a parameter and return another byte array. Now we need to convert back your byte array to a string.
The following code return the same result a Javascript SHA-256.
byte[] bytes = Encoding.UTF8.GetBytes("530500480530490480530480480520570480520510500490");
SHA256Managed hashstring = new SHA256Managed();
byte[] hash = hashstring.ComputeHash(bytes);
string hashString = string.Empty;
foreach (byte x in hash)
{
hashString += String.Format("{0:x2}", x);
}
return(hashString);
Just to explain : String.Format("{0:x2}", x)
X means Hexadecimal format.
2 means 2 characters.
I finally found the answer after uncountable hours of trial and error.
The C# code var digest = ssp.ComputeHash(encodedvalue) is returning byte array from the result of var encodedvalue= Encoding.Unicode.GetBytes(stringvalue); as Jean replied. In order to create the function in Javascript, I need to ensure that the encodedvalue is producing the correct encoding format and size just like the one in C#.
Using only CryptoJS, I manage to get the matching result from below
function GetHexFromString() {
var stringVal = '8563A578-7402-4567-A6CE-4DE4E0825B021234';
// Convert the string to UTF 16 little-endian
// Result: 560530540510650530550560450550520480500450520530540550450650540670690450520680690520690480560500530660480500490500510520
var utf16le = CryptoJS.enc.Utf16LE.parse(stringVal);
// Convert to Sha256 format and get the word array
var utf16Sha256 = CryptoJS.SHA256(utf16le);
// Convert the Sha256 word array to Uint8Array to get the 32 byte array just to see the result to ensure it match with the C# function
// Result: 94,203,69,29,35,202,209,149,121,144,44,6,98,250,141,161,102,7,238,35,228,117,111,236,118,115,51,113,134,72,52,69
var utf16sha256Array = convertWordArrayToUint8Array(utf16Sha256);
// Convert the Sha256 to hex (if i'm not mistaken, it's base 16) format
var hexSha256 = utf16Sha256.toString(CryptoJS.enc.hex);
// Insert a dash in between 2 characters in the string
hexSha256 = hexSha256.replace(/(\S{2})/g, "$1-");
// Remove the last dash in the string
hexSha256 = hexSha256.replace(/-$/, "");
// Final Result: 5E-CB-45-1D-23-CA-D1-95-79-90-2C-06-62-FA-8D-A1-66-07-EE-23-E4-75-6F-EC-76-73-33-71-86-48-34-45
return hexSha256.toUpperCase();
}
function convertWordArrayToUint8Array(wordArray) {
var len = wordArray.words.length,
u8_array = new Uint8Array(len << 2),
offset = 0, word, i
;
for (i = 0; i < len; i++) {
var word = wordArray.words[i];
u8_array[offset++] = word >> 24;
u8_array[offset++] = (word >> 16) & 0xff;
u8_array[offset++] = (word >> 8) & 0xff;
u8_array[offset++] = word & 0xff;
}
return u8_array;
}
Hope it help whoever that need such method
An alternative to Koo SengSeng's answer (if you don't want to use CryptoJS library).
SHA256 function is from here, the arrToUintArr function is from Koo SengSeng's answer.
var SHA256=function a(b){function c(a,b){return a>>>b|a<<32-b}for(var d,e,f=Math.pow,g=f(2,32),h="length",i="",j=[],k=8*b[h],l=a.h=a.h||[],m=a.k=a.k||[],n=m[h],o={},p=2;64>n;p++)if(!o[p]){for(d=0;313>d;d+=p)o[d]=p;l[n]=f(p,.5)*g|0,m[n++]=f(p,1/3)*g|0}for(b+="\x80";b[h]%64-56;)b+="\x00";for(d=0;d<b[h];d++){if(e=b.charCodeAt(d),e>>8)return;j[d>>2]|=e<<(3-d)%4*8}for(j[j[h]]=k/g|0,j[j[h]]=k,e=0;e<j[h];){var q=j.slice(e,e+=16),r=l;for(l=l.slice(0,8),d=0;64>d;d++){var s=q[d-15],t=q[d-2],u=l[0],v=l[4],w=l[7]+(c(v,6)^c(v,11)^c(v,25))+(v&l[5]^~v&l[6])+m[d]+(q[d]=16>d?q[d]:q[d-16]+(c(s,7)^c(s,18)^s>>>3)+q[d-7]+(c(t,17)^c(t,19)^t>>>10)|0),x=(c(u,2)^c(u,13)^c(u,22))+(u&l[1]^u&l[2]^l[1]&l[2]);l=[w+x|0].concat(l),l[4]=l[4]+w|0}for(d=0;8>d;d++)l[d]=l[d]+r[d]|0}for(d=0;8>d;d++)for(e=3;e+1;e--){var y=l[d]>>8*e&255;i+=(16>y?0:"")+y.toString(16)}return i};
var arrToUintArr=function(a){for(var l=a.length,b=new Uint8Array(l<<2),o=0,w,i=0;i<l;i++) w=a[i],b[o++]=w>>24,b[o++]=(w>>16)&0xff,b[o++]=(w>>8)&0xff,b[o++]=w&0xff;return b;}
var computeHash=function(k){for(var a=[],s=SHA256(k),i=0;i<8;i++) a.push(parseInt(s.substr(i*8,8),16));return arrToUintArr(a);}
computeHash(k) will return an array of numbers representing bytes.
This is equal to below code in C#:
new System.Security.Cryptography.SHA256CryptoServiceProvider().ComputeHash(Encoding.UTF8.GetBytes(k));
Try
var digest = ssp.ComputeHash(Encoding.UTF8.GetBytes(stringvalue))
return BitConverter.ToString(digest)
.Replace("-", string.Empty)
.ToLowerInvariant();
That js library is converting the string to UTF8 before calculating its hash.
typescript code:
private computeHash(text: string): string {
return CryptoJS.SHA256(text).toString();
}
c# equivalent:
private string ComputeHash(string text)
{
using (var sha256 = SHA256.Create())
{
var bytes = Encoding.UTF8.GetBytes(text);
var hash = sha256.ComputeHash(bytes);
return hash.Aggregate(string.Empty, (current, x) => current + $"{x:x2}");
}
}
after two days of research it works perfectly! Two different codes give the same result.
js
const sha1 = require('sha1');
const getHash = str =>{
const hashingBytes = Buffer.from(sha1(str), "hex");
const base64Value = Buffer.from(hashingBytes).toString('base64');
return base64Value;
}
c#
System.Security.Cryptography.SHA1 sha = new System.Security.Cryptography.SHA1CryptoServiceProvider();
byte[] bytes = System.Text.Encoding.ASCII.GetBytes(str);
byte[] hashingbytes = sha.ComputeHash(bytes);
var hash = Convert.ToBase64String(hashingbytes);

Is there any way to create mongodb like _id strings without mongodb?

I really like the format of the _ids generated by mongodb. Mostly because I can pull data like the date out of them client side. I'm planning to use another database but still want that type of _id for my document. How can I create these ids without using mongodb?
Thanks!
A very easy pseudo ObjectId generator in javascript:
const ObjectId = (m = Math, d = Date, h = 16, s = s => m.floor(s).toString(h)) =>
s(d.now() / 1000) + ' '.repeat(h).replace(/./g, () => s(m.random() * h))
Use the official MongoDB BSON lib in the client
I have a browser client that generates ObjectIds. I wanted to make sure that I employ the same ObjectId algorithm in the client as the one used in the server. MongoDB has js-bson which can be used to accomplish that.
If you are using javascript with node.
npm install --save bson
Using require statement
var ObjectID = require('bson').ObjectID;
var id = new ObjectID();
console.log(id.toString());
Using ES6 import statement
import { ObjectID } from 'bson';
const id = new ObjectID();
console.log(id.toString());
The library also lets you import using good old script tags but I have not tried this.
Object IDs are usually generated by the client, so any MongoDB driver would have code to generate them.
If you're looking for JavaScript, here's some code from the MongoDB Node.js driver:
https://github.com/mongodb/js-bson/blob/1.0-branch/lib/bson/objectid.js
And another, simpler solution:
https://github.com/justaprogrammer/ObjectId.js
Extending Rubin Stolk's and ChrisV's answer in a more readable syntax (KISS).
function objectId () {
return hex(Date.now() / 1000) +
' '.repeat(16).replace(/./g, () => hex(Math.random() * 16))
}
function hex (value) {
return Math.floor(value).toString(16)
}
export default objectId
ruben-stolk's answer is great, but deliberately opaque? Very slightly easier to pick apart is:
const ObjectId = (rnd = r16 => Math.floor(r16).toString(16)) =>
rnd(Date.now()/1000) + ' '.repeat(16).replace(/./g, () => rnd(Math.random()*16));
(actually in slightly fewer characters). Kudos though!
This is a simple function to generate a new objectId
newObjectId() {
const timestamp = Math.floor(new Date().getTime() / 1000).toString(16);
const objectId = timestamp + 'xxxxxxxxxxxxxxxx'.replace(/[x]/g, () => {
return Math.floor(Math.random() * 16).toString(16);
}).toLowerCase();
return objectId;
}
Here's a link! to a library to do that.
https://www.npmjs.com/package/mongo-object-reader
You can read and write hexadecimal strings.
const { createObjectID, readObjectID,isValidObjectID } = require('mongo-object-reader');
//Creates a new immutable `ObjectID` instance based on the current system time.
const ObjectID = createObjectID() //a valid 24 character `ObjectID` hex string.
//returns boolean
// input - a valid 24 character `ObjectID` hex string.
const isValid = isValidObjectID(ObjectID)
//returns an object with data
// input - a valid 24 character `ObjectID` hex string.
const objectData = readObjectID(ObjectID)
console.log(ObjectID) //ObjectID
console.log(isValid) // true
console.log(objectData) /*
{ ObjectID: '5e92d4be2ced3f58d92187f5',
timeStamp:
{ hex: '5e92d4be',
value: 1586681022,
createDate: 1970-01-19T08:44:41.022Z },
random: { hex: '2ced3f58d9', value: 192958912729 },
incrementValue: { hex: '2187f5', value: 2197493 } }
*/
There is a detailed specification here
http://www.mongodb.org/display/DOCS/Object+IDs
Which you can use to roll your own id strings

Categories

Resources