Skip to content

Instantly share code, notes, and snippets.

@NickBeeuwsaert
Last active August 29, 2015 14:11
Show Gist options
  • Select an option

  • Save NickBeeuwsaert/995300d192d71ef5a7d4 to your computer and use it in GitHub Desktop.

Select an option

Save NickBeeuwsaert/995300d192d71ef5a7d4 to your computer and use it in GitHub Desktop.
C functions for reading data out of a binary function, similar to pythons struct module
//
// endian.h
//
// Created by Nick Beeuwsaert on 5/17/14.
// Copyright (c) 2014 Nick Beeuwsaert.
// MIT Licensed.
//
#ifndef __ENDIAN_H__
#define __ENDIAN_H__
#if defined(__linux__) || defined(__CYGWIN__)
# include <endian.h>
#elif defined(__APPLE__)
#include <libkern/OSByteOrder.h>
#define le16toh(x) OSSwapLittleToHostInt16(x)
#define htole16(x) OSSwapHostToLittleInt16(x)
#define be16toh(x) OSSwapBigToHostInt16(x)
#define htobe16(x) OSSwapHostToBigInt16(x)
#define le32toh(x) OSSwapLittleToHostInt32(x)
#define htole32(x) OSSwapHostToLittleInt32(x)
#define be32toh(x) OSSwapBigToHostInt32(x)
#define htobe32(x) OSSwapHostToBigInt32(x)
#define le64toh(x) OSSwapLittleToHostInt64(x)
#define htole64(x) OSSwapHostToLittleInt64(x)
#define be64toh(x) OSSwapBigToHostInt64(x)
#define htobe64(x) OSSwapHostToBigInt64(x)
#elif defined(__OpenBSD__)
#include <sys/endian.h>
#elif defined(_WIN32) || defined(__MINGW32__)
#if BYTE_ORDER == BIG_ENDIAN
//XBox 360
#define htobe16(x) (x)
#define htole16(x) __builtin_bswap16(x)
#define be16toh(x) (x)
#define le16toh(x) __builtin_bswap16(x)
#define htobe32(x) (x)
#define htole32(x) __builtin_bswap32(x)
#define be32toh(x) (x)
#define le32toh(x) __builtin_bswap32(x)
#define htobe64(x) (x)
#define htole64(x) __builtin_bswap64(x)
#define be64toh(x) (x)
#define le64toh(x) __builtin_bswap64(x)
#elif BYTE_ORDER == LITTLE_ENDIAN
#define htobe16(x) htons(x)
#define htole16(x) (x)
#define be16toh(x) ntohs(x)
#define le16toh(x) (x)
#define htobe32(x) htonl(x)
#define htole32(x) (x)
#define be32toh(x) ntohl(x)
#define le32toh(x) (x)
#define htobe64(x) htonll(x)
#define htole64(x) (x)
#define be64toh(x) ntohll(x)
#define le64toh(x) (x)
#else
#error bad byte order
#endif
#else
#error platform not supported
#endif
#endif
//
// Pack.cpp
//
// Created by Nick Beeuwsaert on 5/17/14.
// Copyright (c) 2014 Nick Beeuwsaert.
// MIT Licensed.
//
#include "Pack.h"
#include <stdarg.h>
#include <stdlib.h>
#include <stdbool.h>
#include <ctype.h>
#include "endian.h"
void unpack(FILE* f, const char *fmt, ...){
va_list ap;
bool big_endian = __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__;
va_start(ap, fmt);
for(;*fmt != '\0'; fmt++){
unsigned long int length=1;
if(isdigit(*fmt)){
length = strtoul(fmt, (char**)&fmt, 10);
}
switch(*fmt){
case '>':
case '<':
big_endian = *fmt=='>';
break;
case 'I':
case 'i':
{
uint32_t *data = va_arg(ap, uint32_t*);
while(length-->0){
//file.read((char*)data, sizeof(uint32_t));
fread(data, sizeof(uint32_t), 1, f);
*(data++) = big_endian?be32toh(*data):le32toh(*data);
}
}break;
case 'H':
case 'h':
{
uint16_t *data = va_arg(ap, uint16_t*);
while(length-->0){
//file.read((char*)data, sizeof(uint16_t));
fread(data, sizeof(uint16_t), 1, f);
*(data++) = big_endian?be16toh(*data):le16toh(*data);
}
}break;
// B and c could probably be to same thing....
case 'B':
case 'b':
{
uint8_t *str_bytes = va_arg(ap, uint8_t*);
fread(str_bytes, sizeof(uint8_t), length, f);
//file.read((char*)str_bytes, length);
}break;
case 'c':{
char *str = va_arg(ap, char*);
fread(str, sizeof(char), length, f);
//file.read(str, length);
}break;
case 'x':
//file.seekg(length, file.cur);
fseek(f, length, SEEK_CUR);
continue;
}
}
va_end(ap);
}
unsigned int calcsize(const char *fmt){
unsigned int size = 0;
for(;*fmt != '\0'; fmt++){
unsigned long int length=1;
if(isdigit(*fmt)){
length = strtoul(fmt, (char**)&fmt, 10);
}
switch(*fmt){
case 'I':
case 'i':
size += length * 4;
break;
case 'H':
case 'h':
size += length * 2;
break;
case 'B':
case 'b':
case 'c':
case 'x':
size += length;
break;
}
}
return size;
}
//
// Pack.h
//
// Created by Nick Beeuwsaert on 5/17/14.
// Copyright (c) 2014 Nick Beeuwsaert.
// MIT Licensed.
//
#ifndef __PACK_H__
#define __PACK_H__
#include <stdio.h>
/**
* Unpacks the data from file into variables
* Supposed to work similar to how python's struct works
* > Means switch to Big Endian
* < Means switch to Little Endian
* H means read a short (uint16_t)
* I means read a int (uint32_t)
* B means read a byte
* c means read a character
* x means skip a byte
* you can prefix a format character with a number to
* mark how many of the following type to read
* unlike pythons struct, the case of the letter doesn't matter
*
* @param file The file to read data from
* @param format The format to use to read
* @param ... Variables to write out to
*/
void unpack(FILE *, const char *, ...);
/**
* Calculates the size of the fmt passed
* See unpack for fmt description
*
* @param fmt The format
*/
unsigned int calcsize(const char*);
#endif /* __PACK_H__ */
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment