1

I'm actually a java developer, but for a lesiure project I'm trying to convert a lib from c++ to c#. I have a small background in ansi C but this code is confusing me

    long hfzWriteHeader(hfzFile* fs, hfzHeader& fh) {

        // copy header into buffer
        char HeaderBuf[28];
        long HeaderBufPos = 0;
        sprintf(HeaderBuf+HeaderBufPos, "HF2"); HeaderBufPos+=4;
        hfzMemcpy(HeaderBuf+HeaderBufPos, &(fh.FileVersionNo), 2); HeaderBufPos+=2;
        hfzMemcpy(HeaderBuf+HeaderBufPos, &(fh.nx), 4); HeaderBufPos+=4;
        hfzMemcpy(HeaderBuf+HeaderBufPos, &(fh.ny), 4); HeaderBufPos+=4;
        hfzMemcpy(HeaderBuf+HeaderBufPos, &(fh.TileSize), 2); HeaderBufPos+=2;
        hfzMemcpy(HeaderBuf+HeaderBufPos, &(fh.Precis), 4); HeaderBufPos+=4;
        hfzMemcpy(HeaderBuf+HeaderBufPos, &(fh.HorizScale), 4); HeaderBufPos+=4;

        // put extended header into a buffer
        char* pExtHeaderData = 0;
        long rval = hfzHeader_EncodeExtHeaderBuf(fh, &pExtHeaderData);
        if(rval<0) return rval;

        // now write in header length of ext header
        hfzMemcpy(HeaderBuf+HeaderBufPos, &(fh.ExtHeaderLength), 4);    

            HeaderBufPos+=4;

        // swap byte order if required (files use little endian)
        if(LIBHFZ_BYTEORDER_BIGENDIAN==hfzByteOrder) {
        HeaderBufPos = 4; // skip "HF2\0" string

           hfzByteSwap(HeaderBuf+HeaderBufPos, 2); HeaderBufPos+=2; // FileVersionNo
           hfzByteSwap(HeaderBuf+HeaderBufPos, 4); HeaderBufPos+=4; // nx
           hfzByteSwap(HeaderBuf+HeaderBufPos, 4); HeaderBufPos+=4; // ny
           hfzByteSwap(HeaderBuf+HeaderBufPos, 2); HeaderBufPos+=2; // TileSize
           hfzByteSwap(HeaderBuf+HeaderBufPos, 4); HeaderBufPos+=4; // Precis
           hfzByteSwap(HeaderBuf+HeaderBufPos, 4); HeaderBufPos+=4; // HorizScale
           hfzByteSwap(HeaderBuf+HeaderBufPos, 4); HeaderBufPos+=4; // ExtHeaderLength
       }

   // write header
   if(28!=hfzWrite(fs, HeaderBuf, 28)) 
       return LIBHFZ_ERROR_WRITE_HEADER_FAILED;

// write extended header
   if(pExtHeaderData) {
       if(fh.ExtHeaderLength!=hfzWrite(fs, pExtHeaderData, fh.ExtHeaderLength)) {
           hfzFree(pExtHeaderData);
           return LIBHFZ_ERROR_WRITE_EXTHEAD_FAILED;
       }
       hfzFree(pExtHeaderData);
   }

   return LIBHFZ_STATUS_OK;
   }

I believe it is trying to build up a char array (string ?) in memory so he can write this later to a binary file. This is the header part of the filetype. In java I would probably just use a string builder and then append away. However I do believe some byteaction is going on that each part of the string is exactly that amount of bytes , but I wonder with fh.nx that is a short what the result would be if the short is just value 1 ? is it " 1" or "0001". This is the part that is confusing me.

Any help or enlightenment in my lack of C knowledge is appreciated

it seems it would have been better to put the entire function here instead of just parts of it cause later on something is happening with the BIGENDIAN situation. Sorry for the formatting but getting it right on stackoverflow is nerve wrecking.

========= Preliminary result ==============

So I ended up using John Skeet's class to take care of the endian and came up with this ... I'm just wondering though that I'm not going about it all wrong. I'm rewriting based on the c++ method structure, but a lot of the methods are so low level , that they are somewhere available in the higher level C# ... Now I remember why I went to Java instead of C. I'm to quickly confused with all the pointer and memory handlings !

