mirror of
https://github.com/fadden/ciderpress.git
synced 2024-11-23 11:33:58 +00:00
aa3145856c
Focusing on the diskimg library this time, which deals with a lot of filesystem structures that have specific widths. This is still a bit lax in places, e.g. using "long" for lengths. Should either specify a bit width or use di_off_t. Also, added "override" keyword where appropriate. Also, bumped library version to 5.0.0.
349 lines
9.3 KiB
C++
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*/
|