ciderpress/diskimg/DIUtil.cpp
Andy McFadden d8223dbcfd Relocate method comments
This moves method comments from the .cpp file to the .h file,
where users of the methods can find them.  This also makes it
possible for the IDE to show the comments when you mouse-hover over
the method name, though Visual Studio is a bit weak in this regard.

Also, added "override" keywords on overridden methods.  Reasonably
current versions of popular compilers seem to support this.

Also, don't have the return type on a separate line in the .cpp file.
The motivation for the practice -- quickly finding a method definition
with "^name" -- is less useful in C++ than C, and modern IDEs provide
more convenient ways to do the same thing.

Also, do some more conversion from unsigned types to uintXX_t.

This commit is primarily for the "app" directory.
2014-11-21 22:33:39 -08:00

372 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)
{
unsigned char 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)
{
unsigned char 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)
{
unsigned char buf;
buf = (unsigned char) (val >> 24);
pGFD->Write(&buf, 1);
buf = (unsigned char) (val >> 16);
pGFD->Write(&buf, 1);
buf = (unsigned char) (val >> 8);
pGFD->Write(&buf, 1);
buf = (unsigned char) 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