Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

@quirinpa
Last active April 9, 2016 22:07
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save quirinpa/b3e3ea4bb416b7c20d73 to your computer and use it in GitHub Desktop.
Save quirinpa/b3e3ea4bb416b7c20d73 to your computer and use it in GitHub Desktop.
/* fileb.h - write/read files bit by bit
*
* MIT License
*
* Copyright (c) 2016 Paulo André Azevedo Quirino
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* quirinpa@gmail.com
*/
#ifndef FILEB_H
#define FILEB_H
#include <stdio.h>
typedef struct bCursor {
unsigned char d;
size_t s;
} bitCursor;
/* creates a new bitCursor object with default values
* (needed for starting bit-wise read/write operations,
* a pointer to that same cursor must then be provided
* to subsequent read/write operations until all data is
* read/written)
*
* @returns cursor with default values
*/
bitCursor newBitCursor() {
bitCursor c = {0, 0};
return c;
}
#define curBusySpace c->s
#define curData c->d
/* Writes a number of bits into a file
*
* @param ptr a pointer to the variable containing the data to be written
* @param sizeb the number of bits to be written
* @param rSizeb the real size of the variable in bits
* @param fp a pointer to the file
* @param c a pointer to a bitCursor (possibly containing bits from the last variable written)
*/
void fwriteb(void *restrict ptr, size_t sizeb, size_t rSizeb, FILE *fp, bitCursor *c) {
size_t firstRelevantBit = rSizeb - sizeb,
firstRelevantByte = firstRelevantBit / 8,
distanceToStartOfByte = firstRelevantBit - firstRelevantByte * 8;
unsigned char *pchar = (unsigned char*)ptr + firstRelevantByte; // Assuming little Endian
size_t bitsToWrite = sizeb,
bitsToAdd;
readywrite:
bitsToAdd = 8 - (curBusySpace > distanceToStartOfByte ? curBusySpace : distanceToStartOfByte);
curData |= (*pchar << distanceToStartOfByte) >> curBusySpace;
curBusySpace += bitsToAdd;
if (curBusySpace >= 8) {
fwrite(&curData, 1, 1, fp);
curBusySpace = curData = 0;
}
bitsToWrite -= bitsToAdd;
if (bitsToWrite <= 0) return;
distanceToStartOfByte += bitsToAdd;
if (distanceToStartOfByte >= 8) {
distanceToStartOfByte = 0;
pchar++;
}
goto readywrite;
}
/* Writes the remaining bits after a sequence of fwriteb operations
* (required for correct behaviour)
*
* @param fp a pointer to the file
* @param c a pointer to a bitCursor (possibly containing bits from the last variable written)
*/
void fcloseb(FILE *fp, bitCursor *c) {
if (curBusySpace <= 0) return;
fwrite(&curData, 1, 1, fp);
}
/* Reads a number of bits from a file (it is your responsibility to init the var as 0)
*
* @param ptr a pointer to the variable in which to write data that is read
* @param sizeb the number of bits to be read
* @param rSizeb the real size of the variable in bits
* @param fp a pointer to the file
* @param c a pointer to a bitCursor (possibly containing bits from the last read Byte)
*/
void freadb(void *restrict ptr, size_t sizeb, size_t rSizeb, FILE *fp, bitCursor *c) {
size_t firstRelevantBit = rSizeb - sizeb,
firstRelevantByte = firstRelevantBit / 8,
distanceToStartOfByte = firstRelevantBit - firstRelevantByte*8;
unsigned char *pchar = (unsigned char*)ptr + firstRelevantByte;
size_t bitsToRead = sizeb,
bitsToAdd,
availableBits = 8 - distanceToStartOfByte;
readyread:
if (curBusySpace <= 0) {
fread(&curData, 1, 1, fp);
curBusySpace = 8;
}
bitsToAdd = curBusySpace > availableBits ? availableBits : curBusySpace;
(*pchar) |= curData >> distanceToStartOfByte;
curData <<= bitsToAdd;
curBusySpace -= bitsToAdd;
bitsToRead -= bitsToAdd;
if (bitsToRead <= 0) return;
distanceToStartOfByte += bitsToAdd;
if (distanceToStartOfByte >= 8) {
distanceToStartOfByte = 0;
pchar++;
}
availableBits = 8 - distanceToStartOfByte;
goto readyread;
}
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment