Objective C - NSNumber storing and retrieving longLongValue always prefixes with 0xFFFFFFFF - objective-c

I am trying to store a file size in bytes as an NSNumber. I am reading the file download size from the NSURLResponse and that gives me a long long value and I then create an NSNumber object from that value and store it. When I go to retrieve that value later, it comes back with all the higher bytes set as FFFFFFFF.
For example, I read in the size as 2196772870 bytes (0x82f01806) and then store it into the NSNumber. When I get it back, I get -2098194426 bytes (0xffffffff82f01806). I tried doing a binary AND with 0x00000000FFFFFFFF before storing the value in NSNumber but it still comes back as negative. Code below:
long long bytesTotal = response.expectedContentLength;
NSLog(#"bytesTotal = %llx",bytesTotal);
[downloadInfo setFileTotalSize:[NSNumber numberWithInt:bytesTotal]];
//[downloadInfo setFileTotalSize:[NSNumber numberWithLongLong:bytesTotal]];
long long fileTotalSize = [[downloadInfo fileTotalSize] longLongValue];
NSLog(#"fileTotalSize = %llx",fileTotalSize);
Output:
bytesTotal = 82f01806
fileTotalSize = ffffffff82f01806
Any suggestions?
Edit: Completely forgot the setter for the downloadInfo object.

The problem is this line:
[downloadInfo setFileTotalSize:[NSNumber numberWithInt:bytesTotal]];
bytesTotal is not an int, it's a long long, so you should be using numberWithLongLong:, not numberWithInt:. Change it to:
[downloadInfo setFileTotalSize:[NSNumber numberWithLongLong:bytesTotal]];
The conversion is causing it to be sign extended to 64 bits, and the number starting with 8 appears to be a negative number so that bit gets extended all the way thru the upper long, causing it to be ffffffff.

Related

getting size harddisk with fseek()

I have been trying to get the harddisk size on linux systems using fseek().
I have a function which should return the correct size:
unsigned long long getsize(FILE *fp){
unsigned long long prev=ftell(fp);
fseek(fp,0,SEEK_END);
unsigned long long size=ftell(fp);
fseek(fp,prev,SEEK_SET);
return size;
}
But when I use it on a harddisk it returns 18446744073709551615 or 2^64-1...
it doesn't seem to always return it. as I can use it on files fine. I also has worked before on harddisks.
You're getting this sort of results because that's not the right way to get the disk size.
If you want to check the size of disk you should issue an ioctl() on disk fd with a request of BLKGETSIZE64 (and argument of pointer to long long).
long long disk_size;
ioctl(<disk_fd>, BLKGETSIZE64, &disk_size);
If you're rather interested in filesystem size (which may be different) or empty space on a filesystem then use statvfs() call.

Dividing variables of type long long to get a percentage?

So I am trying to divide two variables that are type long long, totalBytesWritten and totalBytesExpected
Basically I am trying to figure out the percentage complete my file upload is and update the progressbar accordingly.
For example, I am sending 262144 of 1839948 bytes
But when I do double progress = totalBytesWritten/totalBytesExpected it gives me some unexpected numbers. When I NSLog progress I get only 0s and then finally 1.
Thanks!
You're performing an integer division, then the result is getting casted to a double but it's too late: you already lost precision.If you just cast one of the two operands to a double, the other one will be also promoted to a double and you'll get a floating point value as result:
NSLog(#"%f,"(double)totalBytesWritten/totalBytesExpected);
long long is a non-decimal data type, so it uses integer division. Thus, since totalBytesWritten is probably (hopefully) less than totalBytesExpected, you'll always get 0. Try converting them to double first, then divide.

How do I limit BitConverter.GetBytes() to return only a certain amount of bytes using VB.NET?

I do:
Dim BytArr() as Byte = BitConverter.GetBytes(1234)
Since, by default, they are 32 bits, it returns 4 byte elements.
I want to be able to control it to return only like two bytes. Maybe only three bytes. Are there any built-in functions to control it?
I don't want to rely on using shifting >> 8 >> 16 >> 24 >> 32, etc..
I also don't want to rely on type casting the data in GetBytes() to a specific datatype.
It is not that GetBytes defaults to 32 bits, it is that GetBytes returns an array of the size required to hold the data type. If you pass a Long then you will get a 8 elements in your array.
The best way to control this is indeed casting the data you pass in. Otherwise you could truncate some of the number.
That being said, you could do something like this:
Dim BytArr() as Byte = Array.Resize(BitConverter.GetBytes(1234), 2)
But if the value you passed in exceeded what could be stored in 2 bytes (in this case) then you will have some very broken code.

Using Doubles in Unix?

I am calling sysctl() to retrieve mem stats and for the void* oldVal argument, I am passing in a pointer to a double. However instead of setting the double to the correct value, it just sets it to 0.00000
However, when I try doing the exact same thing with a long, it sets it to the correct stat. Why is the double being set to 0.00000 while long is being set to the correct stat?
int systemInfoNeeded[2] = {CTL_HW, HW_PHYSMEM};
size_t sizeOfBuffer = sizeof(totalAmount);
if (sysctl(systemInfoNeeded, 2, &totalAmount, &sizeOfBuffer, NULL, 0))
{
NSLog(#"Total memory stat retrieval failed.\n");
exit (EXIT_FAILURE);
}
totalAmount is a double. The second I change the type of totalAmount to long, it works perfectly. Is there anyway I can get the double to work? I want to directly send in totalAmount rather than sending a long and then assigning the value to totalAmount.
I am using Objective-C/C, on Mac OS X Snowleopard with Xcode 3.2.6
You can't just choose your favorite data type and pass a pointer to it; the sysctl call expects a pointer to an integer, and so that's what you have to provide. If you pass a pointer to a double, then you get a double with bits that represent a value as a integer -- the result is gibberish.
sysctl() accepts a pointer to the type specified, in the manpage, for the property you are querying. The parameter is declared as a void* so that the same generic interface can work with the different types expected by the various properties. That does not mean that you can use any type you want. In the case of HW_PHYSMEM, it is an integer, i.e. an int, not a long or anything else.
The only reason it works if you pass a long is because macs are little endian, thus the first four bytes of a value as a long are the same as the value as an int, but you should of course not depend on this.
If you want to read a double, convert the integer.
You should take a good look at sysctl(3). Look in particular at the example with KERN_MAXPROC.

Converting a number larger than 255 into a byte variable

I understand the concept of bytes and declaring variables to save on processing space. I understand that the max value that can be stored in a byte is 255.
I cannot seem to wrap my head around my current issue and was hoping that someone would be able to educate me and help me solve this problem. I don't have much experience working with byte manipulation.
I was given a project to update and was told that the service that is passing data to my project would start using 2bytes to transfer the ID rather than the 1 byte previously as their parameters have grown.
The current declaration for the variable is:
Dim bytvariable As Byte = 0
What is the new declaration to accept a 2 byte value?
Secondly, how would I be able to convert that 2 byte value into an integer number?
Example, they are passing me this value: 0x138 and it is supposed to come out as 312.
Thank you in advance.
Here's a summary of the "primitive" datatypes in .NET, and their sizes.
Yes, an Int16 is probably what you want.
Often you'd be reading the binary data from a stream, or getting it from an array of bytes.
To convert from those sources into an Int16, you can do this:
in C#:
byte[] block = new byte[128];
mystream.Read(block, 0, block.Length);
int i = 0;
Int16 value = (Int16)(block[i++] + block[i++] * 256);
In VB.NET, it would be:
Dim block as New Byte(128)
stream.Read(block, 0, block.Length)
Dim i as Int16 = 0
Dim value As Short = CShort((block(i) + (buffer(i+1) * &H100)))
i = i + 2
(I think)
from the top of my head I'd suggest if you insist on doing it that way (instead of just passing an integer), you could use an array of byte, first index holding the first number and the second index the second ex. byte[0] = 123, byte[1] = 255;
then combine them into a string ex. string concatenatedNumber = byte[0].ToString() + byte[1].ToString(); then parse it ex. int ID = Int32.Parse(concatenatedNumber);
Examples are in C#, but I think you should get the idea. I would definitely rather just pass it as an integer though.
You could try this:
Dim bytvariable As Byte(0 To 1)
bytvariable(0) = ' Get the first byte however they are sending it
bytvariable(1) = ' Get the second byte however they are sending it
Dim value As Int16 = BitConverter.ToInt16(buffer, 0);