/* * 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 #include // "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(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*/