Just for reference this is the file format I'm trying to write and convert the library for: http://www.bundysoft.com/docs/doku.php?id=l3dt:formats:specs:hf2

    // copy header into buffer
    MiscUtil.Conversion.EndianBitConverter endian = MiscUtil.Conversion.EndianBitConverter.Big;
    if (BitConverter.IsLittleEndian)
    {
        endian = MiscUtil.Conversion.EndianBitConverter.Little;
    }

    MemoryStream buffer = new MemoryStream();
    EndianBinaryWriter writer = new EndianBinaryWriter(endian, buffer);
    writer.Write("HF2");
    writer.Write(fh.FileVersionNo);
    writer.Write(fh.nx);
    writer.Write(fh.ny);
    writer.Write(fh.TileSize);
    writer.Write(fh.Precis);
    writer.Write(fh.HorizScale);
kenny
  • 1,157
  • 1
  • 16
  • 41
  • A short that is equal to 1 takes the same number of bytes as a short equal to 32767... so yes, 0001 is the memory (or 0100 for machines that byte swap). – mah Mar 12 '14 at 20:50
  • 2
    "In java I would probably just use a string builder and then append away." You'll probably do something similar in C# - you need to understand the _intent_ of the code to translate it properly. – D Stanley Mar 12 '14 at 20:50
  • 2
    He's actually not building up a string, but a byte array to serialise binary data. char is the 'smallest' integer type in C/C++. – MicroVirus Mar 12 '14 at 20:50

3 Answers3

4

This is performing a kind of binary serialization for structured data. Check out BinaryWriter for similar functionality in .NET. This can be attached to any stream, but you can use MemoryStream if you want to use a byte array as the backing store (like in the C code.)

Note also (as another poster mentioned), you may have to watch for Endian-ness and other platform-specific issues, at least assuming you want to be binary-compatible with the C program. It's hard to say more without knowing the platform used for the original program and how you're inter-operating with it, if at all. For instance, is that data saved to a file that you want to be able to load?


UPDATE:

Based on your edit, it looks like the original code is Endian-aware. You can use BitConverter.IsLittleEndian to check the Endian-ness of your platform and make equivalent swap adjustments in your C# code to your byte array.

If you know you're running on Windows and don't want to worry about cross-platform support, you can assume the BinaryWriter is Little Endian (in fact, it might actually be Little Endian in Mono too even on Big Endian platforms, but I'm not sure.) If you want to be safe, you might check out a utility class by Jon Skeet that handles the necessary conversions.

Community
  • 1
  • 1
Dan Bryant
  • 27,329
  • 4
  • 56
  • 102
  • I left out most of the method because I didn't think it was all to relevant in a higher level language as C# but since it seems so I just put the entire method here. But I do believe BinaryWriter is the way I should look. the hfzMemCpy is just a wrapper where someone can use a own overwritten memcpy but when not setup it just uses a regular memcpy – kenny Mar 12 '14 at 21:10
  • for my purposed I'm 100% sure it will only run on windows, however maybe some other people would like a c# conversion of this library. So I better take it into account – kenny Mar 12 '14 at 21:22
1

Depends on sizeof (short) and whether the machine is big- or little-endian. sizeof(short) is probably 2 (but there's nothing that guarantees that), giving:

  • big-endian: 00 01 xx xx
  • little-endian: 01 00 xx xx

where xx is some random garbage. The 00 means a byte with value 0x00; 01 is a byte with value 0x01.

Quite why the code copies four bytes is a mystery...

The whole thing's horrible though: it causes platform-specific and (I'm fairly sure, but don't quote me) undefined behaviour.

Update: given OP's updates (that the vars are longs rather than shorts, and the additional code to handle endianness), my last statement is now somewhat unwarranted.

user3392484
  • 1,929
  • 9
  • 9
  • I read wrong they are long's not shorts that explains the four bytes – kenny Mar 12 '14 at 21:20
  • 1
    Also worth noting that 'long' in C# means Int64, so be cautious porting the structure format. – Dan Bryant Mar 12 '14 at 21:22
  • thanks for that I didn't knew that one yet. I made all my longs into int32 since int64 is 8 bytes , while it seems for longs he is writing 4 bytes. – kenny Mar 12 '14 at 21:51
0
[DllImport("kernel32.dll")]
private static extern void RtlMoveMemory(IntPtr dest, IntPtr src, int byteCount);

This is a true memory copy for use with pointers, and should work on all versions of Windows.

Dwedit
  • 618
  • 5
  • 11