I am doing some animation jobs. I need to pack some pivots into UV and then my shader can read them.
I need to pack 4 float3 into a float4. Therefore, I need to pack each float3 into a float.
These 4 float3 are (model space position1, direction1, model space position2, direction2). I know how to handle the directions because they are normalized. I can use something like:
#define f3_f(c) (dot(round((c) * 255), float3(65536, 256, 1)))
#define f_f3(f) (frac((f) / float3(16777216, 65536, 256)))
But how can I handle positions? I am using SM3.0 and I can't use bitwise operation.
Do you really need to pack it into a float (4 bytes), or can you pack it into a 32-bit unsigned integer (i.e. 4 bytes)?
If, so take a look at the code in DirectXMath for converting to/from various formats as done in DirectXTex such as DXGI_FORMAT_R11G11B10_FLOAT. Since this format is positive only, you'll have to do a scale and bias to/from the format to handle the [-1,+1] range, but that's easy to do (0.5*value + 0.5 <-> 2*value - 1).
// 3D vector: 11/11/10 floating-point components
// The 3D vector is packed into 32 bits as follows: a 5-bit biased exponent
// and 6-bit mantissa for x component, a 5-bit biased exponent and
// 6-bit mantissa for y component, a 5-bit biased exponent and a 5-bit
// mantissa for z. The z component is stored in the most significant bits
// and the x component in the least significant bits. No sign bits so
// all partial-precision numbers are positive.
// (Z10Y11X11): [32] ZZZZZzzz zzzYYYYY yyyyyyXX XXXxxxxx [0]
struct XMFLOAT3PK
{
union
{
struct
{
uint32_t xm : 6; // x-mantissa
uint32_t xe : 5; // x-exponent
uint32_t ym : 6; // y-mantissa
uint32_t ye : 5; // y-exponent
uint32_t zm : 5; // z-mantissa
uint32_t ze : 5; // z-exponent
};
uint32_t v;
};
XMFLOAT3PK() = default;
XMFLOAT3PK(const XMFLOAT3PK&) = default;
XMFLOAT3PK& operator=(const XMFLOAT3PK&) = default;
XMFLOAT3PK(XMFLOAT3PK&&) = default;
XMFLOAT3PK& operator=(XMFLOAT3PK&&) = default;
explicit XM_CONSTEXPR XMFLOAT3PK(uint32_t Packed) : v(Packed) {}
XMFLOAT3PK(float _x, float _y, float _z);
explicit XMFLOAT3PK(_In_reads_(3) const float *pArray);
operator uint32_t () const { return v; }
XMFLOAT3PK& operator= (uint32_t Packed) { v = Packed; return *this; }
};
// Converts float3 to the 11/11/10 format
inline void XM_CALLCONV XMStoreFloat3PK
(
XMFLOAT3PK* pDestination,
FXMVECTOR V
)
{
assert(pDestination);
__declspec(align(16)) uint32_t IValue[4];
XMStoreFloat3A( reinterpret_cast<XMFLOAT3A*>(&IValue), V );
uint32_t Result[3];
// X & Y Channels (5-bit exponent, 6-bit mantissa)
for(uint32_t j=0; j < 2; ++j)
{
uint32_t Sign = IValue[j] & 0x80000000;
uint32_t I = IValue[j] & 0x7FFFFFFF;
if ((I & 0x7F800000) == 0x7F800000)
{
// INF or NAN
Result[j] = 0x7c0;
if (( I & 0x7FFFFF ) != 0)
{
Result[j] = 0x7c0 | (((I>>17)|(I>>11)|(I>>6)|(I))&0x3f);
}
else if ( Sign )
{
// -INF is clamped to 0 since 3PK is positive only
Result[j] = 0;
}
}
else if ( Sign )
{
// 3PK is positive only, so clamp to zero
Result[j] = 0;
}
else if (I > 0x477E0000U)
{
// The number is too large to be represented as a float11, set to max
Result[j] = 0x7BF;
}
else
{
if (I < 0x38800000U)
{
// The number is too small to be represented as a normalized float11
// Convert it to a denormalized value.
uint32_t Shift = 113U - (I >> 23U);
I = (0x800000U | (I & 0x7FFFFFU)) >> Shift;
}
else
{
// Rebias the exponent to represent the value as a normalized float11
I += 0xC8000000U;
}
Result[j] = ((I + 0xFFFFU + ((I >> 17U) & 1U)) >> 17U)&0x7ffU;
}
}
// Z Channel (5-bit exponent, 5-bit mantissa)
uint32_t Sign = IValue[2] & 0x80000000;
uint32_t I = IValue[2] & 0x7FFFFFFF;
if ((I & 0x7F800000) == 0x7F800000)
{
// INF or NAN
Result[2] = 0x3e0;
if ( I & 0x7FFFFF )
{
Result[2] = 0x3e0 | (((I>>18)|(I>>13)|(I>>3)|(I))&0x1f);
}
else if ( Sign )
{
// -INF is clamped to 0 since 3PK is positive only
Result[2] = 0;
}
}
else if ( Sign )
{
// 3PK is positive only, so clamp to zero
Result[2] = 0;
}
else if (I > 0x477C0000U)
{
// The number is too large to be represented as a float10, set to max
Result[2] = 0x3df;
}
else
{
if (I < 0x38800000U)
{
// The number is too small to be represented as a normalized float10
// Convert it to a denormalized value.
uint32_t Shift = 113U - (I >> 23U);
I = (0x800000U | (I & 0x7FFFFFU)) >> Shift;
}
else
{
// Rebias the exponent to represent the value as a normalized float10
I += 0xC8000000U;
}
Result[2] = ((I + 0x1FFFFU + ((I >> 18U) & 1U)) >> 18U)&0x3ffU;
}
// Pack Result into memory
pDestination->v = (Result[0] & 0x7ff)
| ( (Result[1] & 0x7ff) << 11 )
| ( (Result[2] & 0x3ff) << 22 );
}
// Converts the 11/11/10 format to float3
inline XMVECTOR XM_CALLCONV XMLoadFloat3PK
(
const XMFLOAT3PK* pSource
)
{
assert(pSource);
__declspec(align(16)) uint32_t Result[4];
uint32_t Mantissa;
uint32_t Exponent;
// X Channel (6-bit mantissa)
Mantissa = pSource->xm;
if ( pSource->xe == 0x1f ) // INF or NAN
{
Result[0] = static_cast<uint32_t>(0x7f800000 | (static_cast<int>(pSource->xm) << 17));
}
else
{
if ( pSource->xe != 0 ) // The value is normalized
{
Exponent = pSource->xe;
}
else if (Mantissa != 0) // The value is denormalized
{
// Normalize the value in the resulting float
Exponent = 1;
do
{
Exponent--;
Mantissa <<= 1;
} while ((Mantissa & 0x40) == 0);
Mantissa &= 0x3F;
}
else // The value is zero
{
Exponent = static_cast<uint32_t>(-112);
}
Result[0] = ((Exponent + 112) << 23) | (Mantissa << 17);
}
// Y Channel (6-bit mantissa)
Mantissa = pSource->ym;
if ( pSource->ye == 0x1f ) // INF or NAN
{
Result[1] = static_cast<uint32_t>(0x7f800000 | (static_cast<int>(pSource->ym) << 17));
}
else
{
if ( pSource->ye != 0 ) // The value is normalized
{
Exponent = pSource->ye;
}
else if (Mantissa != 0) // The value is denormalized
{
// Normalize the value in the resulting float
Exponent = 1;
do
{
Exponent--;
Mantissa <<= 1;
} while ((Mantissa & 0x40) == 0);
Mantissa &= 0x3F;
}
else // The value is zero
{
Exponent = static_cast<uint32_t>(-112);
}
Result[1] = ((Exponent + 112) << 23) | (Mantissa << 17);
}
// Z Channel (5-bit mantissa)
Mantissa = pSource->zm;
if ( pSource->ze == 0x1f ) // INF or NAN
{
Result[2] = static_cast<uint32_t>(0x7f800000 | (static_cast<int>(pSource->zm) << 17));
}
else
{
if ( pSource->ze != 0 ) // The value is normalized
{
Exponent = pSource->ze;
}
else if (Mantissa != 0) // The value is denormalized
{
// Normalize the value in the resulting float
Exponent = 1;
do
{
Exponent--;
Mantissa <<= 1;
} while ((Mantissa & 0x20) == 0);
Mantissa &= 0x1F;
}
else // The value is zero
{
Exponent = static_cast<uint32_t>(-112);
}
Result[2] = ((Exponent + 112) << 23) | (Mantissa << 18);
}
return XMLoadFloat3A( reinterpret_cast<const XMFLOAT3A*>(&Result) );
}
Related
I need to implement my own packets to send over UDP. I decided that I would do this by sending a char buffer which has the sequence number, checksum, size, and the data of the packet which is bytes from a file. The string i'm sending separates each field by a semicolon. Then, when I receive the string (which is my packet) I want to extract each felid, use them accordingly (the sequence number, size, and checksum) and write the bytes to a file. So far I have wrote a method to create 100 packets, and I'm trying to extract and write the bytes to a file (I'm not doing it in the receiver yet, first I'm testing the parsing in the sender). For some reason, the bytes written to my file are incorrect and I'm getting "JPEG DATATSTREAM CONTAINS NO IMAGE" error when I try to open it.
struct packetNode{
char packet[1052]; // this is the entire packet data including the header
struct packetNode *next;
};
This is how I'm creating my packets:
//populate initial window of size 100
for(i = 0; i < 100; i++){
memset(&data[0], 0, sizeof(data));
struct packetNode *p; // create packet node
p = (struct packetNode *)malloc(sizeof(struct packetNode));
bytes = fread(data, 1, sizeof(data), fp); // read 1024 bytes from file into data buffer
int b = fwrite(data, 1, bytes, fpNew);
printf("read: %d\n", bytes);
memset(&p->packet[0], 0, sizeof(p->packet));
sprintf(p->packet, "%d;%d;%d;%s", s, 0, numPackets, data); // create packet
//calculate checksum
int check = checksum8(p->packet, sizeof(p->packet));
sprintf(p->packet, "%d;%d;%d;%s", s, check, numPackets, data); //put checksum in packet
s++; //incremenet sequence number
if(i == 0){
head = p;
tail = p;
tail->next = NULL;
}
else{
tail->next = p;
tail = p;
tail->next = NULL;
}
}
fclose(fp);
and this is where I parse and write the bytes to a file:
void test(){
FILE *fpNew = fopen("test.jpg", "w");
struct packetNode *ptr = head;
char *tokens;
int s, c, size;
int i = 0;
char data[1024];
while(ptr != NULL){
memset(&data[0], 0, sizeof(data));
tokens = strtok(ptr->packet,";");
s = atoi(tokens);
tokens = strtok(NULL, ";");
c = atoi(tokens);
tokens = strtok(NULL, ";");
size = atoi(tokens);
tokens = strtok(NULL, ";");
if(tokens != NULL)
strcpy(data, tokens);
printf("sequence: %d, checksum: %d, size: %d\n", s,c,size);
int b = fwrite(data, 1, sizeof(data), fpNew);
ptr = ptr->next;
i++;
}
fclose(fpNew);
}
Since there is transfer of binary data, a JPEG stream, this data cannot be treated as a string. It's better to go all binary. For instance, instead of
sprintf(p->packet, "%d;%d;%d;%s", s, 0, numPackets, data); // create packet
you would do
sprintf(p->packet, "%d;%d;%d;", s, 0, numPackets);
memcpy(&p->packet[strlen(p->packet)], data, bytes);
but this leads to parsing problems: we would need to change this:
tokens = strtok(NULL, ";");
if(tokens != NULL)
strcpy(data, tokens);
to something like this:
tokens += 1 + ( size < 10 ? 1 : size < 100 ? 2 : size < 1000 ? 3 : size < 10000 ? 4 : 5 );
memcpy(data, tokens, sizeof(data));
#Binary Protocol
It's easier to use a binary packet:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#pragma push(pack,1)
typedef struct Packet {
int seq, maxseq, size;
unsigned short cksum;
unsigned char payload[];
} Packet;
#pragma pop(pack)
typedef struct PacketNode{
struct PacketNode * next;
Packet packet;
} PacketNode;
PacketNode * allocPacketNode(int maxPayloadSize) {
void * ptr = malloc(sizeof(PacketNode) + maxPayloadSize); // FIXME: error checking
memset(ptr, 0, sizeof(PacketNode) + maxPayloadSize); // mallocz wouldn't cooperate
return (PacketNode*) ptr;
}
PacketNode * prepare(FILE * fp, int fsize, int chunksize)
{
PacketNode * head = allocPacketNode(chunksize);
PacketNode * pn = head;
int rd, seq = 0;
int maxseq = fsize / chunksize + ( fsize % chunksize ? 1 : 0 );
while ( ( rd = fread(pn->packet.payload, 1, chunksize, fp ) ) > 0 )
{
printf("read %d bytes\n", rd);
pn->packet.seq = seq++;
pn->packet.maxseq = maxseq;
pn->packet.size = rd + sizeof(Packet);
pn->packet.cksum = 0;
pn->packet.cksum = ~checksum(&pn->packet, pn->packet.size);
if ( rd == chunksize )
pn = pn->next = allocPacketNode(chunksize);
}
return head;
}
int checksum(unsigned char * data, int len)
{
int sum = 0, i;
for ( i = 0; i < len; i ++ )
sum += data[i];
if ( sum > 0xffff )
sum = (sum & 0xffff) + (sum>>16);
return sum;
}
void test( PacketNode * ptr ) {
FILE *fpNew = fopen("test.jpg", "w");
while (ptr != NULL)
{
printf("sequence: %d/%d, checksum: %04x, size: %d\n",
ptr->packet.seq,
ptr->packet.maxseq,
ptr->packet.cksum,
ptr->packet.size - sizeof(Packet)
);
int b = fwrite(ptr->packet.payload, ptr->packet.size - sizeof(Packet), 1, fpNew);
ptr = ptr->next;
}
fclose(fpNew);
}
void fatal( const char * msg ) { printf("FATAL: %s\n", msg); exit(1); }
int main(int argc, char** argv)
{
if ( ! argv[1] ) fatal( "missing filename argument" );
FILE * fp = fopen( argv[1], "r" );
if ( ! fp ) fatal( "cannot open file" );
fseek( fp, 0, SEEK_END );
long fsize = ftell(fp);
fseek( fp, 0, SEEK_SET );
printf("Filesize: %d\n", fsize );
test( prepare(fp, fsize, 1024) );
}
The #pragma push(pack,1) changes how the compiler aligns fields of the struct. We want them to be compact, for network transport. Using 1 is byte-aligned. The #pragma pop(pack) restores the previous setting of the pack pragma.
A note on the checksum method
First we calculate the sum of all the bytes in the packet:
int sum = 0, i;
for ( i = 0; i < len; i ++ )
sum += data[i];
Since the packet uses an unsigned short (16 bits, max value 65535 or 0xffff) to store the checksum, we make sure that the result will fit:
if ( sum > 0xffff ) // takes up more than 16 bits.
Getting the low 16 bits of this int is done using sum & 0xffff, masking out everything but the low 16 bits. We could simply return this value, but we would loose the information from higher checksum bits. So, we will add the upper 16 bits to the lower 16 bits. Accessing the higher 16 bits is done by shifting the int to the right 16 bits, like so: sum >> 16. This is the same as sum / 65536, since 65536 = 216 = 1 << 16.
sum = (sum & 0xffff) + (sum>>16); // add low 16 bits and high 16 bits
I should note that network packet checksums are usually computed 2 bytes (or 'octets' as they like to call them there) at a time. For that, the data should be cast to an unsigned short *, and len should be divided by 2. However! len may be odd, so in that case we'll need to take special care of the last byte. For instance, assuming that the maximum packet size is even, and that the len argument is always <= max_packet_size:
unsigned short * in = (unsigned short *) data;
if ( len & 1 ) data[len] = 0; // make sure last byte is 0
len = (len + 1) / 2;
The rest of the checksum method can remain the same, except that it should operate on in instead of data.
My application is receiving information from smart heart device. Now i can see pulse value. Could you please help me to parse R-R Interval value? How can i check device support R-R Interval value or Not ?
Any advise from you
Thanks
Have you checked the Bluetooth spec? The sample code below is in C#, but I think it shows the way to parse the data in each heart rate packet.
//first byte of heart rate record denotes flags
byte flags = heartRateRecord[0];
ushort offset = 1;
bool HRC2 = (flags & 1) == 1;
if (HRC2) //this means the BPM is un uint16
{
short hr = BitConverter.ToInt16(heartRateRecord, offset);
offset += 2;
}
else //BPM is uint8
{
byte hr = heartRateRecord[offset];
offset += 1;
}
//see if EE is available
//if so, pull 2 bytes
bool ee = (flags & (1 << 3)) != 0;
if (ee)
offset += 2;
//see if RR is present
//if so, the number of RR values is total bytes left / 2 (size of uint16)
bool rr = (flags & (1 << 4)) != 0;
if (rr)
{
int count = (heartRateRecord.Length - offset)/2;
for (int i = 0; i < count; i++)
{
//each existence of these values means an R-Wave was already detected
//the ushort means the time (1/1024 seconds) since last r-wave
ushort value = BitConverter.ToUInt16(heartRateRecord, offset);
double intervalLengthInSeconds = value/1024.0;
offset += 2;
}
}
This post is a little old but a full answer has not been given.
As I run into this post and it did help me at the end, I would like to share my final code. Hopefully it will help others.
The code provided by Daniel Judge is actually right, but as he already wrote, it is C#. HIs code is a bit better compared to what Simon M came up with at the end as the code of Daniel Judge takes into account there can be more than two RR-values within one message.
Here is the actual spec of the Heart_rate_measurement characteristic
I have translated Daniel Judge his code to Objective-C:
// Instance method to get the heart rate BPM information
- (void) getHeartBPMData:(CBCharacteristic *)characteristic error:(NSError *)error
{
// Get the BPM //
// https://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.heart_rate_measurement.xml //
// Convert the contents of the characteristic value to a data-object //
NSData *data = [characteristic value];
// Get the byte sequence of the data-object //
const uint8_t *reportData = [data bytes];
// Initialise the offset variable //
NSUInteger offset = 1;
// Initialise the bpm variable //
uint16_t bpm = 0;
// Next, obtain the first byte at index 0 in the array as defined by reportData[0] and mask out all but the 1st bit //
// The result returned will either be 0, which means that the 2nd bit is not set, or 1 if it is set //
// If the 2nd bit is not set, retrieve the BPM value at the second byte location at index 1 in the array //
if ((reportData[0] & 0x01) == 0) {
// Retrieve the BPM value for the Heart Rate Monitor
bpm = reportData[1];
offset = offset + 1; // Plus 1 byte //
}
else {
// If the second bit is set, retrieve the BPM value at second byte location at index 1 in the array and //
// convert this to a 16-bit value based on the host’s native byte order //
bpm = CFSwapInt16LittleToHost(*(uint16_t *)(&reportData[1]));
offset = offset + 2; // Plus 2 bytes //
}
NSLog(#"bpm: %i", bpm);
// Determine if EE data is present //
// If the 3rd bit of the first byte is 1 this means there is EE data //
// If so, increase offset with 2 bytes //
if ((reportData[0] & 0x03) == 1) {
offset = offset + 2; // Plus 2 bytes //
}
// Determine if RR-interval data is present //
// If the 4th bit of the first byte is 1 this means there is RR data //
if ((reportData[0] & 0x04) == 0)
{
NSLog(#"%#", #"Data are not present");
}
else
{
// The number of RR-interval values is total bytes left / 2 (size of uint16) //
NSUInteger length = [data length];
NSUInteger count = (length - offset)/2;
NSLog(#"RR count: %lu", (unsigned long)count);
for (int i = 0; i < count; i++) {
// The unit for RR interval is 1/1024 seconds //
uint16_t value = CFSwapInt16LittleToHost(*(uint16_t *)(&reportData[offset]));
value = ((double)value / 1024.0 ) * 1000.0;
offset = offset + 2; // Plus 2 bytes //
NSLog(#"RR value %lu: %u", (unsigned long)i, value);
}
}
}
EDIT:
this work for me, i get the correct rr values:
In some cases you can find two values at the same time for rr.
- (void) updateWithHRMData:(NSData *)datas {
const uint8_t *reportData = [datas bytes];
uint16_t bpm = 0;
uint16_t bpm2 = 0;
if ((reportData[0] & 0x04) == 0)
{
NSLog(#"%#", #"Data are not present");
}
else
{
bpm = CFSwapInt16LittleToHost(*(uint16_t *)(&reportData[2]));
bpm2 = CFSwapInt16LittleToHost(*(uint16_t *)(&reportData[4]));
if (bpm != 0 || bpm2 != 0) {
NSLog(#"%u", bpm);
if (bpm2 != 0) {
NSLog(#"%u", bpm2);
}
}
}
}
in #Brabbeldas solution i had to use a different flag to get rri values. but might depend on device used.
if ((reportData[0] & 0x10) == 0)
instead of
if ((reportData[0] & 0x04) == 0)
Parse heart rate parameters in "C"
I uploaded the sample application to GitHub Heart-Rate-Bluegiga
void ble_evt_attclient_attribute_value(const struct ble_msg_attclient_attribute_value_evt_t *msg)
{
if (msg->value.len < 2) {
printf("Not enough fields in Heart Rate Measurement value");
change_state(state_finish);
}
// Heart Rate Profile defined flags
const unsigned char HEART_RATE_VALUE_FORMAT = 0x01;
const unsigned char ENERGY_EXPENDED_STATUS = 0x08;
const unsigned char RR_INTERVAL = 0x10;
unsigned char current_offset = 0;
unsigned char flags = msg->value.data[current_offset];
int is_heart_rate_value_size_long = ((flags & HEART_RATE_VALUE_FORMAT) != 0);
int has_expended_energy = ((flags & ENERGY_EXPENDED_STATUS) != 0);
int has_rr_intervals = ((flags & RR_INTERVAL) != 0);
current_offset++;
uint16 heart_rate_measurement_value = 0;
if (is_heart_rate_value_size_long)
{
heart_rate_measurement_value = (uint16)((msg->value.data[current_offset + 1] << 8) +
msg->value.data[current_offset]);
current_offset += 2;
}
else
{
heart_rate_measurement_value = msg->value.data[current_offset];
current_offset++;
}
printf("Heart rate measurment value: %d ", heart_rate_measurement_value);
uint16 expended_energy_value = 0;
if (has_expended_energy)
{
expended_energy_value = (uint16)((msg->value.data[current_offset + 1] << 8) +
msg->value.data[current_offset]);
current_offset += 2;
printf(" Expended energy value: %d ", expended_energy_value);
}
uint16 rr_intervals[10] = {0};
if (has_rr_intervals)
{
printf(" Rr intervals: ");
int rr_intervals_count = (msg->value.len - current_offset) / 2;
for (int i = 0; i < rr_intervals_count; i++)
{
int raw_rr_interval = (uint16)((msg->value.data[current_offset + 1] << 8) +
msg->value.data[current_offset]);
rr_intervals[i] = ((double)raw_rr_interval / 1024) * 1000;
current_offset += 2;
printf("%d ", rr_intervals[i]);
}
printf("\n");
}
}
A project I am working on uses Apache Shiro as a security framework. Passwords are SHA1 hashed (no salt, no iterations). Login is SSL secured. However, the remaining part of the application is not SSL secured. In this context (no SSL) there should be a form where a user can change the password.
Since it wouldn't be a good idea to transmit it plainly it should be hashed on the client and then transmitted to the server. As the client is GWT (2.3) based, I am trying this library http://code.google.com/p/gwt-crypto, which uses code from bouncycastle.
However, in many cases (not all) the hashes generated by both frameworks differ in 1-4(?) characters.
For instance "happa3" is hashed to
"fe7f3cffd8a5f0512a5f1120f1369f48cd6f47c2"
by both implementations, whereas just "happa" is hashed to
"fb3c3a741b4e07a87d9cb68f3db020d6fbfed00a"
by the Shiro implementation and to
"fb3c3a741b4e07a87d9cb63f3db020d6fbfed00a"
by the gwt-crypto implementation (23rd character differs).
I wonder whether there is a "correct"/standard SHA1 hashing and whether there is a bug in one of the libraries or maybe my usage of them is flawed.
One of my first thoughts was related to different encodings or strange conversions due to different transport mechanisms (RPC vs. Post). To my knowledge though (and what puzzles me most), SHA1 hashes should differ completely with a high probability if there is just a difference of a single bit. So different encodings shouldn't be the issue here.
I am using this code on the client (GWT) for hashing:
String hashed = toHex(createSHA1Hash("password"));
...
private String createSHA1Hash(String passwordString){
SHA1Digest sha1 = new SHA1Digest();
byte[] bytes;
byte[] result = new byte[sha1.getDigestSize()];
try {
bytes = passwordString.getBytes();
sha1.update(bytes, 0, bytes.length);
int val = sha1.doFinal(result, 0);
} catch (UnsupportedEncodingException e) {}
return new String(result);
}
public String toHex(String arg) {
return new BigInteger(1, arg.getBytes()).toString(16);
}
And this on the server (Shiro):
String hashed = new Sha1Hash("password").toHex()
which afaics does something very similar behind the scenes (had a quick view on the source code).
Did I miss something obvious here?
EDIT: Seems like the GWT code does not run natively for some reason (i.e. just in development mode) and silently fails (it does compile, though). Have to find out why...
Edit(2): "int val = sha1.doFinal(result, 0);" is the line that makes trouble, i.e. if present, the whole code does not run natively (JS) but only in dev-mode (with wrong results)
You could test this version:
public class SHA1 {
public static native String calcSHA1(String s) /*-{
//
// A JavaScript implementation of the Secure Hash Algorithm, SHA-1, as defined
// in FIPS 180-1
// Version 2.2 Copyright Paul Johnston 2000 - 2009.
// Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
// Distributed under the BSD License
// See http://pajhome.org.uk/crypt/md5 for details.
//
//
// Configurable variables. You may need to tweak these to be compatible with
// the server-side, but the defaults work in most cases.
//
var hexcase = 0; // hex output format. 0 - lowercase; 1 - uppercase
var b64pad = ""; // base-64 pad character. "=" for strict RFC compliance
//
// These are the functions you'll usually want to call
// They take string arguments and return either hex or base-64 encoded strings
//
function b64_sha1(s) { return rstr2b64(rstr_sha1(str2rstr_utf8(s))); }
function any_sha1(s, e) { return rstr2any(rstr_sha1(str2rstr_utf8(s)), e); }
function hex_hmac_sha1(k, d)
{ return rstr2hex(rstr_hmac_sha1(str2rstr_utf8(k), str2rstr_utf8(d))); }
function b64_hmac_sha1(k, d)
{ return rstr2b64(rstr_hmac_sha1(str2rstr_utf8(k), str2rstr_utf8(d))); }
function any_hmac_sha1(k, d, e)
{ return rstr2any(rstr_hmac_sha1(str2rstr_utf8(k), str2rstr_utf8(d)), e); }
//
// Perform a simple self-test to see if the VM is working
//
function sha1_vm_test()
{
return hex_sha1("abc").toLowerCase() == "a9993e364706816aba3e25717850c26c9cd0d89d";
}
//
// Calculate the SHA1 of a raw string
//
function rstr_sha1(s)
{
return binb2rstr(binb_sha1(rstr2binb(s), s.length * 8));
}
//
// Calculate the HMAC-SHA1 of a key and some data (raw strings)
//
function rstr_hmac_sha1(key, data)
{
var bkey = rstr2binb(key);
if(bkey.length > 16) bkey = binb_sha1(bkey, key.length * 8);
var ipad = Array(16), opad = Array(16);
for(var i = 0; i < 16; i++)
{
ipad[i] = bkey[i] ^ 0x36363636;
opad[i] = bkey[i] ^ 0x5C5C5C5C;
}
var hash = binb_sha1(ipad.concat(rstr2binb(data)), 512 + data.length * 8);
return binb2rstr(binb_sha1(opad.concat(hash), 512 + 160));
}
//
// Convert a raw string to a hex string
//
function rstr2hex(input)
{
try { hexcase } catch(e) { hexcase=0; }
var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef";
var output = "";
var x;
for(var i = 0; i < input.length; i++)
{
x = input.charCodeAt(i);
output += hex_tab.charAt((x >>> 4) & 0x0F)
+ hex_tab.charAt( x & 0x0F);
}
return output;
}
//
// Convert a raw string to a base-64 string
//
function rstr2b64(input)
{
try { b64pad } catch(e) { b64pad=''; }
var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
var output = "";
var len = input.length;
for(var i = 0; i < len; i += 3)
{
var triplet = (input.charCodeAt(i) << 16)
| (i + 1 < len ? input.charCodeAt(i+1) << 8 : 0)
| (i + 2 < len ? input.charCodeAt(i+2) : 0);
for(var j = 0; j < 4; j++)
{
if(i * 8 + j * 6 > input.length * 8) output += b64pad;
else output += tab.charAt((triplet >>> 6*(3-j)) & 0x3F);
}
}
return output;
}
//
// Convert a raw string to an arbitrary string encoding
//
function rstr2any(input, encoding)
{
var divisor = encoding.length;
var remainders = Array();
var i, q, x, quotient;
// Convert to an array of 16-bit big-endian values, forming the dividend
var dividend = Array(Math.ceil(input.length / 2));
for(i = 0; i < dividend.length; i++)
{
dividend[i] = (input.charCodeAt(i * 2) << 8) | input.charCodeAt(i * 2 + 1);
}
//
// Repeatedly perform a long division. The binary array forms the dividend,
// the length of the encoding is the divisor. Once computed, the quotient
// forms the dividend for the next step. We stop when the dividend is zero.
// All remainders are stored for later use.
//
while(dividend.length > 0)
{
quotient = Array();
x = 0;
for(i = 0; i < dividend.length; i++)
{
x = (x << 16) + dividend[i];
q = Math.floor(x / divisor);
x -= q * divisor;
if(quotient.length > 0 || q > 0)
quotient[quotient.length] = q;
}
remainders[remainders.length] = x;
dividend = quotient;
}
// Convert the remainders to the output string
var output = "";
for(i = remainders.length - 1; i >= 0; i--)
output += encoding.charAt(remainders[i]);
// Append leading zero equivalents
var full_length = Math.ceil(input.length * 8 /
(Math.log(encoding.length) / Math.log(2)))
for(i = output.length; i < full_length; i++)
output = encoding[0] + output;
return output;
}
//
// Encode a string as utf-8.
// For efficiency, this assumes the input is valid utf-16.
//
function str2rstr_utf8(input)
{
var output = "";
var i = -1;
var x, y;
while(++i < input.length)
{
// Decode utf-16 surrogate pairs
x = input.charCodeAt(i);
y = i + 1 < input.length ? input.charCodeAt(i + 1) : 0;
if(0xD800 <= x && x <= 0xDBFF && 0xDC00 <= y && y <= 0xDFFF)
{
x = 0x10000 + ((x & 0x03FF) << 10) + (y & 0x03FF);
i++;
}
// Encode output as utf-8
if(x <= 0x7F)
output += String.fromCharCode(x);
else if(x <= 0x7FF)
output += String.fromCharCode(0xC0 | ((x >>> 6 ) & 0x1F),
0x80 | ( x & 0x3F));
else if(x <= 0xFFFF)
output += String.fromCharCode(0xE0 | ((x >>> 12) & 0x0F),
0x80 | ((x >>> 6 ) & 0x3F),
0x80 | ( x & 0x3F));
else if(x <= 0x1FFFFF)
output += String.fromCharCode(0xF0 | ((x >>> 18) & 0x07),
0x80 | ((x >>> 12) & 0x3F),
0x80 | ((x >>> 6 ) & 0x3F),
0x80 | ( x & 0x3F));
}
return output;
}
//
// Encode a string as utf-16
//
function str2rstr_utf16le(input)
{
var output = "";
for(var i = 0; i < input.length; i++)
output += String.fromCharCode( input.charCodeAt(i) & 0xFF,
(input.charCodeAt(i) >>> 8) & 0xFF);
return output;
}
function str2rstr_utf16be(input)
{
var output = "";
for(var i = 0; i < input.length; i++)
output += String.fromCharCode((input.charCodeAt(i) >>> 8) & 0xFF,
input.charCodeAt(i) & 0xFF);
return output;
}
//
// Convert a raw string to an array of big-endian words
// Characters >255 have their high-byte silently ignored.
//
function rstr2binb(input)
{
var output = Array(input.length >> 2);
for(var i = 0; i < output.length; i++)
output[i] = 0;
for(var i = 0; i < input.length * 8; i += 8)
output[i>>5] |= (input.charCodeAt(i / 8) & 0xFF) << (24 - i % 32);
return output;
}
//
// Convert an array of big-endian words to a string
//
function binb2rstr(input)
{
var output = "";
for(var i = 0; i < input.length * 32; i += 8)
output += String.fromCharCode((input[i>>5] >>> (24 - i % 32)) & 0xFF);
return output;
}
//
// Calculate the SHA-1 of an array of big-endian words, and a bit length
//
function binb_sha1(x, len)
{
// append padding
x[len >> 5] |= 0x80 << (24 - len % 32);
x[((len + 64 >> 9) << 4) + 15] = len;
var w = Array(80);
var a = 1732584193;
var b = -271733879;
var c = -1732584194;
var d = 271733878;
var e = -1009589776;
for(var i = 0; i < x.length; i += 16)
{
var olda = a;
var oldb = b;
var oldc = c;
var oldd = d;
var olde = e;
for(var j = 0; j < 80; j++)
{
if(j < 16) w[j] = x[i + j];
else w[j] = bit_rol(w[j-3] ^ w[j-8] ^ w[j-14] ^ w[j-16], 1);
var t = safe_add(safe_add(bit_rol(a, 5), sha1_ft(j, b, c, d)),
safe_add(safe_add(e, w[j]), sha1_kt(j)));
e = d;
d = c;
c = bit_rol(b, 30);
b = a;
a = t;
}
a = safe_add(a, olda);
b = safe_add(b, oldb);
c = safe_add(c, oldc);
d = safe_add(d, oldd);
e = safe_add(e, olde);
}
return Array(a, b, c, d, e);
}
//
// Perform the appropriate triplet combination function for the current
// iteration
//
function sha1_ft(t, b, c, d)
{
if(t < 20) return (b & c) | ((~b) & d);
if(t < 40) return b ^ c ^ d;
if(t < 60) return (b & c) | (b & d) | (c & d);
return b ^ c ^ d;
}
//
// Determine the appropriate additive constant for the current iteration
//
function sha1_kt(t)
{
return (t < 20) ? 1518500249 : (t < 40) ? 1859775393 :
(t < 60) ? -1894007588 : -899497514;
}
//
// Add integers, wrapping at 2^32. This uses 16-bit operations internally
// to work around bugs in some JS interpreters.
//
function safe_add(x, y)
{
var lsw = (x & 0xFFFF) + (y & 0xFFFF);
var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
return (msw << 16) | (lsw & 0xFFFF);
}
//
// Bitwise rotate a 32-bit number to the left.
//
function bit_rol(num, cnt)
{
return (num << cnt) | (num >>> (32 - cnt));
}
return rstr2hex(rstr_sha1(str2rstr_utf8(s)));
}-*/;
}
I'm using it in my client side sha generation and it worked well.
I'm familiar with WideCharToMultiByte and MultiByteToWideChar conversions and could use these to do something like:
UTF8 -> UTF16 -> 1252
I know that iconv will do what I need, but does anybody know of any MS libs that will allow this in a single call?
I should probably just pull in the iconv library, but am feeling lazy.
Thanks
Windows 1252 is mostly equivalent to latin-1, aka ISO-8859-1: Windows-1252 just has some additional characters allocated in the latin-1 reserved range 128-159. If you are ready to ignore those extra characters, and stick to latin-1, then conversion is rather easy. Try this:
#include <stddef.h>
/*
* Convert from UTF-8 to latin-1. Invalid encodings, and encodings of
* code points beyond 255, are replaced by question marks. No more than
* dst_max_len bytes are stored in the destination array. Returned value
* is the length that the latin-1 string would have had, assuming a big
* enough destination buffer.
*/
size_t
utf8_to_latin1(char *src, size_t src_len,
char *dst, size_t dst_max_len)
{
unsigned char *sb;
size_t u, v;
u = v = 0;
sb = (unsigned char *)src;
while (u < src_len) {
int c = sb[u ++];
if (c >= 0x80) {
if (c >= 0xC0 && c < 0xE0) {
if (u == src_len) {
c = '?';
} else {
int w = sb[u];
if (w >= 0x80 && w < 0xC0) {
u ++;
c = ((c & 0x1F) << 6)
+ (w & 0x3F);
} else {
c = '?';
}
}
} else {
int i;
for (i = 6; i >= 0; i --)
if (!(c & (1 << i)))
break;
c = '?';
u += i;
}
}
if (v < dst_max_len)
dst[v] = (char)c;
v ++;
}
return v;
}
/*
* Convert from latin-1 to UTF-8. No more than dst_max_len bytes are
* stored in the destination array. Returned value is the length that
* the UTF-8 string would have had, assuming a big enough destination
* buffer.
*/
size_t
latin1_to_utf8(char *src, size_t src_len,
char *dst, size_t dst_max_len)
{
unsigned char *sb;
size_t u, v;
u = v = 0;
sb = (unsigned char *)src;
while (u < src_len) {
int c = sb[u ++];
if (c < 0x80) {
if (v < dst_max_len)
dst[v] = (char)c;
v ++;
} else {
int h = 0xC0 + (c >> 6);
int l = 0x80 + (c & 0x3F);
if (v < dst_max_len) {
dst[v] = (char)h;
if ((v + 1) < dst_max_len)
dst[v + 1] = (char)l;
}
v += 2;
}
}
return v;
}
Note that I make no guarantee about this code. This is completely untested.
Say I have a large number (integer or float) like 12345 and I want it to look like 12,345.
How would I accomplish that?
I'm trying to do this for an iPhone app, so something in Objective-C or C would be nice.
Here is the answer.
NSNumber* number = [NSNumber numberWithDouble:10000000];
NSNumberFormatter *numberFormatter = [[NSNumberFormatter alloc] init];
[numberFormatter setNumberStyle:kCFNumberFormatterDecimalStyle];
[numberFormatter setGroupingSeparator:#","];
NSString* commaString = [numberFormatter stringForObjectValue:number];
[numberFormatter release];
NSLog(#"%# -> %#", number, commaString);
Try using an NSNumberFormatter.
This should allow you to handle this correctly on an iPhone. Make sure you use the 10.4+ style, though. From that page:
"iPhone OS: The v10.0 compatibility mode is not available on iPhone OS—only the 10.4 mode is available."
At least on Mac OS X, you can just use the "'" string formatter with printf(3).
$ man 3 printf
`'' Decimal conversions (d, u, or i) or the integral portion
of a floating point conversion (f or F) should be
grouped and separated by thousands using the non-mone-
tary separator returned by localeconv(3).
as in printf("%'6d",1000000);
Cleaner C code
// write integer value in ASCII into buf of size bufSize, inserting commas at tousands
// character string in buf is terminated by 0.
// return length of character string or bufSize+1 if buf is too small.
size_t int2str( char *buf, size_t bufSize, int val )
{
char *p;
size_t len, neg;
// handle easy case of value 0 first
if( val == 0 )
{
a[0] = '0';
a[1] = '\0';
return 1;
}
// extract sign of value and set val to absolute value
if( val < 0 )
{
val = -val;
neg = 1;
}
else
neg = 0;
// initialize encoding
p = buf + bufSize;
*--p = '\0';
len = 1;
// while the buffer is not yet full
while( len < bufSize )
{
// put front next digit
*--p = '0' + val % 10;
val /= 10;
++len;
// if the value has become 0 we are done
if( val == 0 )
break;
// increment length and if it's a multiple of 3 put front a comma
if( (len % 3) == 0 )
*--p = ',';
}
// if buffer is too small return bufSize +1
if( len == bufSize && (val > 0 || neg == 1) )
return bufSize + 1;
// add negative sign if required
if( neg == 1 )
{
*--p = '-';
++len;
}
// move string to front of buffer if required
if( p != buf )
while( *buf++ = *p++ );
// return encoded string length not including \0
return len-1;
}
I did this for an iPhone game recently. I was using the built-in LCD font, which is a monospaced font. I formatted the numbers, ignoring the commas, then stuck the commas in afterward. (The way calculators do it, where the comma is not considered a character.)
Check out the screenshots at RetroJuJu. Sorry--they aren't full-sized screenshots so you'll have to squint!
Hope that helps you (it's in C) :
char* intToFormat(int a)
{
int nb = 0;
int i = 1;
char* res;
res = (char*)malloc(12*sizeof(char));
// Should be enough to get you in the billions. Get it higher if you need
// to use bigger numbers.
while(a > 0)
{
if( nb > 3 && nb%3 == 0)
res[nb++] = ',';
// Get the code for the '0' char and add it the position of the
// number to add (ex: '0' + 5 = '5')
res[nb] = '0' + a%10;
nb++;
a /= 10;
}
reverse(&res);
return res;
}
There might be a few errors I didn't see (I'm blind when it comes to this...)
It's like an enhanced iToA so maybe it's not the best solution.
Use recursion, Luke:
#include <stdio.h>
#include <stdlib.h>
static int sprint64u( char* buffer, unsigned __int64 x) {
unsigned __int64 quot = x / 1000;
int chars_written;
if ( quot != 0) {
chars_written = sprint64u( buffer, quot);
chars_written += sprintf( buffer + chars_written, ".%03u", ( unsigned int)( x % 1000));
}
else {
chars_written = sprintf( buffer, "%u", ( unsigned int)( x % 1000));
}
return chars_written;
}
int main( void) {
char buffer[ 32];
sprint64u( buffer, 0x100000000ULL);
puts( buffer);
return EXIT_SUCCESS;
}