mirror of
https://github.com/fadden/ciderpress.git
synced 2024-12-22 05:29:43 +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.
361 lines
8.9 KiB
C++
361 lines
8.9 KiB
C++
/*
|
|
* CiderPress
|
|
* Copyright (C) 2007 by faddenSoft, LLC. All Rights Reserved.
|
|
* See the file LICENSE for distribution terms.
|
|
*/
|
|
/*
|
|
* DiskImgLib global utility functions.
|
|
*/
|
|
#include "StdAfx.h"
|
|
#include "DiskImgPriv.h"
|
|
|
|
#define kFilenameExtDelim '.' /* separates extension from filename */
|
|
|
|
/*
|
|
* Get values from a memory buffer.
|
|
*/
|
|
uint16_t DiskImgLib::GetShortLE(const uint8_t* ptr)
|
|
{
|
|
return *ptr | (uint16_t) *(ptr+1) << 8;
|
|
}
|
|
|
|
uint32_t DiskImgLib::GetLongLE(const uint8_t* ptr)
|
|
{
|
|
return *ptr |
|
|
(uint32_t) *(ptr+1) << 8 |
|
|
(uint32_t) *(ptr+2) << 16 |
|
|
(uint32_t) *(ptr+3) << 24;
|
|
}
|
|
|
|
uint16_t DiskImgLib::GetShortBE(const uint8_t* ptr)
|
|
{
|
|
return *(ptr+1) | (uint16_t) *ptr << 8;
|
|
}
|
|
|
|
uint32_t DiskImgLib::GetLongBE(const uint8_t* ptr)
|
|
{
|
|
return *(ptr+3) |
|
|
(uint32_t) *(ptr+2) << 8 |
|
|
(uint32_t) *(ptr+1) << 16 |
|
|
(uint32_t) *ptr << 24;
|
|
}
|
|
|
|
uint32_t DiskImgLib::Get24BE(const uint8_t* ptr)
|
|
{
|
|
return *(ptr+2) |
|
|
(uint32_t) *(ptr+1) << 8 |
|
|
(uint32_t) *ptr << 16;
|
|
}
|
|
|
|
void DiskImgLib::PutShortLE(uint8_t* ptr, uint16_t val)
|
|
{
|
|
*ptr++ = (uint8_t) val;
|
|
*ptr = val >> 8;
|
|
}
|
|
|
|
void DiskImgLib::PutLongLE(uint8_t* ptr, uint32_t val)
|
|
{
|
|
*ptr++ = (uint8_t) val;
|
|
*ptr++ = (uint8_t) (val >> 8);
|
|
*ptr++ = (uint8_t) (val >> 16);
|
|
*ptr = (uint8_t) (val >> 24);
|
|
}
|
|
|
|
void DiskImgLib::PutShortBE(uint8_t* ptr, uint16_t val)
|
|
{
|
|
*ptr++ = val >> 8;
|
|
*ptr = (uint8_t) val;
|
|
}
|
|
|
|
void DiskImgLib::PutLongBE(uint8_t* ptr, uint32_t val)
|
|
{
|
|
*ptr++ = (uint8_t) (val >> 24);
|
|
*ptr++ = (uint8_t) (val >> 16);
|
|
*ptr++ = (uint8_t) (val >> 8);
|
|
*ptr = (uint8_t) val;
|
|
}
|
|
|
|
|
|
/*
|
|
* Read a two-byte little-endian value.
|
|
*/
|
|
DIError DiskImgLib::ReadShortLE(GenericFD* pGFD, uint16_t* pBuf)
|
|
{
|
|
DIError dierr;
|
|
uint8_t val[2];
|
|
|
|
dierr = pGFD->Read(&val[0], 1);
|
|
if (dierr == kDIErrNone)
|
|
dierr = pGFD->Read(&val[1], 1);
|
|
|
|
*pBuf = val[0] | (short) val[1] << 8;
|
|
return dierr;
|
|
}
|
|
|
|
/*
|
|
* Read a four-byte little-endian value.
|
|
*/
|
|
DIError DiskImgLib::ReadLongLE(GenericFD* pGFD, uint32_t* pBuf)
|
|
{
|
|
DIError dierr;
|
|
uint8_t val[4];
|
|
|
|
dierr = pGFD->Read(&val[0], 1);
|
|
if (dierr == kDIErrNone)
|
|
dierr = pGFD->Read(&val[1], 1);
|
|
if (dierr == kDIErrNone)
|
|
dierr = pGFD->Read(&val[2], 1);
|
|
if (dierr == kDIErrNone)
|
|
dierr = pGFD->Read(&val[3], 1);
|
|
|
|
*pBuf = val[0] | (uint32_t)val[1] << 8 |
|
|
(uint32_t)val[2] << 16 | (uint32_t)val[3] << 24;
|
|
return dierr;
|
|
}
|
|
|
|
/*
|
|
* Write a two-byte little-endian value.
|
|
*/
|
|
DIError DiskImgLib::WriteShortLE(FILE* fp, uint16_t val)
|
|
{
|
|
putc(val, fp);
|
|
putc(val >> 8, fp);
|
|
return kDIErrNone;
|
|
}
|
|
|
|
/*
|
|
* Write a four-byte little-endian value.
|
|
*/
|
|
DIError DiskImgLib::WriteLongLE(FILE* fp, uint32_t val)
|
|
{
|
|
putc(val, fp);
|
|
putc(val >> 8, fp);
|
|
putc(val >> 16, fp);
|
|
putc(val >> 24, fp);
|
|
return kDIErrNone;
|
|
}
|
|
|
|
/*
|
|
* Write a two-byte little-endian value.
|
|
*/
|
|
DIError DiskImgLib::WriteShortLE(GenericFD* pGFD, uint16_t val)
|
|
{
|
|
uint8_t buf;
|
|
|
|
buf = (uint8_t) val;
|
|
pGFD->Write(&buf, 1);
|
|
buf = val >> 8;
|
|
return pGFD->Write(&buf, 1);
|
|
}
|
|
|
|
/*
|
|
* Write a four-byte little-endian value.
|
|
*/
|
|
DIError DiskImgLib::WriteLongLE(GenericFD* pGFD, uint32_t val)
|
|
{
|
|
uint8_t buf;
|
|
|
|
buf = (uint8_t) val;
|
|
pGFD->Write(&buf, 1);
|
|
buf = (uint8_t) (val >> 8);
|
|
pGFD->Write(&buf, 1);
|
|
buf = (uint8_t) (val >> 16);
|
|
pGFD->Write(&buf, 1);
|
|
buf = (uint8_t) (val >> 24);
|
|
return pGFD->Write(&buf, 1);
|
|
}
|
|
|
|
/*
|
|
* Write a two-byte big-endian value.
|
|
*/
|
|
DIError DiskImgLib::WriteShortBE(GenericFD* pGFD, uint16_t val)
|
|
{
|
|
uint8_t buf;
|
|
|
|
buf = val >> 8;
|
|
pGFD->Write(&buf, 1);
|
|
buf = (uint8_t) val;
|
|
return pGFD->Write(&buf, 1);
|
|
}
|
|
|
|
/*
|
|
* Write a four-byte big-endian value.
|
|
*/
|
|
DIError DiskImgLib::WriteLongBE(GenericFD* pGFD, uint32_t val)
|
|
{
|
|
uint8_t buf;
|
|
|
|
buf = (uint8_t) (val >> 24);
|
|
pGFD->Write(&buf, 1);
|
|
buf = (uint8_t) (val >> 16);
|
|
pGFD->Write(&buf, 1);
|
|
buf = (uint8_t) (val >> 8);
|
|
pGFD->Write(&buf, 1);
|
|
buf = (uint8_t) val;
|
|
return pGFD->Write(&buf, 1);
|
|
}
|
|
|
|
|
|
/*
|
|
* Find the filename component of a local pathname. Uses the fssep passed
|
|
* in. If the fssep is '\0' (as is the case for DOS 3.3), then the entire
|
|
* pathname is returned.
|
|
*
|
|
* Always returns a pointer to a string; never returns NULL.
|
|
*/
|
|
const char* DiskImgLib::FilenameOnly(const char* pathname, char fssep)
|
|
{
|
|
const char* retstr;
|
|
const char* pSlash;
|
|
char* tmpStr = NULL;
|
|
|
|
assert(pathname != NULL);
|
|
if (fssep == '\0') {
|
|
retstr = pathname;
|
|
goto bail;
|
|
}
|
|
|
|
pSlash = strrchr(pathname, fssep);
|
|
if (pSlash == NULL) {
|
|
retstr = pathname; /* whole thing is the filename */
|
|
goto bail;
|
|
}
|
|
|
|
pSlash++;
|
|
if (*pSlash == '\0') {
|
|
if (strlen(pathname) < 2) {
|
|
retstr = pathname; /* the pathname is just "/"? Whatever */
|
|
goto bail;
|
|
}
|
|
|
|
/* some bonehead put an fssep on the very end; back up before it */
|
|
/* (not efficient, but this should be rare, and I'm feeling lazy) */
|
|
tmpStr = strdup(pathname);
|
|
tmpStr[strlen(pathname)-1] = '\0';
|
|
pSlash = strrchr(tmpStr, fssep);
|
|
|
|
if (pSlash == NULL) {
|
|
retstr = pathname; /* just a filename with a '/' after it */
|
|
goto bail;
|
|
}
|
|
|
|
pSlash++;
|
|
if (*pSlash == '\0') {
|
|
retstr = pathname; /* I give up! */
|
|
goto bail;
|
|
}
|
|
|
|
retstr = pathname + (pSlash - tmpStr);
|
|
|
|
} else {
|
|
retstr = pSlash;
|
|
}
|
|
|
|
bail:
|
|
free(tmpStr);
|
|
return retstr;
|
|
}
|
|
|
|
/*
|
|
* Return the filename extension found in a full pathname.
|
|
*
|
|
* An extension is the stuff following the last '.' in the filename. If
|
|
* there is nothing following the last '.', then there is no extension.
|
|
*
|
|
* Returns a pointer to the '.' preceding the extension, or NULL if no
|
|
* extension was found.
|
|
*
|
|
* We guarantee that there is at least one character after the '.'.
|
|
*/
|
|
const char* DiskImgLib::FindExtension(const char* pathname, char fssep)
|
|
{
|
|
const char* pFilename;
|
|
const char* pExt;
|
|
|
|
/*
|
|
* We have to isolate the filename so that we don't get excited
|
|
* about "/foo.bar/file".
|
|
*/
|
|
pFilename = FilenameOnly(pathname, fssep);
|
|
assert(pFilename != NULL);
|
|
pExt = strrchr(pFilename, kFilenameExtDelim);
|
|
|
|
/* also check for "/blah/foo.", which doesn't count */
|
|
if (pExt != NULL && *(pExt+1) != '\0')
|
|
return pExt;
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
* Like strcpy(), but allocate with new[] instead.
|
|
*
|
|
* If "str" is NULL, or "new" fails, this returns NULL.
|
|
*
|
|
* TODO: should be "StrdupNew()"
|
|
*/
|
|
char* DiskImgLib::StrcpyNew(const char* str)
|
|
{
|
|
char* newStr;
|
|
|
|
if (str == NULL)
|
|
return NULL;
|
|
newStr = new char[strlen(str)+1];
|
|
if (newStr != NULL)
|
|
strcpy(newStr, str);
|
|
return newStr;
|
|
}
|
|
|
|
|
|
#ifdef _WIN32
|
|
/*
|
|
* Convert the value from GetLastError() to its DIError counterpart.
|
|
*/
|
|
DIError DiskImgLib::LastErrorToDIError(void)
|
|
{
|
|
DWORD lastErr = ::GetLastError();
|
|
|
|
switch (lastErr) {
|
|
case ERROR_FILE_NOT_FOUND: return kDIErrFileNotFound; // 2
|
|
case ERROR_ACCESS_DENIED: return kDIErrAccessDenied; // 5
|
|
case ERROR_WRITE_PROTECT: return kDIErrWriteProtected; // 19
|
|
case ERROR_SECTOR_NOT_FOUND: return kDIErrGeneric; // 27
|
|
case ERROR_SHARING_VIOLATION: return kDIErrSharingViolation; // 32
|
|
case ERROR_HANDLE_EOF: return kDIErrEOF; // 38
|
|
case ERROR_INVALID_PARAMETER: return kDIErrInvalidArg; // 87
|
|
case ERROR_SEM_TIMEOUT: return kDIErrGenericIO; // 121
|
|
// ERROR_SEM_TIMEOUT seen read bad blocks from floptical under Win2K
|
|
|
|
case ERROR_INVALID_HANDLE: // 6
|
|
LOGI("HEY: got ERROR_INVALID_HANDLE!");
|
|
return kDIErrInternal;
|
|
case ERROR_NEGATIVE_SEEK: // 131
|
|
LOGI("HEY: got ERROR_NEGATIVE_SEEK!");
|
|
return kDIErrInternal;
|
|
default:
|
|
LOGI("LastErrorToDIError: not converting 0x%08lx (%ld)",
|
|
lastErr, lastErr);
|
|
return kDIErrGeneric;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Returns "true" if we're running on Win9x (Win95, Win98, WinME), "false"
|
|
* if not (could be WinNT/2K/XP or even Win31 with Win32s).
|
|
*/
|
|
bool DiskImgLib::IsWin9x(void)
|
|
{
|
|
OSVERSIONINFO osvers;
|
|
BOOL result;
|
|
|
|
osvers.dwOSVersionInfoSize = sizeof(osvers);
|
|
result = ::GetVersionEx(&osvers);
|
|
assert(result != FALSE);
|
|
|
|
if (osvers.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS)
|
|
return true;
|
|
else
|
|
return false;
|
|
}
|
|
#endif
|