ciderpress/diskimg/DiskImgPriv.h

349 lines
9.3 KiB
C++

/*
* CiderPress
* Copyright (C) 2007 by faddenSoft, LLC. All Rights Reserved.
* See the file LICENSE for distribution terms.
*/
/*
* Declarations common within but private to the DiskImg library.
*
* External code should not include this.
*/
#ifndef DISKIMG_DISKIMGPRIV_H
#define DISKIMG_DISKIMGPRIV_H
#include "DiskImgDetail.h"
#include <errno.h>
#include <assert.h>
// "GenericFD.h" included at end
using namespace DiskImgLib; // make life easy for all internal code
namespace DiskImgLib {
/*
* Debug logging macros.
*
* The macro choice implies a severity level, but we don't currently
* support that in the callback interface, so it's not used.
*/
#define DLOG_BASE(file, line, format, ...) \
Global::PrintDebugMsg((file), (line), (format), ##__VA_ARGS__)
//#ifdef SHOW_LOGV
# define LOGV(format, ...) DLOG_BASE(__FILE__, __LINE__, (format), ##__VA_ARGS__)
//#else
//# define LOGV(format, ...) ((void) 0)
//#endif
#define LOGD(format, ...) DLOG_BASE(__FILE__, __LINE__, (format), ##__VA_ARGS__)
#define LOGI(format, ...) DLOG_BASE(__FILE__, __LINE__, (format), ##__VA_ARGS__)
#define LOGW(format, ...) DLOG_BASE(__FILE__, __LINE__, (format), ##__VA_ARGS__)
#define LOGE(format, ...) DLOG_BASE(__FILE__, __LINE__, (format), ##__VA_ARGS__)
/* put this in to break on interesting events when built debug */
#if defined(_DEBUG)
# define DebugBreak() { assert(false); }
#else
# define DebugBreak() ((void) 0)
#endif
/*
* Standard goodies.
*/
#define NELEM(x) (sizeof(x) / sizeof(x[0]))
#define ErrnoOrGeneric() (errno != 0 ? (DIError) errno : kDIErrGeneric)
/* filename manipulation functions */
const char* FilenameOnly(const char* pathname, char fssep);
const char* FindExtension(const char* pathname, char fssep);
char* StrcpyNew(const char* str);
/* get/set integer values out of a memory buffer */
uint16_t GetShortLE(const uint8_t* buf);
uint32_t GetLongLE(const uint8_t* buf);
uint16_t GetShortBE(const uint8_t* buf);
uint32_t GetLongBE(const uint8_t* buf);
uint32_t Get24BE(const uint8_t* ptr);
void PutShortLE(uint8_t* ptr, uint16_t val);
void PutLongLE(uint8_t* ptr, uint32_t val);
void PutShortBE(uint8_t* ptr, uint16_t val);
void PutLongBE(uint8_t* ptr, uint32_t val);
/* little-endian read/write, for file headers (mainly 2MG and DC42) */
DIError ReadShortLE(GenericFD* pGFD, uint16_t* pBuf);
DIError ReadLongLE(GenericFD* pGFD, uint32_t* pBuf);
DIError WriteShortLE(FILE* fp, uint16_t val);
DIError WriteLongLE(FILE* fp, uint32_t val);
DIError WriteShortLE(GenericFD* pGFD, uint16_t val);
DIError WriteLongLE(GenericFD* pGFD, uint32_t val);
DIError WriteShortBE(GenericFD* pGFD, uint16_t val);
DIError WriteLongBE(GenericFD* pGFD, uint32_t val);
#ifdef _WIN32
/* Windows helpers */
DIError LastErrorToDIError(void);
bool IsWin9x(void);
#endif
/*
* Provide access to a buffer of data as if it were a circular buffer.
* Access is through the C array operator ([]).
*
* This DOES NOT own the array it is handed, and will not try to
* free it.
*/
class CircularBufferAccess {
public:
CircularBufferAccess(uint8_t* buf, long len) :
fBuf(buf), fLen(len)
{ assert(fLen > 0); assert(fBuf != NULL); }
CircularBufferAccess(const uint8_t* buf, long len) :
fBuf(const_cast<uint8_t*>(buf)), fLen(len)
{ assert(fLen > 0); assert(fBuf != NULL); }
~CircularBufferAccess(void) {}
/*
* Be circular. Assume that we won't stray far past the end, so
* it's cheaper to subtract than mod.
*/
uint8_t& operator[](int idx) const {
if (idx < 0) {
assert(false);
}
while (idx >= fLen)
idx -= fLen;
return fBuf[idx];
}
//uint8_t* GetPointer(int idx) const {
// while (idx >= fLen)
// idx -= fLen;
// return &fBuf[idx];
//}
int Normalize(int idx) const {
while (idx >= fLen)
idx -= fLen;
return idx;
}
long GetSize(void) const {
return fLen;
}
private:
uint8_t* fBuf;
long fLen;
};
/*
* Manage an output buffer into which we write one bit at a time.
*
* Bits fill in from the MSB to the LSB. If we write 10 bits, the
* output buffer will look like this:
*
* xxxxxxxx xx000000
*
* Call WriteBit() repeatedly. When done, call Finish() to write any pending
* data and return the number of bits in the buffer.
*/
class BitOutputBuffer {
public:
/* pass in the output buffer and the output buffer's size */
BitOutputBuffer(uint8_t* buf, int size) {
fBufStart = fBuf = buf;
fBufSize = size;
fBitMask = 0x80;
fByte = 0;
fOverflow = false;
}
virtual ~BitOutputBuffer(void) {}
/* write a single bit */
void WriteBit(int val) {
if (fBuf - fBufStart >= fBufSize) {
if (!fOverflow) {
LOGI("Overran bit output buffer");
DebugBreak();
fOverflow = true;
}
return;
}
if (val)
fByte |= fBitMask;
fBitMask >>= 1;
if (fBitMask == 0) {
*fBuf++ = fByte;
fBitMask = 0x80;
fByte = 0;
}
}
/* flush pending bits; returns length in bits (or -1 on overrun) */
int Finish(void) {
int outputBits;
if (fOverflow)
return -1;
outputBits = (fBuf - fBufStart) * 8;
if (fBitMask != 0x80) {
*fBuf++ = fByte;
assert(fBitMask != 0);
while (fBitMask != 0x80) {
outputBits++;
fBitMask <<= 1;
}
}
return outputBits;
}
private:
uint8_t* fBufStart;
uint8_t* fBuf;
int fBufSize;
uint8_t fBitMask;
uint8_t fByte;
bool fOverflow;
};
/*
* Extract data from the buffer one bit or one byte at a time.
*/
class BitInputBuffer {
public:
BitInputBuffer(const uint8_t* buf, int bitCount) {
fBufStart = fBuf = buf;
fBitCount = bitCount;
fCurrentBit = 0;
fBitPosn = 7;
fBitsConsumed = 0;
}
virtual ~BitInputBuffer(void) {}
/*
* Get the next bit. Returns 0 or 1.
*
* If we wrapped around to the start of the buffer, and "pWrap" is
* non-null, set "*pWrap". (This does *not* set it to "false" if we
* don't wrap.)
*/
uint8_t GetBit(bool* pWrap) {
uint8_t val;
//assert(fBitPosn == 7 - (fCurrentBit & 0x07));
if (fCurrentBit == fBitCount) {
/* end reached, wrap to start */
fCurrentBit = 0;
fBitPosn = 7;
fBuf = fBufStart;
//fByte = *fBuf++;
if (pWrap != NULL)
*pWrap = true;
}
val = (*fBuf >> fBitPosn) & 0x01;
fCurrentBit++;
fBitPosn--;
if (fBitPosn < 0) {
fBitPosn = 7;
fBuf++;
}
fBitsConsumed++;
return val;
}
/*
* Get the next 8 bits.
*/
uint8_t GetByte(bool* pWrap) {
uint8_t val;
int i;
if (true || fCurrentBit > fBitCount-8) {
/* near end, use single-bit function iteratively */
val = 0;
for (i = 0; i < 8; i++)
val = (val << 1) | GetBit(pWrap);
} else {
/* room to spare, grab it in one or two chunks */
assert(false);
}
return val;
}
/*
* Set the start position.
*/
void SetStartPosition(int bitOffset) {
assert(bitOffset >= 0 && bitOffset < fBitCount);
fCurrentBit = bitOffset;
fBitPosn = 7 - (bitOffset & 0x07); // mod 8, 0 to MSB
fBuf = fBufStart + (bitOffset >> 3); // div 8
}
/* used to ensure we consume exactly 100% of bits */
void ResetBitsConsumed(void) { fBitsConsumed = 0; }
int GetBitsConsumed(void) const { return fBitsConsumed; }
private:
const uint8_t* fBufStart;
const uint8_t* fBuf;
int fBitCount; // #of bits in buffer
int fCurrentBit; // where we are in buffer
int fBitPosn; // which bit to access within byte
//uint8_t fByte;
int fBitsConsumed; // sanity check - all bits used?
};
/*
* Linear bitmap. Suitable for use as a bad block map.
*/
class LinearBitmap {
public:
LinearBitmap(int numBits) {
assert(numBits > 0);
fBits = new uint8_t[(numBits + 7) / 8];
memset(fBits, 0, (numBits + 7) / 8);
fNumBits = numBits;
}
~LinearBitmap(void) {
delete[] fBits;
}
/*
* Set or get the status of bit N.
*/
bool IsSet(int bit) const {
assert(bit >= 0 && bit < fNumBits);
return ((fBits[bit >> 3] >> (bit & 0x07)) & 0x01) != 0;
}
void Set(int bit) {
assert(bit >= 0 && bit < fNumBits);
fBits[bit >> 3] |= 1 << (bit & 0x07);
}
private:
uint8_t* fBits;
int fNumBits;
};
} // namespace DiskImgLib
/*
* Most of the code needs these.
*/
#include "GenericFD.h"
#endif /*DISKIMG_DISKIMGPRIV_H*/