Question

I am new programmer in Obj-C and cocoa. Im a trying to write a framework which will be used to read a binary files (Flexible Image Transport System or FITS binary files, usually used by astronomers). The binary data, that I am interested to extract, can have various formats and I get its properties by reading the header of the FITS file.

Up to now, I manage to create a class to store the content of the FITS file and to isolate the header into a NSString object and the binary data into a NSData object. I also manage to write method which allow me to extract the key values from the header that are very valuable to interpret the binary data.

I am now trying to convert the NSData object into a primitive array (array of double, int, short ...). But, here, I get stuck and would appreciate any help.

According to the documentation I have about the FITS file, I have 5 possibilities to interpret the binary data depending on the value of the BITPIX key:

BITPIX value | Data represented
  8          | Char or unsigned binary int
 16          | 16-bit two's complement binary integer
 32          | 32-bit two's complement binary integer
 64          | 64-bit two's complement binary integer
-32          | IEEE single precision floating-point
-64          | IEEE double precision floating-point

I already write the peace of code, shown bellow, to try to convert the NSData into a primitive array.

// self reefer to my FITS class which contain a NSString object  
// with the content of the header and a NSData object with the binary data. 

-(void*) GetArray
{
switch (BITPIX)
{
    case 8:
        return [self GetArrayOfUInt];
        break;
    case 16:
        return [self GetArrayOfInt];
        break;
    case 32:
        return [self GetArrayOfLongInt];
        break;
    case 64:
        return [self GetArrayOfLongLong];
        break;
    case -32:
        return [self GetArrayOfFloat];
        break;
    case -64:
        return [self GetArrayOfDouble];
        break;
    default:
        return NULL;
}
}

// then I show you the method to convert the NSData into a primitive array.
// I restrict my example to the case of 'double'. Code is similar for other methods
// just change double by 'unsigned int' (BITPIX 8), 'short' (BITPIX 16)
// 'int' (BITPIX 32) 'long lon' (BITPIX 64), 'float' (BITPIX -32). 

-(double*) GetArrayOfDouble
{
int Nelements=[self NPIXEL]; // Metod to extract, from the header 
                             // the number of element into the array
NSLog(@"TOTAL NUMBER OF ELEMENTS [%i]\n",Nelements);

//CREATE THE ARRAY
double (*array)[Nelements];

// Get the total number of bits in the binary data
int Nbit = abs(BITPIX)*GCOUNT*(PCOUNT + Nelements); // GCOUNT and PCOUNT are defined
                                                        // into the header
NSLog(@"TOTAL NUMBER OF BIT [%i]\n",Nbit);
int i=0;

    //FILL THE ARRAY
double Value;

for(int bit=0; bit < Nbit; bit+=sizeof(double))
{
    [Img getBytes:&Value range:NSMakeRange(bit,sizeof(double))];
    NSLog(@"[%i]:(%u)%.8G\n",i,bit,Value);
        (*array)[i]=Value;
    i++;

}

return (*array);

}

However, the value I print in the loop are very different from the expected values (compared using official FITS software). Therefore, I think that the Obj-C double does not use the IEEE-754 convention as well as the Obj-C int are not twos-complement. I am really not familiar with this two convention (IEEE and twos-complement) and would like to know how I can do this conversion with Obj-C.

In advance many thanks for any help or information.

Was it helpful?

Solution 4

Thanks a lot. The problem was really related to the endian and I was not aware of this. Honestly, I was never really aware of the endian type because, up to now, I was never confronted to the problem.

By the way, I find the solution, thanks all for your remarks. Because it can be useful for other developer, I will propose a peace of code which allow to convert NSData to primitive, what ever the endian type. This is the solution I find (work with the Foundation and cocoa framework on Os X 10.5 and 10.6) and it may not be the best, so, use at your own risk ;)

// 1- CREATE AN ARRAY OF SIZE Nelements;
int Nelements = XXX;
double (*array)[Nelements];

// 2- Create the swapped double -> a double with the wrong bit order
NSSwappedDouble swappedValue;

// 3- The correct value
double Value;

// 4- Fill your array
int i=0, bit=0;
int BitStep=sizeof(double);

while(i<Nelements)
{
    [MyNSData getBytes:&swappedValue range:NSMakeRange(bit,step)];
    Value = NSSwapBigDoubleToHost(swappedValue);   // or NSSwapLittleDoubleToHost depending of your endian type.
    (*array)[i]=Value;
    i++; bit+=BitStep;

}

Hope this can be useful.

OTHER TIPS

Objective-C uses IEEE-754 floats (like practically every system does) as well as two's-complement integers. I think your conjecture is false. Maybe you are having endianness problems?

Virtually all systems use two's complement and IEEE 754, simply because it is rarely worth it to come up with a brand new representation of these things - you just don't do that unless you have very specialized circumstances that require it.

I would suggest you display the number in hexadecimal - it is much more likely to be an issue with endianness than the data types being of a special format, and printing the values in hexadecimal makes it easier to tell if that is the problem.

Are you sure that

double (*array)[NElements];

is what you want? This simple program:

int main( int argc, char** argv)
{
    double (*array)[5];
    (*array)[4] = 0;
    return 0;
}

Crashes miserably on my machine.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top