Fix copy & paste

Some of the code was mis-handling wide character filenames.

A direct copy & paste should be using the 8-bit form of the filename,
but that's a deeper fix.

Also, changed some types to use explicit integer width specifiers.
This commit is contained in:
Andy McFadden 2014-12-10 17:10:13 -08:00
parent be8d3a4911
commit a5fa12b332
3 changed files with 69 additions and 55 deletions

View File

@ -17,7 +17,8 @@
* "Open" and "Save As" dialogs do, because those want to choose normal files * "Open" and "Save As" dialogs do, because those want to choose normal files
* only, while this wants to select a folder. * only, while this wants to select a folder.
* *
* TODO: Vista-style dialogs support folder selection. * TODO: Vista-style dialogs support folder selection. Consider switching
* based on OS version.
*/ */
class ChooseDirDialog : public CDialog { class ChooseDirDialog : public CDialog {
public: public:

View File

@ -12,9 +12,9 @@
#include "PasteSpecialDialog.h" #include "PasteSpecialDialog.h"
static const WCHAR kClipboardFmtName[] = L"faddenSoft:CiderPress:v1"; static const WCHAR kClipboardFmtName[] = L"faddenSoft:CiderPress:v2";
const int kClipVersion = 1; // should match "vN" in fmt name const int kClipVersion = 2; // should match "vN" in fmt name
const unsigned short kEntrySignature = 0x4350; const uint16_t kEntrySignature = 0x4350;
/* /*
* Win98 is quietly dying on large (20MB-ish) copies. Everything * Win98 is quietly dying on large (20MB-ish) copies. Everything
@ -48,10 +48,10 @@ const int kClipTextMult = 4; // CF_OEMTEXT, CF_LOCALE, CF_UNICODETEXT*2
* File collection header. * File collection header.
*/ */
typedef struct FileCollection { typedef struct FileCollection {
unsigned short version; // currently 1 uint16_t version; // currently 1
unsigned short dataOffset; // offset to start of data uint16_t dataOffset; // offset to start of data
unsigned long length; // total length; uint32_t length; // total length;
unsigned long count; // #of entries uint32_t count; // #of entries
} FileCollection; } FileCollection;
/* what kind of entry is this */ /* what kind of entry is this */
@ -68,24 +68,27 @@ typedef enum EntryKind {
* One of these per entry in the collection. * One of these per entry in the collection.
* *
* The next file starts at (start + dataOffset + dataLen + rsrcLen + cmmtLen). * The next file starts at (start + dataOffset + dataLen + rsrcLen + cmmtLen).
*
* TODO: filename should be 8-bit from original, not 16-bit conversion
*/ */
typedef struct FileCollectionEntry { typedef struct FileCollectionEntry {
unsigned short signature; // let's be paranoid uint16_t signature; // let's be paranoid
unsigned short dataOffset; // offset to start of data uint16_t dataOffset; // offset to start of data
unsigned short fileNameLen; // len of (8-bit) filename, in bytes uint16_t fileNameLen; // len of filename, in bytes
unsigned long dataLen; // len of data fork uint32_t dataLen; // len of data fork
unsigned long rsrcLen; // len of rsrc fork uint32_t rsrcLen; // len of rsrc fork
unsigned long cmmtLen; // len of comments uint32_t cmmtLen; // len of comments
unsigned long fileType; uint32_t fileType;
unsigned long auxType; uint32_t auxType;
time_t createWhen; int64_t createWhen; // time_t
time_t modWhen; int64_t modWhen; // time_t
unsigned char access; // ProDOS access flags uint8_t access; // ProDOS access flags
unsigned char entryKind; // GenericArchive::FileDetails::FileKind uint8_t entryKind; // GenericArchive::FileDetails::FileKind
unsigned char sourceFS; // DiskImgLib::DiskImg::FSFormat uint8_t sourceFS; // DiskImgLib::DiskImg::FSFormat
unsigned char fssep; // filesystem separator char, e.g. ':' uint8_t fssep; // filesystem separator char, e.g. ':'
/* data comes next: filename, then data, then resource, then comment */ /* data comes next: null-terminated WCHAR filename, then data fork, then
resource fork, then comment */
} FileCollectionEntry; } FileCollectionEntry;
@ -103,7 +106,7 @@ void MainWindow::OnEditCopy(void)
bool isOpen = false; bool isOpen = false;
HGLOBAL hGlobal; HGLOBAL hGlobal;
LPVOID pGlobal; LPVOID pGlobal;
unsigned char* buf = NULL; uint8_t* buf = NULL;
long bufLen = -1; long bufLen = -1;
/* associate a number with the format name */ /* associate a number with the format name */
@ -289,7 +292,7 @@ HGLOBAL MainWindow::CreateFileCollection(SelectionSet* pSelSet)
if (pEntry->GetRecordKind() != GenericEntry::kRecordKindVolumeDir) { if (pEntry->GetRecordKind() != GenericEntry::kRecordKindVolumeDir) {
totalLength += sizeof(FileCollectionEntry); totalLength += sizeof(FileCollectionEntry);
totalLength += wcslen(pEntry->GetPathName()) +1; totalLength += (wcslen(pEntry->GetPathName()) +1) * sizeof(WCHAR);
numFiles++; numFiles++;
if (pEntry->GetRecordKind() != GenericEntry::kRecordKindDirectory) { if (pEntry->GetRecordKind() != GenericEntry::kRecordKindDirectory) {
totalLength += (long) pEntry->GetDataForkLen(); totalLength += (long) pEntry->GetDataForkLen();
@ -361,7 +364,7 @@ HGLOBAL MainWindow::CreateFileCollection(SelectionSet* pSelSet)
void* buf; void* buf;
remainingLen = totalLength - sizeof(FileCollection); remainingLen = totalLength - sizeof(FileCollection);
buf = (unsigned char*) pGlobal + sizeof(FileCollection); buf = (uint8_t*) pGlobal + sizeof(FileCollection);
pSelSet->IterReset(); pSelSet->IterReset();
pSelEntry = pSelSet->IterNext(); pSelEntry = pSelSet->IterNext();
while (pSelEntry != NULL) { while (pSelEntry != NULL) {
@ -384,7 +387,7 @@ HGLOBAL MainWindow::CreateFileCollection(SelectionSet* pSelSet)
} }
ASSERT(remainingLen == 0); ASSERT(remainingLen == 0);
ASSERT(buf == (unsigned char*) pGlobal + totalLength); ASSERT(buf == (uint8_t*) pGlobal + totalLength);
/* /*
* Write the header. * Write the header.
@ -421,8 +424,8 @@ CString MainWindow::CopyToCollection(GenericEntry* pEntry, void** pBuf,
long* pBufLen) long* pBufLen)
{ {
FileCollectionEntry collEnt; FileCollectionEntry collEnt;
CString errStr, dummyStr; CString errStr;
unsigned char* buf = (unsigned char*) *pBuf; uint8_t* buf = (uint8_t*) *pBuf;
long remLen = *pBufLen; long remLen = *pBufLen;
errStr.LoadString(IDS_CLIPBOARD_WRITEFAILURE); errStr.LoadString(IDS_CLIPBOARD_WRITEFAILURE);
@ -457,25 +460,25 @@ CString MainWindow::CopyToCollection(GenericEntry* pEntry, void** pBuf,
memset(&collEnt, 0x99, sizeof(collEnt)); memset(&collEnt, 0x99, sizeof(collEnt));
collEnt.signature = kEntrySignature; collEnt.signature = kEntrySignature;
collEnt.dataOffset = sizeof(collEnt); collEnt.dataOffset = sizeof(collEnt);
collEnt.fileNameLen = wcslen(pEntry->GetPathName()) +1; collEnt.fileNameLen = (wcslen(pEntry->GetPathName()) +1) * sizeof(WCHAR);
if (pEntry->GetRecordKind() == GenericEntry::kRecordKindDirectory) { if (pEntry->GetRecordKind() == GenericEntry::kRecordKindDirectory) {
collEnt.dataLen = collEnt.rsrcLen = collEnt.cmmtLen = 0; collEnt.dataLen = collEnt.rsrcLen = collEnt.cmmtLen = 0;
} else { } else {
collEnt.dataLen = (unsigned long) pEntry->GetDataForkLen(); collEnt.dataLen = (uint32_t) pEntry->GetDataForkLen();
collEnt.rsrcLen = (unsigned long) pEntry->GetRsrcForkLen(); collEnt.rsrcLen = (uint32_t) pEntry->GetRsrcForkLen();
collEnt.cmmtLen = 0; // CMMT FIX -- length unknown?? collEnt.cmmtLen = 0; // CMMT FIX -- length unknown??
} }
collEnt.fileType = pEntry->GetFileType(); collEnt.fileType = pEntry->GetFileType();
collEnt.auxType = pEntry->GetAuxType(); collEnt.auxType = pEntry->GetAuxType();
collEnt.createWhen = pEntry->GetCreateWhen(); collEnt.createWhen = pEntry->GetCreateWhen();
collEnt.modWhen = pEntry->GetModWhen(); collEnt.modWhen = pEntry->GetModWhen();
collEnt.access = (unsigned char) pEntry->GetAccess(); collEnt.access = (uint8_t) pEntry->GetAccess();
collEnt.entryKind = (unsigned char) entryKind; collEnt.entryKind = (uint8_t) entryKind;
collEnt.sourceFS = pEntry->GetSourceFS(); collEnt.sourceFS = pEntry->GetSourceFS();
collEnt.fssep = pEntry->GetFssep(); collEnt.fssep = pEntry->GetFssep();
/* verify there's enough space to hold everything */ /* verify there's enough space to hold everything */
if ((unsigned long) remLen < collEnt.fileNameLen + if ((uint32_t) remLen < collEnt.fileNameLen +
collEnt.dataLen + collEnt.rsrcLen + collEnt.cmmtLen) collEnt.dataLen + collEnt.rsrcLen + collEnt.cmmtLen)
{ {
ASSERT(false); ASSERT(false);
@ -511,13 +514,15 @@ CString MainWindow::CopyToCollection(GenericEntry* pEntry, void** pBuf,
else else
which = GenericEntry::kDataThread; which = GenericEntry::kDataThread;
CString extractErrStr;
result = pEntry->ExtractThreadToBuffer(which, &bufCopy, &lenCopy, result = pEntry->ExtractThreadToBuffer(which, &bufCopy, &lenCopy,
&dummyStr); &extractErrStr);
if (result == IDCANCEL) { if (result == IDCANCEL) {
errStr.LoadString(IDS_CANCELLED); errStr.LoadString(IDS_CANCELLED);
return errStr; return errStr;
} else if (result != IDOK) { } else if (result != IDOK) {
LOGI("ExtractThreadToBuffer (data) failed"); LOGW("ExtractThreadToBuffer (data) failed: %ls",
(LPCWSTR) extractErrStr);
return errStr; return errStr;
} }
@ -533,13 +538,15 @@ CString MainWindow::CopyToCollection(GenericEntry* pEntry, void** pBuf,
lenCopy = remLen; lenCopy = remLen;
which = GenericEntry::kRsrcThread; which = GenericEntry::kRsrcThread;
CString extractErrStr;
result = pEntry->ExtractThreadToBuffer(which, &bufCopy, &lenCopy, result = pEntry->ExtractThreadToBuffer(which, &bufCopy, &lenCopy,
&dummyStr); &extractErrStr);
if (result == IDCANCEL) { if (result == IDCANCEL) {
errStr.LoadString(IDS_CANCELLED); errStr.LoadString(IDS_CANCELLED);
return errStr; return errStr;
} else if (result != IDOK) { } else if (result != IDOK) {
LOGI("ExtractThreadToBuffer (rsrc) failed"); LOGI("ExtractThreadToBuffer (rsrc) failed: %ls",
(LPCWSTR) extractErrStr);
return errStr; return errStr;
} }
@ -717,7 +724,7 @@ CString MainWindow::ProcessClipboard(const void* vbuf, long bufLen,
{ {
FileCollection fileColl; FileCollection fileColl;
CString errMsg, storagePrefix; CString errMsg, storagePrefix;
const unsigned char* buf = (const unsigned char*) vbuf; const uint8_t* buf = (const uint8_t*) vbuf;
DiskImgLib::A2File* pTargetSubdir = NULL; DiskImgLib::A2File* pTargetSubdir = NULL;
XferFileOptions xferOpts; XferFileOptions xferOpts;
bool xferPrepped = false; bool xferPrepped = false;
@ -729,7 +736,7 @@ CString MainWindow::ProcessClipboard(const void* vbuf, long bufLen,
* Pull the header out. * Pull the header out.
*/ */
if (bufLen < sizeof(fileColl)) { if (bufLen < sizeof(fileColl)) {
LOGI("Clipboard contents too small!"); LOGW("Clipboard contents too small!");
goto bail; goto bail;
} }
memcpy(&fileColl, buf, sizeof(fileColl)); memcpy(&fileColl, buf, sizeof(fileColl));
@ -739,7 +746,7 @@ CString MainWindow::ProcessClipboard(const void* vbuf, long bufLen,
* boundaries, which screws up our "bufLen > 0" while condition below. * boundaries, which screws up our "bufLen > 0" while condition below.
*/ */
if ((long) fileColl.length > bufLen) { if ((long) fileColl.length > bufLen) {
LOGI("GLITCH: stored len=%ld, clip len=%ld", LOGW("GLITCH: stored len=%ld, clip len=%ld",
fileColl.length, bufLen); fileColl.length, bufLen);
goto bail; goto bail;
} }
@ -778,7 +785,7 @@ CString MainWindow::ProcessClipboard(const void* vbuf, long bufLen,
if (pTargetSubdir != NULL) { if (pTargetSubdir != NULL) {
storagePrefix = pTargetSubdir->GetPathName(); storagePrefix = pTargetSubdir->GetPathName();
LOGI("--- using storagePrefix '%ls'", (LPCWSTR) storagePrefix); LOGD("--- using storagePrefix '%ls'", (LPCWSTR) storagePrefix);
} }
/* /*
@ -795,11 +802,12 @@ CString MainWindow::ProcessClipboard(const void* vbuf, long bufLen,
LOGI("+++ Starting paste, bufLen=%ld", bufLen); LOGI("+++ Starting paste, bufLen=%ld", bufLen);
while (bufLen > 0) { while (bufLen > 0) {
FileCollectionEntry collEnt; FileCollectionEntry collEnt;
CString fileName, processErrStr; CString fileName;
CString processErrStr;
/* read the entry info */ /* read the entry info */
if (bufLen < sizeof(collEnt)) { if (bufLen < sizeof(collEnt)) {
LOGI("GLITCH: bufLen=%ld, sizeof(collEnt)=%d", LOGW("GLITCH: bufLen=%ld, sizeof(collEnt)=%d",
bufLen, sizeof(collEnt)); bufLen, sizeof(collEnt));
ASSERT(false); ASSERT(false);
goto bail; goto bail;
@ -823,14 +831,15 @@ CString MainWindow::ProcessClipboard(const void* vbuf, long bufLen,
ASSERT(false); ASSERT(false);
goto bail; goto bail;
} }
fileName = buf; // TODO: consider moving filename as raw 8-bit data
fileName = (const WCHAR*) buf;
buf += collEnt.fileNameLen; buf += collEnt.fileNameLen;
bufLen -= collEnt.fileNameLen; bufLen -= collEnt.fileNameLen;
//LOGI("+++ pasting '%s'", fileName); LOGD("+++ pasting '%ls'", (LPCWSTR) fileName);
/* strip the path (if requested) and prepend the storage prefix */ /* strip the path (if requested) and prepend the storage prefix */
ASSERT(fileName.GetLength() == collEnt.fileNameLen -1); ASSERT((fileName.GetLength() +1 ) * sizeof(WCHAR) == collEnt.fileNameLen);
if (pasteJunkPaths && collEnt.fssep != '\0') { if (pasteJunkPaths && collEnt.fssep != '\0') {
int idx; int idx;
idx = fileName.ReverseFind(collEnt.fssep); idx = fileName.ReverseFind(collEnt.fssep);
@ -905,8 +914,8 @@ CString MainWindow::ProcessClipboardEntry(const FileCollectionEntry* pCollEnt,
{ {
GenericArchive::FileDetails::FileKind entryKind; GenericArchive::FileDetails::FileKind entryKind;
GenericArchive::FileDetails details; GenericArchive::FileDetails details;
unsigned char* dataBuf = NULL; uint8_t* dataBuf = NULL;
unsigned char* rsrcBuf = NULL; uint8_t* rsrcBuf = NULL;
long dataLen, rsrcLen, cmmtLen; long dataLen, rsrcLen, cmmtLen;
CString errMsg; CString errMsg;
@ -915,7 +924,7 @@ CString MainWindow::ProcessClipboardEntry(const FileCollectionEntry* pCollEnt,
details.entryKind = entryKind; details.entryKind = entryKind;
details.origName = L"Clipboard"; details.origName = L"Clipboard";
details.storageName = pathName; details.storageName = pathName; // TODO MacRoman convert
details.fileSysFmt = (DiskImg::FSFormat) pCollEnt->sourceFS; details.fileSysFmt = (DiskImg::FSFormat) pCollEnt->sourceFS;
details.fileSysInfo = pCollEnt->fssep; details.fileSysInfo = pCollEnt->fssep;
details.access = pCollEnt->access; details.access = pCollEnt->access;
@ -970,11 +979,11 @@ CString MainWindow::ProcessClipboardEntry(const FileCollectionEntry* pCollEnt,
if (hasData) { if (hasData) {
if (pCollEnt->dataLen == 0) { if (pCollEnt->dataLen == 0) {
dataBuf = new unsigned char[1]; dataBuf = new uint8_t[1];
dataLen = 0; dataLen = 0;
} else { } else {
dataLen = pCollEnt->dataLen; dataLen = pCollEnt->dataLen;
dataBuf = new unsigned char[dataLen]; dataBuf = new uint8_t[dataLen];
if (dataBuf == NULL) if (dataBuf == NULL)
return "memory allocation failed."; return "memory allocation failed.";
memcpy(dataBuf, buf, dataLen); memcpy(dataBuf, buf, dataLen);
@ -988,11 +997,11 @@ CString MainWindow::ProcessClipboardEntry(const FileCollectionEntry* pCollEnt,
if (hasRsrc) { if (hasRsrc) {
if (pCollEnt->rsrcLen == 0) { if (pCollEnt->rsrcLen == 0) {
rsrcBuf = new unsigned char[1]; rsrcBuf = new uint8_t[1];
rsrcLen = 0; rsrcLen = 0;
} else { } else {
rsrcLen = pCollEnt->rsrcLen; rsrcLen = pCollEnt->rsrcLen;
rsrcBuf = new unsigned char[rsrcLen]; rsrcBuf = new uint8_t[rsrcLen];
if (rsrcBuf == NULL) if (rsrcBuf == NULL)
return "Memory allocation failed."; return "Memory allocation failed.";
memcpy(rsrcBuf, buf, rsrcLen); memcpy(rsrcBuf, buf, rsrcLen);

View File

@ -520,6 +520,10 @@ public:
* *
* It's based on the NuFileDetails class from NufxLib (which used to be * It's based on the NuFileDetails class from NufxLib (which used to be
* used everywhere). * used everywhere).
*
* TODO: fix this
* TODO: may want to hold a raw 8-bit pathname for copy & paste, which
* doesn't need to convert in and out of MacRoman
*/ */
class FileDetails { class FileDetails {
public: public: