mirror of
https://github.com/fadden/ciderpress.git
synced 2024-11-26 17:49:21 +00:00
365 lines
9.0 KiB
C++
365 lines
9.0 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 __DISK_IMG_PRIV__
|
|
#define __DISK_IMG_PRIV__
|
|
|
|
#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 {
|
|
|
|
#ifndef _DEBUG_LOG
|
|
//# define _DEBUG_LOG /* define this to force log msgs in non-debug build */
|
|
#endif
|
|
|
|
#if defined(_DEBUG) || defined(_DEBUG_LOG)
|
|
# define _DEBUG_MSGS
|
|
#endif
|
|
|
|
/*
|
|
* Win32-style debug message macros.
|
|
*/
|
|
#ifdef _DEBUG_MSGS
|
|
#define WMSG0(fmt) \
|
|
Global::PrintDebugMsg(__FILE__, __LINE__, fmt)
|
|
#define WMSG1(fmt, arg0) \
|
|
Global::PrintDebugMsg(__FILE__, __LINE__, fmt, arg0)
|
|
#define WMSG2(fmt, arg0, arg1) \
|
|
Global::PrintDebugMsg(__FILE__, __LINE__, fmt, arg0, arg1)
|
|
#define WMSG3(fmt, arg0, arg1, arg2) \
|
|
Global::PrintDebugMsg(__FILE__, __LINE__, fmt, arg0, arg1, arg2)
|
|
#define WMSG4(fmt, arg0, arg1, arg2, arg3) \
|
|
Global::PrintDebugMsg(__FILE__, __LINE__, fmt, arg0, arg1, arg2, arg3)
|
|
#define WMSG5(fmt, arg0, arg1, arg2, arg3, arg4) \
|
|
Global::PrintDebugMsg(__FILE__, __LINE__, fmt, arg0, arg1, arg2, arg3, arg4)
|
|
#else
|
|
#define WMSG0(fmt) ((void) 0)
|
|
#define WMSG1(fmt, arg0) ((void) 0)
|
|
#define WMSG2(fmt, arg0, arg1) ((void) 0)
|
|
#define WMSG3(fmt, arg0, arg1, arg2) ((void) 0)
|
|
#define WMSG4(fmt, arg0, arg1, arg2, arg3) ((void) 0)
|
|
#define WMSG5(fmt, arg0, arg1, arg2, arg3, arg4) ((void) 0)
|
|
#endif
|
|
|
|
/* 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) ((int) (sizeof(x) / sizeof(x[0])))
|
|
|
|
#define nil NULL
|
|
|
|
#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 */
|
|
unsigned short GetShortLE(const unsigned char* buf);
|
|
unsigned long GetLongLE(const unsigned char* buf);
|
|
unsigned short GetShortBE(const unsigned char* buf);
|
|
unsigned long GetLongBE(const unsigned char* buf);
|
|
unsigned long Get24BE(const unsigned char* ptr);
|
|
void PutShortLE(unsigned char* ptr, unsigned short val);
|
|
void PutLongLE(unsigned char* ptr, unsigned long val);
|
|
void PutShortBE(unsigned char* ptr, unsigned short val);
|
|
void PutLongBE(unsigned char* ptr, unsigned long val);
|
|
|
|
/* little-endian read/write, for file headers (mainly 2MG and DC42) */
|
|
DIError ReadShortLE(GenericFD* pGFD, short* pBuf);
|
|
DIError ReadLongLE(GenericFD* pGFD, long* pBuf);
|
|
DIError WriteShortLE(FILE* fp, unsigned short val);
|
|
DIError WriteLongLE(FILE* fp, unsigned long val);
|
|
DIError WriteShortLE(GenericFD* pGFD, unsigned short val);
|
|
DIError WriteLongLE(GenericFD* pGFD, unsigned long val);
|
|
DIError WriteShortBE(GenericFD* pGFD, unsigned short val);
|
|
DIError WriteLongBE(GenericFD* pGFD, unsigned long 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(unsigned char* buf, long len) :
|
|
fBuf(buf), fLen(len)
|
|
{ assert(fLen > 0); assert(fBuf != nil); }
|
|
CircularBufferAccess(const unsigned char* buf, long len) :
|
|
fBuf(const_cast<unsigned char*>(buf)), fLen(len)
|
|
{ assert(fLen > 0); assert(fBuf != nil); }
|
|
~CircularBufferAccess(void) {}
|
|
|
|
/*
|
|
* Be circular. Assume that we won't stray far past the end, so
|
|
* it's cheaper to subtract than mod.
|
|
*/
|
|
unsigned char& operator[](int idx) const {
|
|
if (idx < 0) {
|
|
assert(false);
|
|
}
|
|
while (idx >= fLen)
|
|
idx -= fLen;
|
|
return fBuf[idx];
|
|
}
|
|
|
|
//unsigned char* 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:
|
|
unsigned char* 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(unsigned char* 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) {
|
|
WMSG0("Overran bit output buffer\n");
|
|
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:
|
|
unsigned char* fBufStart;
|
|
unsigned char* fBuf;
|
|
int fBufSize;
|
|
unsigned char fBitMask;
|
|
unsigned char fByte;
|
|
bool fOverflow;
|
|
};
|
|
|
|
/*
|
|
* Extract data from the buffer one bit or one byte at a time.
|
|
*/
|
|
class BitInputBuffer {
|
|
public:
|
|
BitInputBuffer(const unsigned char* 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.)
|
|
*/
|
|
unsigned char GetBit(bool* pWrap) {
|
|
unsigned char val;
|
|
|
|
//assert(fBitPosn == 7 - (fCurrentBit & 0x07));
|
|
|
|
if (fCurrentBit == fBitCount) {
|
|
/* end reached, wrap to start */
|
|
fCurrentBit = 0;
|
|
fBitPosn = 7;
|
|
fBuf = fBufStart;
|
|
//fByte = *fBuf++;
|
|
if (pWrap != nil)
|
|
*pWrap = true;
|
|
}
|
|
|
|
val = (*fBuf >> fBitPosn) & 0x01;
|
|
|
|
fCurrentBit++;
|
|
fBitPosn--;
|
|
if (fBitPosn < 0) {
|
|
fBitPosn = 7;
|
|
fBuf++;
|
|
}
|
|
|
|
fBitsConsumed++;
|
|
return val;
|
|
}
|
|
|
|
/*
|
|
* Get the next 8 bits.
|
|
*/
|
|
unsigned char GetByte(bool* pWrap) {
|
|
unsigned char 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 unsigned char* fBufStart;
|
|
const unsigned char* fBuf;
|
|
int fBitCount; // #of bits in buffer
|
|
int fCurrentBit; // where we are in buffer
|
|
int fBitPosn; // which bit to access within byte
|
|
//unsigned char 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 unsigned char[(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:
|
|
unsigned char* fBits;
|
|
int fNumBits;
|
|
};
|
|
|
|
|
|
}; // namespace DiskImgLib
|
|
|
|
/*
|
|
* Most of the code needs these.
|
|
*/
|
|
#include "GenericFD.h"
|
|
|
|
#endif /*__DISK_IMG_PRIV__*/
|