Left bit rotation of a string Objective C - c++

I've been given the following C++ function to do a left bit rotation of a string, I need to implement it in Objective C(Obviously I've added the logging bit at the bottom):
void left_rotate ( uint16_t *in,
uint16_t *out,
int16_t len,
int16_t shift )
{
int16_t i, j;
j = (len / 2) - 1;
for (i = 0; i < (len / 2); i++) {
out[i] = (uint16_t) (in[i] << shift);
if (i < j) {
out[i] |= in[i + 1] >> ((int16_t) len - shift);
} else {
out[i] |= in[0] >> ((int16_t) len - shift);
}
}
NSLog(#"In: %hd", (short)in);
NSLog(#"Out: %hd", (short)out);
unsigned char * char1 = out;
NSLog(#"Char: %s", char1);
NSData * data1 = [[NSData alloc] initWithBytes:char1 length:sizeof(char1)];
NSLog(#"Data: %#", data1);
}
However I'm not entirely sure how it's supposed to work. I've tried to call it as follows:
NSString * originStringData = #"acf7183f7673200BBA7719775b20393c4487fa008e13542f4013eb9b2eb7490e";
NSString * RotateNumber = #"0003";
NSData *data = originStringData;
NSUInteger len = [data length];
Byte *byteData = (Byte*)malloc(len);
memcpy(byteData, [data bytes], len);
for(int i=0; i<sizeof(byteData); i++)
{
u_int16_t data2 = byteData[i];
int16_t shift1 = (short)[RotateNumber intValue];
u_int16_t out1;
left_rotate(&data2, &out1, sizeof(byteData),shift1);
}
However it returns:
<60055600><b8077b00><c1001c00><f9011f00>
Where as the string I actually want is:
67b8c1fbb399005dd3b8cbbad901c9e2243fd004709aa17a009f5cd975ba4875
What I need to do is perform a left bit rotation on the origin string by the Rotate Number. I'm willing to give anything a go right now so any help would be appreciated, I'm a bit stuck!
Cheers!
Adam

It seems left_rotate doesn't work as you desire.
You can write you own rotate function like this(it works as what you want):
#import <Foundation/Foundation.h>
char char_to_hex(char ch)
{
char* table = "0123456789abcdef";
char* str = strchr(table, tolower(ch));
if(str == NULL)
return -1;
return str - table;
}
NSString* left_rotate(NSString* source, NSUInteger shift)
{
if(shift >= [source length] * 4)
{
shift %= ([source length] * 4);
}
NSInteger index = shift / 4;
NSString* tmp = [source substringFromIndex:index];
NSString* left = [source substringToIndex:index+1];
tmp = [tmp stringByAppendingString:left];
shift %= 4;
//get the internal pointer;
const char* data = [tmp cStringUsingEncoding:NSASCIIStringEncoding];
NSString* result = [[NSString alloc] init];
for(NSInteger i = 0; i < strlen(data) - 1; i++)
{
char ch1 = char_to_hex(data[i]);
char ch2 = char_to_hex(data[i+1]);
if(ch1 < 0 || ch2 < 0)
return nil;
char ch = ((ch1 << shift) | (ch2 >> (4 - shift))) & 0xF;
result = [result stringByAppendingFormat:#"%x", ch];
}
return result;
}
int main(int argc, const char * argv[]) {
NSString* source = #"acf7183f7673200BBA7719775b20393c4487fa008e13542f4013eb9b2eb7490e";
NSString* result = left_rotate(source, 3);
NSLog(#"result:%#", result);
return 0;
}

I believe you pass the wrong types to your function, you want to convert your NSString* to an array of int16 before you pass it, what you're doing however, is simply copying the bytes representing the string.
Simply put, if you copy the byes representing "1", you won't get the equivalent of 1, you have to add some conversion.
Something along these lines (no error handling, assuming a lot of things from your input, adapt!)
for (NSUInteger i = 0; i < originStringData.length; ++i {
unichar oneChar = [originStringData characterAtIndex:i];
if (isnumber(oneChar)) {
byteData[i] = oneChar - '0';
} else {
byteData[i] = oneChar - 'a' + 10;
}
}
On top of that you want to allocate some space for your out too, you're passing a pointer to a single int16, allocate another array of the same size and pass that.

Related

Facing issues trying to decode base64 image

I have a JPEG image, which is represented as a base64 encoded string. I want to save it as a decoded byte array using the Win32 API WriteFile() function.
Because I will use WriteFile(), I need a C string, and I need to know its length, strlen() is bad, because, as I understand, it counts to \0 which could not be the exact end of file. So, I need a function that decodes base64 and returns a char* and outputs the exact byte count.
I have read this answer, and chose code from here (some stuff changed, I marked it):
static const unsigned char base64_table[65] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
unsigned char * base64_decode(const unsigned char *src, size_t len,
size_t *out_len)
{
unsigned char dtable[256], *out, *pos, block[4], tmp;
size_t i, count, olen;
int pad = 0;
memset(dtable, 0x80, 256); // CHANGED
for (i = 0; i < sizeof(base64_table) - 1; i++)
dtable[base64_table[i]] = (unsigned char) i;
dtable['='] = 0;
count = 0;
for (i = 0; i < len; i++) {
if (dtable[src[i]] != 0x80)
count++;
}
if (count == 0 || count % 4)
return NULL;
olen = count / 4 * 3;
pos = out = new unsigned char[olen]; // CHANGED
if (out == NULL)
return NULL;
count = 0;
for (i = 0; i < len; i++) {
tmp = dtable[src[i]];
if (tmp == 0x80)
continue;
if (src[i] == '=')
pad++;
block[count] = tmp;
count++;
if (count == 4) {
*pos++ = (block[0] << 2) | (block[1] >> 4);
*pos++ = (block[1] << 4) | (block[2] >> 2);
*pos++ = (block[2] << 6) | block[3];
count = 0;
if (pad) {
if (pad == 1)
pos--;
else if (pad == 2)
pos -= 2;
else {
/* Invalid padding */
free(out); // CHANGED
return NULL;
}
break;
}
}
}
*out_len = pos - out;
return out;
}
Usage
unsigned char base[]="data:image/jpeg;base64,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";
unsigned char *g = base64_decode(base, 2568, &re); // length is appearing when you hover mouse on char[] in Visual Studio
// after call re equals 1921
HANDLE f2 = CreateFile(L"img.jpeg", GENERIC_WRITE, 0, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
DWORD wr2;
WriteFile(f2, g, re, &wr2, 0);
CloseHandle(f2);
The file I am getting is not viewable, the Photos app says it is corrupted. The main problem - it weights 1.87 kb, but should be 2.31 (I download this image from a browser).
What am I doing wrong?
As #IngoLeonhardt pointed out, I should not pass the data:image/jpeg;base64, part to the function. Now it works.

Convert LPCTSTR HEXADECIMAL to BYTE in VS C++

I have below function that supports for conversion of LPCTSTR to BYTE , but the input str only support digits as of now.
void StrToByte2(LPCTSTR str, BYTE *dest)
{
UINT count = _ttoi(str);
BYTE buf[4] = { 0 };
char string[10] = { 0 };
sprintf_s(string, 10, "%04d", count);
for (int i = 0; i < 4; ++i)
{
if ((string[i] >= '0') && (string[i] <= '9'))
buf[i] = string[i] - '0';
}
dest[0] = (BYTE)(buf[0] << 4) | buf[1];
dest[1] = (BYTE)(buf[2] << 4) | buf[3];
}
If i call this function on "1234" ( any digits) , dest output some 12814,
struct st
{
byte btID[2];
int nID;
};
PTR ptr(new st);
StrToByte2(strCode, ptr->btID);
but when i call this function on any hexadecimal ex A123 , it outputs 0000 always.
Below function is used to convert back the dest code to str
CString Byte2ToStr(const byte* pbuf)
{
CString str;
str.Format(_T("%02X%02X"), pbuf[0], pbuf[1]);
return str;
}
How can i get A123 to converted to bytes and than back to str to display A123??
Please help!!
PTR ptr(new st);
This is a memory leak in C++, because new st allocates memory and there is no way to release it.
UINT count = _ttoi(str);
...
sprintf_s(string, 10, "%04d", count);
This is converting string to integer, then converts integer back to string. It doesn't seem to have a real purpose.
For example, "1234" is converted to 1234, and back to "1234". But "A123" is not a valid number so it is converted to 0, then converted to "0000". So this method fails. You can just work with the original string.
It seems this function tries to fit 2 integers in to 1 byte. This can be done as long as each value is less than 16 or 0xF (I don't know what purpose this might have) It can be fixed as follows:
void StrToByte2(const wchar_t* str, BYTE *dest)
{
int len = wcslen(str);
if(len != 4)
return; //handle error
char buf[4] = { 0 };
for(int i = 0; i < 4; ++i)
if(str[i] >= L'0' && str[i] <= L'9')
buf[i] = (BYTE)(str[i] - L'0');
dest[0] = (buf[0] << 4) + buf[1];
dest[1] = (buf[2] << 4) + buf[3];
}
CStringW Byte2_To_Str(BYTE *dest)
{
CStringW str;
str.AppendFormat(L"%X", 0xF & (dest[0] >> 4));
str.AppendFormat(L"%X", 0xF & (dest[0]));
str.AppendFormat(L"%X", 0xF & (dest[1] >> 4));
str.AppendFormat(L"%X", 0xF & (dest[1]));
return str;
}
int main()
{
BYTE dest[2] = { 0 };
StrToByte2(L"1234", dest);
OutputDebugStringW(Byte2_To_Str(dest));
OutputDebugStringW(L"\n");
return 0;
}
If the string is hexadecimal, you can use sscanf to convert each pair of character to bytes.
Basically, "1234" changes to 12 34
"A123" changes to A1 23
bool hexstring_to_bytes(const wchar_t* str, BYTE *dest, int dest_size = 2)
{
int len = wcslen(str);
if((len / 2) > dest_size)
{
//error
return false;
}
for(int i = 0; i < len / 2; i++)
{
int v;
if(swscanf_s(str + i * 2, L"%2x", &v) != 1)
break;
dest[i] = (unsigned char)v;
}
return true;
}
CStringW bytes_to_hexstring(const BYTE* bytes, int byte_size = 2)
{
CString str;
for(int i = 0; i < byte_size; i++)
str.AppendFormat(L"%02X ", bytes[i] & 0xFF);
return str;
}
int main()
{
CStringW str;
CStringW new_string;
BYTE dest[2] = { 0 };
str = L"1234";
hexstring_to_bytes(str, dest);
new_string = bytes_to_hexstring(dest);
OutputDebugString(new_string);
OutputDebugString(L"\n");
str = L"A123";
hexstring_to_bytes(str, dest);
new_string = bytes_to_hexstring(dest);
OutputDebugStringW(new_string);
OutputDebugStringW(L"\n");
return 0;
}

Fill struct in6_addr with unsigned char array

I'am doing DNS lookup tool in C++ and i am trying to get IPv6 from
unsigned char * (where it is stored in non readable format), copy it to struct in6_addr, then i want to convert it and print it.
struct in6_addr tmp2;
char buf[41];
memcpy(tmp2.s6_addr, answ[i].rdata, 128);
cout << answ[i].name << " IN AAAA " << inet_ntop(AF_INET6, tmp2.s6_addr, buf, 128) << endl;
My output should look like this,
www.domain.name.cz. IN AAAA 2001:67c:1220:809::93e5:917
but somehow it looks like this.
www.domain.name.cz IN AAAA 106:7c12:2008:900::
Generating RDATA
u_char *ReadName(unsigned char *readResponse, unsigned char *buffer, int *count) {
unsigned char *name;
unsigned int p = 0, jumped = 0, offset;
int i, j;
*count = 1;
name = (unsigned char *) malloc(256);
name[0] = '\0';
//read the names in 3www6google3com format
while (*readResponse != 0) {
if (*readResponse >= 192) {
offset = (*readResponse) * 256 + *(readResponse + 1) - 49152; //49152 = 11000000 00000000 ;)
readResponse = buffer + offset - 1;
jumped = 1; //we have jumped to another location so counting wont go up!
} else {
name[p++] = *readResponse;
}
readResponse = readResponse + 1;
if (jumped == 0) {
*count = *count + 1; //if we havent jumped to another location then we can count up
}
}
name[p] = '\0'; //string complete
if (jumped == 1) {
*count = *count + 1; //number of steps we actually moved forward in the packet
}
//now convert 3www6google3com0 to www.google.com
for (i = 0; i < (int) strlen((const char *) name); i++) {
p = name[i];
for (j = 0; j < (int) p; j++) {
name[i] = name[i + 1];
i = i + 1;
}
name[i] = '.';
}
name[i - 1] = '\0'; //remove the last dot
return name;
Thanks for your help!

C++: Convert Win32 textbox char -> int -> char and put back in another textbox

I want to accept text input using a text box, then change the characters to integers and do fun math with my integers, and then put them back into a char array to be printed in another text box.
Here is my code:
int len = GetWindowTextLength(textbox) + 1;
char* text = new char[len];
GetWindowText(textbox, &text[0], len);
int x = 0;
int INTmessage[len];
int ENClen = (len * 2);
char ENCmessage[ENClen];
while (x < len) {
INTmessage[x] = int(text[x]) - 32;
x++;
}
int z = 0;
int y = 0;
while (z < ENClen) {
ENCmessage[z] = (INTmessage[y] % 9);
ENCmessage[z + 1] = (INTmessage[y] % 10);
z += 2;
y++;
}
SetWindowText(textreturn, "");
SetWindowText(textreturn, ENCmessage[0]);
The last line displays a compiler error:
invalid conversion from 'char' to LPCSTR.
Please specify What you mean by 'I don't know why this does not work'. One Error in your code is this:
//This line is incorrect because it converts an address to integer, which has no relation to value of textbox, making decryption impossible.
INTmessage[x] = int(&text[x]) - 32;
//Maybe you may want to use this code:
INTmessage[x] = int(text[x]) - 32;
The last line fails because you are passing a single char to SetWindowText() (accessing ENCmessage[0] returns the first char in the ENCmessage array). SetWindowText() expects a char* pointer to a null-terminated string instead. You can drop the [0]:
SetWindowText(textreturn, ENCmessage);
Just make sure that ENCmessage contains a null character after your digit characters.
That being said, your code can be re-written to something more like this:
int len = GetWindowTextLength(textbox) + 1;
char* text = new char[len];
len = GetWindowText(textbox, text, len);
int *INTmessage = new int[len];
for(int x = 0; x < len; ++x) {
INTmessage[x] = int(text[x]) - 32;
}
int ENClen = (len * 2) + 1;
char *ENCmessage = new char[ENClen];
for(int x = 0, y = 0; x < len; ++x, y += 2) {
ENCmessage[y] = (INTmessage[x] % 9);
ENCmessage[y + 1] = (INTmessage[x] % 10);
}
ENCmessage[ENCLen-1] = '\0';
SetWindowText(textreturn, ENCmessage);
delete[] INTmessage;
delete[] ENCmessage;
delete[] text;
Or, since you tagged the question as C++, like this instead:
#include <string>
#include <vector>
int len = GetWindowTextLength(textbox) + 1;
std::string text;
text.resize(len);
len = GetWindowText(textbox, &text[0], len);
std::vector<int> INTmessage(len);
for(int x = 0; x < len; ++x) {
INTmessage[x] = int(text[x]) - 32;
}
int ENClen = (len * 2);
std::string ENCmessage;
ENCmessage.resize(ENClen);
for (int x = 0; y = 0; x < len; ++x, y += 2) {
ENCmessage[y] = (INTmessage[x] % 9);
ENCmessage[y + 1] = (INTmessage[x] % 10);
}
SetWindowText(textreturn, ENCmessage.c_str());

Why can't I assign a scalar value to a class using shorthand, but instead declare it first, then set its value?

I am writing a UTF-8 library for C++ as an exercise as this is my first real-world C++ code. So far, I've implemented concatenation, character indexing, parsing and encoding UTF-8 in a class called "ustring". It looks like it's working, but two seemingly equivalent ways of declaring a new ustring behave differently. The first way:
ustring a;
a = "test";
works, and the overloaded "=" operator parses the string into the class (which stores the Unicode strings as an dynamically allocated int pointer). However, the following does not work:
ustring a = "test";
because I get the following error:
test.cpp:4: error: conversion from ‘const char [5]’ to non-scalar type ‘ustring’ requested
Is there a way to workaround this error? It probably is a problem with my code, though. The following is what I've written so far for the library:
#include <cstdlib>
#include <cstring>
class ustring {
int * values;
long len;
public:
long length() {
return len;
}
ustring * operator=(ustring input) {
len = input.len;
values = (int *) malloc(sizeof(int) * len);
for (long i = 0; i < len; i++)
values[i] = input.values[i];
return this;
}
ustring * operator=(char input[]) {
len = sizeof(input);
values = (int *) malloc(0);
long s = 0; // s = number of parsed chars
int a, b, c, d, contNeed = 0, cont = 0;
for (long i = 0; i < sizeof(input); i++)
if (input[i] < 0x80) { // ASCII, direct copy (00-7f)
values = (int *) realloc(values, sizeof(int) * ++s);
values[s - 1] = input[i];
} else if (input[i] < 0xc0) { // this is a continuation (80-bf)
if (cont == contNeed) { // no need for continuation, use U+fffd
values = (int *) realloc(values, sizeof(int) * ++s);
values[s - 1] = 0xfffd;
}
cont = cont + 1;
values[s - 1] = values[s - 1] | ((input[i] & 0x3f) << ((contNeed - cont) * 6));
if (cont == contNeed) cont = contNeed = 0;
} else if (input[i] < 0xc2) { // invalid byte, use U+fffd (c0-c1)
values = (int *) realloc(values, sizeof(int) * ++s);
values[s - 1] = 0xfffd;
} else if (input[i] < 0xe0) { // start of 2-byte sequence (c2-df)
contNeed = 1;
values = (int *) realloc(values, sizeof(int) * ++s);
values[s - 1] = (input[i] & 0x1f) << 6;
} else if (input[i] < 0xf0) { // start of 3-byte sequence (e0-ef)
contNeed = 2;
values = (int *) realloc(values, sizeof(int) * ++s);
values[s - 1] = (input[i] & 0x0f) << 12;
} else if (input[i] < 0xf5) { // start of 4-byte sequence (f0-f4)
contNeed = 3;
values = (int *) realloc(values, sizeof(int) * ++s);
values[s - 1] = (input[i] & 0x07) << 18;
} else { // restricted or invalid (f5-ff)
values = (int *) realloc(values, sizeof(int) * ++s);
values[s - 1] = 0xfffd;
}
return this;
}
ustring operator+(ustring input) {
ustring result;
result.len = len + input.len;
result.values = (int *) malloc(sizeof(int) * result.len);
for (long i = 0; i < len; i++)
result.values[i] = values[i];
for (long i = 0; i < input.len; i++)
result.values[i + len] = input.values[i];
return result;
}
ustring operator[](long index) {
ustring result;
result.len = 1;
result.values = (int *) malloc(sizeof(int));
result.values[0] = values[index];
return result;
}
char * encode() {
char * r = (char *) malloc(0);
long s = 0;
for (long i = 0; i < len; i++) {
if (values[i] < 0x80)
r = (char *) realloc(r, s + 1),
r[s + 0] = char(values[i]),
s += 1;
else if (values[i] < 0x800)
r = (char *) realloc(r, s + 2),
r[s + 0] = char(values[i] >> 6 | 0x60),
r[s + 1] = char(values[i] & 0x3f | 0x80),
s += 2;
else if (values[i] < 0x10000)
r = (char *) realloc(r, s + 3),
r[s + 0] = char(values[i] >> 12 | 0xe0),
r[s + 1] = char(values[i] >> 6 & 0x3f | 0x80),
r[s + 2] = char(values[i] & 0x3f | 0x80),
s += 3;
else
r = (char *) realloc(r, s + 4),
r[s + 0] = char(values[i] >> 18 | 0xf0),
r[s + 1] = char(values[i] >> 12 & 0x3f | 0x80),
r[s + 2] = char(values[i] >> 6 & 0x3f | 0x80),
r[s + 3] = char(values[i] & 0x3f | 0x80),
s += 4;
}
return r;
}
};
Your problem is that ustring a = "test" actually invokes the constructor, not the assignment operator. yay, welcome to c++ :)
You'll need to define yourself both a default constructor and one that takes a const char*, because once you define a constructor, you need to define all your constructors.
A few other things:
pass your input ustring by reference
pass const char * instead of char[] (you don't modify the input and char* is more common)
sizeof isn't doing what you think it's doing, it doesn't work properly for array parameters. It is returning you sizeof(char*), not sizeof(array).
return reference to this from your operators.
you can use vector<int> values; to manage all your memory for you.
encode() should probably return a string. With string:
it manages its own memory, so the caller doesn't need to free or delete it.
you can use s.append(c); instead of using realloc.
you can use printf("%s", s.c_str());, but in c++ you usually use cout << s;
consider defining a copy constructor as well.
Like this:
class ustring {
public:
// Default constructor, allows you to create your class with no arguments.
ustring() { ...; }
// Allows you to create your class from string literals.
ustring(const char *input) { ...; }
// Copy constructor, allows you to create your class from other instances.
ustring(const ustring &input) { ...; }
// Assignment operators.
ustring &operator=(const ustring &input) { ...; return *this; }
ustring &operator=(const char *input) { ...; return *this; }
};
int main() {
ustring s, t; // invokes default constructor.
s = t; // invokes ustring assignment op.
s = "test"; // invokes const char* assignment op.
ustring u = "test"; // invokes const char* constructor.
ustring v("test"); // invokes const char* constructor.
ustring x(u); // invokes copy constructor.
}
If this is c++, why are you doing all this malloc/realloc stuff? I haven't fully parsed that code, but I'd imagine there's a simpler way... see the comment about using vector.
As #Michael Aaron Safyan mentioned in the comments, if you do any memory allocation for the ustring class, you will want to deallocate it in the destructor. However, I think by switching to memory managed containers - vector & string - you'll avoid any of your own memory management and can avoid writing a destructor.
These are two operations:
ustring a; // construct a new object using constructor
a = "test"; // assign value to object using operator=
This is one operation:
ustring a = "test"; // construct with a value, aka value-intialization
In the interest of runtime efficiency and allowing semantic freedom, C++ does not extrapolate the default constructor ustring::ustring() and the assignment operator ustring::operator=(const char*) into a constructor ustring::ustring(const char *).
But, for most reasonable string classes, this will work:
ustring::ustring(const char *str)
: /* initialize ustring::ustring() does */ {
/* do whatever ustring::ustring() does */
*this = str; // assign value.
}
It is better to call the assignment operator from the constructor than to attempt it the other way around.
Of course, you can probably improve efficiency by considering the length of the given string while performing initialization.