Упаковка целых в байты (NSData) - PullRequest
4 голосов
/ 10 сентября 2010

Я хочу упаковать MIDI-сообщение в объект NSData.

int messageType = 3; // 0-15
int channel = 5;      // 0-15
int data1 = 56;       // 0-127
int data2 = 78;       // 0-127

int packed = data2;
packed += data1 * 127;
packed += channel * 16129; // 127^2
packed += messageType * 258064; // 127^2 * 16

NSLog(@"packed %d", packed);

NSData *packedData = [NSData dataWithBytes:&packed length:sizeof(packed)];

int recovered;
[packedData getBytes:&recovered];

NSLog(@"recovered %d", recovered);

Это прекрасно работает, и хотя я горжусь собой, я знаю, что преобразование в байты не выполнено правильно: это должно быть прямое преобразование без большого сложения и умножения.Как это можно сделать?

Редактировать: Теперь я знаю, что могу просто сделать это

char theBytes[] = {messageType, channel, data1, data2};
NSData *packedData = [NSData dataWithBytes:&theBytes length:sizeof(theBytes)];

и на стороне Java

byte[] byteBuffer = new byte[4]; // Receive buffer
while (in.read(byteBuffer) != -1) {  
    System.out.println("data2="  + byteBuffer[3]);
}

и это будет работать, но я бы хотел, чтобы решение получило NSData всего с 3 байтами.

Ответы [ 3 ]

3 голосов
/ 10 сентября 2010

Лично я бы пошел на NSString:

NSString *dataString = [NSString stringWithFormat:@"%i+%i+%i+%i", messageType, channel, data1, data2];
NSData *packedData = [dataString dataUsingEncoding:NSUTF8StringEncoding];

Легко использовать и легко переносить. Распаковка немного сложнее, но совсем не сложна.

NSScanner *scanner = [NSScanner scannerWithString:[[[NSString alloc] initWithData:packedData encoding:NSUTF8StringEncoding] autorelease]];
int messageType, channel, data1, data2;
[scanner scanInt:&messageType];
[scanner scanInt:&channel];
[scanner scanInt:&data1];
[scanner scanInt:&data2];
2 голосов
/ 10 сентября 2010

Вот 3-байтовое решение, которое я собрал.

char theBytes[] = {message_type  * 16 + channel, data1, data2};
NSData *packedData = [NSData dataWithBytes:&theBytes length:sizeof(theBytes)];

char theBytesRecovered[3];
[packedData getBytes:theBytesRecovered];

int messageTypeAgain = (int)theBytesRecovered[0]/16;
int channelAgain = (int)theBytesRecovered[0] % 16;
int data1Again = (int)theBytesRecovered[1];
int data2Again = (int)theBytesRecovered[2];

NSLog(@"packed %d %d %d %d", messageTypeAgain, channelAgain, data1Again, data2Again);

и на другой стороне провода это так же легко подобрать, потому что каждый байт является байтом. Я только что закончил пробовать это на стороне iOS и на стороне Java, и никаких проблем также нет. Нет проблем с порядком байтов, потому что каждое целое число помещается в один байт (или два в одном байте, в одном случае).

0 голосов
/ 10 сентября 2010

у вас есть несколько вариантов.

, поскольку похоже, что вы хотите непрерывный шарик данных в представлении NSData ...

вы захотите создать упакованную структуру и передать данные в вызов NSData в качестве предопределенного порядка байтов (чтобы оба конца знали, как разархивировать глобус данных).

/* pack this struct's ivars and and enable -Wreorder to sanity check that the compiler does not reorder members -- i see no reason for the compiler to do this since the fields are equal size/type */
struct t_midi_message {
    UInt8 message_type; /* 0-15 */
    UInt8 channel; /* 0-15 */
    UInt8 data1; /* 0-127 */
    UInt8 data2; /* 0-127 */
};

union t_midi_message_archive {
/* members - as a union for easy endian swapping */
    SInt32 glob;
    t_midi_message message;
    enum { ValidateSize = 1 / (4 == sizeof(t_midi_message)) };
/* nothing unusual here, although you may want a ctor which takes NSData as an argument */
    t_midi_message_archive();
    t_midi_message_archive(const t_midi_message&);
    t_midi_message_archive(const t_midi_message_archive&);
    t_midi_message_archive& operator=(const t_midi_message_archive&);

/* swap routines -- just pass @member glob to the system's endian routines */
    void swapToNativeEndianFromTransferEndian();
    void swapToTransferEndianFromNativeEndian();

};

void a(const t_midi_message_archive& msg) {

    t_midi_message_archive copy(msg);
    copy.swapToTransferEndianFromNativeEndian();

    NSData * packedData([NSData dataWithBytes:&copy.glob length:sizeof(copy.glob)]);
    assert(packedData);

    t_midi_message_archive recovered;
    [packedData getBytes:&recovered.glob];

    recovered.swapToNativeEndianFromTransferEndian();
    /* recovered may now be used safely */
}
...