0
votes

I have some old C code that looks like this:

#include <stdio.h>
#include <strings.h>
main()
{

    FILE *output;

    struct socket_cpacket
    {
        char    type;                                /* CP_SOCKET */
        char    version;
        char    udp_version;                         /* was pad2 */
        char    pad3;
        unsigned socket;
    };

    struct socket_cpacket sockPack;

    bzero(&sockPack,sizeof(sockPack));
    sockPack.type = 27;
    sockPack.version = 4;
    sockPack.udp_version = 10;
    sockPack.pad3 = 0;
    sockPack.socket = 0;

    output = fopen("/tmp/sockPack.bin", "wb");
    fwrite(&sockPack, sizeof(sockPack), 1, output);
}

I'd like to duplicate this functionality in obj-c and I started down the path of using NSCoding protocol.

CP_Socket.h

#import <Foundation/Foundation.h>

@interface CP_Socket : NSObject <NSCoding>
{
@private
    char type;
    char version;
    char udp_version;
    char pad3;
    unsigned int socket;
}

@property (readonly) char type;
@property (readonly) char version;
@property (readonly) char udp_version;
@property (readonly) char pad3;
@property unsigned int socket;

typedef enum {
    mTYPE = 27,
    mVERSION = 4,
    mUDP_VERSION = 10,
} cpSocketEnum;

@end

And CP_Socket.m

#import "CP_Socket.h"

@implementation CP_Socket

#pragma mark ======== properties =========

@synthesize  type;
@synthesize  version;
@synthesize  udp_version;
@synthesize  pad3;
@synthesize  socket;


- (id)init {
    NSLog(@"init");

    if( !( self = [super init] ) )
        return nil;

    type = mTYPE;
    version = mVERSION;
    udp_version = mUDP_VERSION;
    pad3 = 0;
    socket = 0;

    return self;
}

#pragma mark ======== Archiving and unarchiving methods =========
//
// Archives and Serializations Programming Guide for Cocoa
// http://bit.ly/PAaRsV
//
// NSCoding Protocol Reference
// http://bit.ly/PAb1Rd
//

- (void)encodeWithCoder:(NSCoder *)coder
{
    NSLog(@"encodeWithCoder");

    [coder encodeBytes:[self type] length:1 forKey:@"type"];
    //[coder encodeBytes:[self version] length:1 forKey:@"version"];
    //[coder encodeBytes:[self udp_version] length:1 forKey:@"udp_version"];
    //[coder encodeBytes:[self pad3] length:1 forKey:@"pad3"];
    //[coder encodeInt:[self socket] forKey:@"socket"];

}

- (id)initWithCoder:(NSCoder *)coder
{
    NSLog(@"initWithCoder");
}
@end

First problem, [coder encodeBytes:[self type] length:1 forKey:@"type"]; throws a warning. Incompatible integer to pointer conversion sending 'char' to parameter of type 'const uint8_t *.

How do I encode a char?

I tried [coder encodeInt:[self type] forKey:@"type"]; but char != int.

Going with the code to further understand how it work; the file the obj-c code generates is 280 bytes and looking inside the file I see what looks like name-mangled class identifiers.

I've tried NSKeyedArchiver and NSArchiver with the same results.

I don't know where to go from here. The C-code generates a 8 byte file. I'd like the obj-c code to do the same while using some of the OO stuff like the NSCoding protocol.

I feel like I'm going to have to extend the NSCoder object to make this work.

Any help would be appreciated.

2
"How do I encode a char?" Pass a pointer to it. char c = [self type]; [coder encodeBytes:&c length:1 forKey:@"type"];user529758
Throws warning: Sending 'char *' to parameter of type 'const uint8_t *' (aka 'const unsigned char *') converts between points to integer types with different signBob Tanner
or unsigned char, or whatever. That warning is not something to be afraid of.user529758

2 Answers

0
votes

The first argument to encodeBytes:length:forKey: is expected to be a pointer to the buffer you want to encode, so take the address of your ivar:

[coder encodeBytes:&type length:1 forKey:@"type"];

Or make a temp variable, put the result of the property access in that, and take its address.

Using encodeInt:forKey: should work too (with a cast), but it'll inflate the size of your data file.

If you really wanted to, you could certainly extend NSCoder with a category:

@implementation NSCoder (BTEncodeChar)
- (void)BTencodeChar: (char)c forKey: (NSString *)key
{
    [self encodeBytes:&c length:1 forKey:key];
}
@end
0
votes

I dont know much about NSCoding, but obj C interops with C just fine. Take your existing code put it in a function with params and call it.