/* * CiderPress * Copyright (C) 2007, 2008 by faddenSoft, LLC. All Rights Reserved. * See the file LICENSE for distribution terms. */ /* * Save and restore preferences from the config file. */ #include "stdafx.h" #include "Preferences.h" #include "NufxArchive.h" #include "MyApp.h" #include "../util/UtilLib.h" static const char* kDefaultTempPath = "."; /* registry section for columns */ static const WCHAR kColumnSect[] = L"columns"; /* registry section for file add options */ static const WCHAR kAddSect[] = L"add"; /* registry section for extraction options */ static const WCHAR kExtractSect[] = L"extract"; /* registry section for view options */ static const WCHAR kViewSect[] = L"view"; /* registry section for logical/physical volume operations */ static const WCHAR kVolumeSect[] = L"volume"; /* registry section for file-to-disk options */ //static const WCHAR kConvDiskSect[] = L"conv-disk"; /* registry section for disk-to-file options */ static const WCHAR kConvFileSect[] = L"conv-file"; /* registry section for folders */ static const WCHAR kFolderSect[] = L"folders"; /* registry section for preferences on property pages */ static const WCHAR kPrefsSect[] = L"prefs"; /* registry section for miscellaneous settings */ static const WCHAR kMiscSect[] = L"misc"; /* * Map PrefNum to type and registry string. * * To make life easier, we require that the PrefNum (first entry) match the * offset in the table. That way instead of searching for a match we can just * index into the table. */ const Preferences::PrefMap Preferences::fPrefMaps[kPrefNumLastEntry] = { /**/ { kPrefNumUnknown, kPTNone, nil, nil }, { kPrAddIncludeSubFolders, kBool, kAddSect, L"include-sub-folders" }, { kPrAddStripFolderNames, kBool, kAddSect, L"strip-folder-names" }, { kPrAddOverwriteExisting, kBool, kAddSect, L"overwrite-existing" }, { kPrAddTypePreservation, kLong, kAddSect, L"type-preservation" }, { kPrAddConvEOL, kLong, kAddSect, L"conv-eol" }, // { kPrExtractPath, kString, kExtractSect, L"path" }, { kPrExtractConvEOL, kLong, kExtractSect, L"conv-eol" }, { kPrExtractConvHighASCII, kBool, kExtractSect, L"conv-high-ascii" }, { kPrExtractIncludeData, kBool, kExtractSect, L"include-data" }, { kPrExtractIncludeRsrc, kBool, kExtractSect, L"include-rsrc" }, { kPrExtractIncludeDisk, kBool, kExtractSect, L"include-disk" }, { kPrExtractEnableReformat, kBool, kExtractSect, L"enable-reformat" }, { kPrExtractDiskTo2MG, kBool, kExtractSect, L"disk-to-2mg" }, { kPrExtractAddTypePreservation, kBool, kExtractSect, L"add-type-preservation" }, { kPrExtractAddExtension, kBool, kExtractSect, L"add-extension" }, { kPrExtractStripFolderNames, kBool, kExtractSect, L"strip-folder-names" }, { kPrExtractOverwriteExisting, kBool, kExtractSect, L"overwrite-existing" }, // { kPrViewIncludeDataForks, kBool, kViewSect, L"include-data-forks" }, // { kPrViewIncludeRsrcForks, kBool, kViewSect, L"include-rsrc-forks" }, // { kPrViewIncludeDiskImages, kBool, kViewSect, L"include-disk-images" }, // { kPrViewIncludeComments, kBool, kViewSect, L"include-comments" }, { kPrConvFileEmptyFolders, kBool, kConvFileSect, L"preserve-empty-folders" }, { kPrOpenArchiveFolder, kString, kFolderSect, L"open-archive" }, { kPrConvertArchiveFolder, kString, kFolderSect, L"convert-archive" }, { kPrAddFileFolder, kString, kFolderSect, L"add-file" }, { kPrExtractFileFolder, kString, kFolderSect, L"extract-file" }, { kPrVolumeFilter, kLong, kVolumeSect, L"open-filter" }, //{ kPrVolumeReadOnly, kBool, kVolumeSect, L"read-only" }, { kPrCassetteAlgorithm, kLong, kVolumeSect, L"cassette-algorithm" }, { kPrOpenWAVFolder, kString, kFolderSect, L"open-wav" }, { kPrMimicShrinkIt, kBool, kPrefsSect, L"mimic-shrinkit" }, { kPrBadMacSHK, kBool, kPrefsSect, L"bad-mac-shk" }, { kPrReduceSHKErrorChecks, kBool, kPrefsSect, L"reduce-shk-error-checks" }, { kPrCoerceDOSFilenames, kBool, kPrefsSect, L"coerce-dos-filenames" }, { kPrSpacesToUnder, kBool, kPrefsSect, L"spaces-to-under" }, { kPrPasteJunkPaths, kBool, kPrefsSect, L"paste-junk-paths" }, { kPrBeepOnSuccess, kBool, kPrefsSect, L"beep-on-success" }, { kPrQueryImageFormat, kBool, kPrefsSect, L"query-image-format" }, { kPrOpenVolumeRO, kBool, kPrefsSect, L"open-volume-ro" }, { kPrOpenVolumePhys0, kBool, kPrefsSect, L"open-volume-phys0" }, { kPrProDOSAllowLower, kBool, kPrefsSect, L"prodos-allow-lower" }, { kPrProDOSUseSparse, kBool, kPrefsSect, L"prodos-use-sparse" }, { kPrCompressionType, kLong, kPrefsSect, L"compression-type" }, { kPrMaxViewFileSize, kLong, kPrefsSect, L"max-view-file-size" }, { kPrNoWrapText, kBool, kPrefsSect, L"no-wrap-text" }, { kPrHighlightHexDump, kBool, kPrefsSect, L"highlight-hex-dump" }, { kPrHighlightBASIC, kBool, kPrefsSect, L"highlight-basic" }, { kPrConvHiResBlackWhite, kBool, kPrefsSect, L"conv-hi-res-black-white" }, { kPrConvDHRAlgorithm, kLong, kPrefsSect, L"dhr-algorithm" }, { kPrRelaxGfxTypeCheck, kBool, kPrefsSect, L"relax-gfx-type-check" }, { kPrDisasmOneByteBrkCop, kBool, kPrefsSect, L"disasm-onebytebrkcop" }, //{ kPrEOLConvRaw, kBool, kPrefsSect, L"eol-conv-raw" }, { kPrConvTextEOL_HA, kBool, kPrefsSect, L"conv-eol-ha" }, { kPrConvPascalText, kBool, kPrefsSect, L"conv-pascal-text" }, { kPrConvPascalCode, kBool, kPrefsSect, L"conv-pascal-code" }, { kPrConvCPMText, kBool, kPrefsSect, L"conv-cpm-text" }, { kPrConvApplesoft, kBool, kPrefsSect, L"conv-applesoft" }, { kPrConvInteger, kBool, kPrefsSect, L"conv-integer" }, { kPrConvBusiness, kBool, kPrefsSect, L"conv-business" }, { kPrConvGWP, kBool, kPrefsSect, L"conv-gwp" }, { kPrConvText8, kBool, kPrefsSect, L"conv-text8" }, { kPrConvGutenberg, kBool, kPrefsSect, L"conv-gutenberg" }, { kPrConvAWP, kBool, kPrefsSect, L"conv-awp" }, { kPrConvADB, kBool, kPrefsSect, L"conv-adb" }, { kPrConvASP, kBool, kPrefsSect, L"conv-asp" }, { kPrConvSCAssem, kBool, kPrefsSect, L"conv-scassem" }, { kPrConvDisasm, kBool, kPrefsSect, L"conv-disasm" }, { kPrConvHiRes, kBool, kPrefsSect, L"conv-hi-res" }, { kPrConvDHR, kBool, kPrefsSect, L"conv-dhr" }, { kPrConvSHR, kBool, kPrefsSect, L"conv-shr" }, { kPrConvPrintShop, kBool, kPrefsSect, L"conv-print-shop" }, { kPrConvMacPaint, kBool, kPrefsSect, L"conv-mac-paint" }, { kPrConvProDOSFolder, kBool, kPrefsSect, L"conv-prodos-folder" }, { kPrConvResources, kBool, kPrefsSect, L"conv-resources" }, { kPrTempPath, kString, kPrefsSect, L"temp-path" }, { kPrExtViewerExts, kString, kPrefsSect, L"extviewer-exts" }, { kPrLastOpenFilterIndex, kLong, kMiscSect, L"open-filter-index" }, /**/ { kPrefNumLastRegistry, kPTNone, nil, nil }, { kPrViewTextTypeFace, kString, nil, nil }, { kPrViewTextPointSize, kLong, nil, nil }, { kPrFileViewerWidth, kLong, nil, nil }, { kPrFileViewerHeight, kLong, nil, nil }, { kPrDiskImageCreateFormat, kLong, nil, nil }, }; /* * Constructor. There should be only one Preferences object in the * application, so this should only be run once. */ Preferences::Preferences(void) { WMSG0("Initializing Preferences\n"); ScanPrefMaps(); // sanity-check the table memset(fValues, 0, sizeof(fValues)); SetPrefBool(kPrAddIncludeSubFolders, true); SetPrefBool(kPrAddStripFolderNames, false); SetPrefBool(kPrAddOverwriteExisting, false); SetPrefLong(kPrAddTypePreservation, 1); // kPreserveTypes SetPrefLong(kPrAddConvEOL, 1); // kConvEOLType InitFolders(); // set default add/extract folders; overriden by reg SetPrefLong(kPrExtractConvEOL, 0); // kConvEOLNone SetPrefBool(kPrExtractConvHighASCII, true); SetPrefBool(kPrExtractIncludeData, true); SetPrefBool(kPrExtractIncludeRsrc, false); SetPrefBool(kPrExtractIncludeDisk, true); SetPrefBool(kPrExtractEnableReformat, false); SetPrefBool(kPrExtractDiskTo2MG, false); SetPrefBool(kPrExtractAddTypePreservation, true); SetPrefBool(kPrExtractAddExtension, false); SetPrefBool(kPrExtractStripFolderNames, false); SetPrefBool(kPrExtractOverwriteExisting, false); // SetPrefBool(kPrViewIncludeDataForks, true); // SetPrefBool(kPrViewIncludeRsrcForks, false); // SetPrefBool(kPrViewIncludeDiskImages, false); // SetPrefBool(kPrViewIncludeComments, false); SetPrefBool(kPrConvFileEmptyFolders, true); // string kPrOpenArchiveFolder // string kPrAddFileFolder // string kPrExtractFileFolder SetPrefLong(kPrVolumeFilter, 0); //SetPrefBool(kPrVolumeReadOnly, true); SetPrefLong(kPrCassetteAlgorithm, 0); // string kPrOpenWAVFolder SetPrefBool(kPrMimicShrinkIt, false); SetPrefBool(kPrBadMacSHK, false); SetPrefBool(kPrReduceSHKErrorChecks, false); SetPrefBool(kPrCoerceDOSFilenames, false); SetPrefBool(kPrSpacesToUnder, false); SetPrefBool(kPrPasteJunkPaths, true); SetPrefBool(kPrBeepOnSuccess, true); SetPrefBool(kPrQueryImageFormat, false); SetPrefBool(kPrOpenVolumeRO, true); SetPrefBool(kPrOpenVolumePhys0, false); SetPrefBool(kPrProDOSAllowLower, false); SetPrefBool(kPrProDOSUseSparse, true); SetPrefLong(kPrCompressionType, DefaultCompressionType()); SetPrefLong(kPrMaxViewFileSize, 1024*1024); // 1MB SetPrefBool(kPrNoWrapText, false); SetPrefBool(kPrHighlightHexDump, false); SetPrefBool(kPrHighlightBASIC, false); SetPrefBool(kPrConvHiResBlackWhite, false); SetPrefLong(kPrConvDHRAlgorithm, 1); // latched SetPrefBool(kPrRelaxGfxTypeCheck, true); SetPrefBool(kPrDisasmOneByteBrkCop, false); //SetPrefBool(kPrEOLConvRaw, true); SetPrefBool(kPrConvTextEOL_HA, true); SetPrefBool(kPrConvPascalText, true); SetPrefBool(kPrConvPascalCode, true); SetPrefBool(kPrConvCPMText, true); SetPrefBool(kPrConvApplesoft, true); SetPrefBool(kPrConvInteger, true); SetPrefBool(kPrConvBusiness, true); SetPrefBool(kPrConvGWP, true); SetPrefBool(kPrConvText8, true); SetPrefBool(kPrConvGutenberg, true); SetPrefBool(kPrConvAWP, true); SetPrefBool(kPrConvADB, true); SetPrefBool(kPrConvASP, true); SetPrefBool(kPrConvSCAssem, true); SetPrefBool(kPrConvDisasm, true); SetPrefBool(kPrConvHiRes, true); SetPrefBool(kPrConvDHR, true); SetPrefBool(kPrConvSHR, true); SetPrefBool(kPrConvPrintShop, true); SetPrefBool(kPrConvMacPaint, true); SetPrefBool(kPrConvProDOSFolder, true); SetPrefBool(kPrConvResources, true); InitTempPath(); // set default for kPrTempPath SetPrefString(kPrExtViewerExts, L"gif; jpg; jpeg"); SetPrefLong(kPrLastOpenFilterIndex, 0); SetPrefString(kPrViewTextTypeFace, L"Courier New"); SetPrefLong(kPrViewTextPointSize, 10); long width = 680; /* exact width for 80-column text */ long height = 510; /* exact height for file viewer to show IIgs graphic */ if (GetSystemMetrics(SM_CXSCREEN) < width) width = GetSystemMetrics(SM_CXSCREEN); if (GetSystemMetrics(SM_CYSCREEN) < height) height = GetSystemMetrics(SM_CYSCREEN); // may overlap system bar //width = 640; height = 480; SetPrefLong(kPrFileViewerWidth, width); SetPrefLong(kPrFileViewerHeight, height); SetPrefLong(kPrDiskImageCreateFormat, -1); } /* * ========================================================================== * ColumnLayout * ========================================================================== */ /* * Restore column widths. */ void ColumnLayout::LoadFromRegistry(const WCHAR* section) { WCHAR numBuf[8]; int i; for (i = 0; i < kNumVisibleColumns; i++) { wsprintf(numBuf, L"%d", i); fColumnWidth[i] = gMyApp.GetProfileInt(section, numBuf, fColumnWidth[i]); fColumnWidth[i] = gMyApp.GetProfileInt(section, numBuf, fColumnWidth[i]); } fSortColumn = gMyApp.GetProfileInt(section, L"sort-column", fSortColumn); fAscending = (gMyApp.GetProfileInt(section, L"ascending", fAscending) != 0); } /* * Store column widths. */ void ColumnLayout::SaveToRegistry(const WCHAR* section) { WCHAR numBuf[8]; int i; for (i = 0; i < kNumVisibleColumns; i++) { wsprintf(numBuf, L"%d", i); gMyApp.WriteProfileInt(section, numBuf, fColumnWidth[i]); } gMyApp.WriteProfileInt(section, L"sort-column", fSortColumn); gMyApp.WriteProfileInt(section, L"ascending", fAscending); } /* * ========================================================================== * Preferences * ========================================================================== */ /* * Get a default value for the temp path. */ void Preferences::InitTempPath(void) { WCHAR buf[MAX_PATH]; DWORD len; CString tempPath; len = ::GetTempPath(NELEM(buf), buf); if (len == 0) { DWORD err = ::GetLastError(); WMSG1("GetTempPath failed, err=%d\n", err); tempPath = kDefaultTempPath; } else if (len >= NELEM(buf)) { /* sheesh! */ WMSG1("GetTempPath wants a %d-unit buffer\n", len); tempPath = kDefaultTempPath; } else { tempPath = buf; } PathName path(tempPath); WMSG1("Temp path is '%ls'\n", tempPath); path.SFNToLFN(); tempPath = path.GetPathName(); WMSG1("Temp path (long form) is '%ls'\n", tempPath); SetPrefString(kPrTempPath, tempPath); // ::GetFullPathName(fTempPath, sizeof(buf), buf, &foo); // ::SetCurrentDirectory(buf); // ::GetCurrentDirectory(sizeof(buf2), buf2); } /* * Set default values for the various folders. */ void Preferences::InitFolders(void) { CString path; if (GetMyDocuments(&path)) { SetPrefString(kPrOpenArchiveFolder, path); SetPrefString(kPrConvertArchiveFolder, path); SetPrefString(kPrAddFileFolder, path); SetPrefString(kPrExtractFileFolder, path); SetPrefString(kPrOpenWAVFolder, path); } else { WCHAR buf[MAX_PATH]; ::GetCurrentDirectory(NELEM(buf), buf); SetPrefString(kPrOpenArchiveFolder, buf); SetPrefString(kPrConvertArchiveFolder, buf); SetPrefString(kPrAddFileFolder, buf); SetPrefString(kPrExtractFileFolder, buf); SetPrefString(kPrOpenWAVFolder, buf); } WMSG1("Default folder is '%ls'\n", GetPrefString(kPrExtractFileFolder)); } /* * Get the path to the "My Documents" folder. */ bool Preferences::GetMyDocuments(CString* pPath) { LPITEMIDLIST pidl = nil; LPMALLOC lpMalloc = nil; HRESULT hr; bool result = false; hr = ::SHGetMalloc(&lpMalloc); if (FAILED(hr)) return nil; hr = SHGetSpecialFolderLocation(nil, CSIDL_PERSONAL, &pidl); if (FAILED(hr)) { WMSG0("WARNING: unable to get CSIDL_PERSONAL\n"); goto bail; } result = (Pidl::GetPath(pidl, pPath) != FALSE); if (!result) { WMSG0("WARNING: unable to convert CSIDL_PERSONAL to path\n"); /* fall through with "result" */ } bail: lpMalloc->Free(pidl); lpMalloc->Release(); return result; } /* * Determine the type of compression to use as a default, based on what this * version of NufxLib supports. * * Note this happens *before* the AppInit call, so we should restrict this to * things that are version-safe for all of NufxLib v2.x. */ int Preferences::DefaultCompressionType(void) { if (NufxArchive::IsCompressionSupported(kNuThreadFormatLZW2)) return kNuThreadFormatLZW2; else return kNuThreadFormatUncompressed; } /* * Preference getters and setters. */ bool Preferences::GetPrefBool(PrefNum num) const { if (!ValidateEntry(num, kBool)) return false; //return (bool) (fValues[num]); return (bool) ((long) (fValues[num]) != 0); } void Preferences::SetPrefBool(PrefNum num, bool val) { if (!ValidateEntry(num, kBool)) return; fValues[num] = (void*) val; } long Preferences::GetPrefLong(PrefNum num) const { if (!ValidateEntry(num, kLong)) return -1; return (long) fValues[num]; } void Preferences::SetPrefLong(PrefNum num, long val) { if (!ValidateEntry(num, kLong)) return; fValues[num] = (void*) val; } const WCHAR* Preferences::GetPrefString(PrefNum num) const { if (!ValidateEntry(num, kString)) return nil; return (const WCHAR*) fValues[num]; } void Preferences::SetPrefString(PrefNum num, const WCHAR* str) { if (!ValidateEntry(num, kString)) return; free(fValues[num]); if (str == nil) { fValues[num] = nil; } else { fValues[num] = wcsdup(str); } } /* * Free storage for any string entries. */ void Preferences::FreeStringValues(void) { int i; for (i = 0; i < kPrefNumLastEntry; i++) { if (fPrefMaps[i].type == kString) { delete[] fValues[i]; } } } /* * Do a quick scan of the PrefMaps to identify duplicate, misplaced, and * missing entries. */ void Preferences::ScanPrefMaps(void) { int i, j; /* scan PrefNum */ for (i = 0; i < kPrefNumLastEntry; i++) { if (fPrefMaps[i].num != i) { WMSG2("HEY: PrefMaps[%d] has num=%d\n", i, fPrefMaps[i].num); ASSERT(false); break; } } /* look for duplicate strings */ for (i = 0; i < kPrefNumLastEntry; i++) { for (j = i+1; j < kPrefNumLastEntry; j++) { if (fPrefMaps[i].registryKey == nil || fPrefMaps[j].registryKey == nil) { continue; } if (wcsicmp(fPrefMaps[i].registryKey, fPrefMaps[j].registryKey) == 0 && wcsicmp(fPrefMaps[i].registrySection, fPrefMaps[j].registrySection) == 0) { WMSG4("HEY: PrefMaps[%d] and [%d] both have '%ls'/'%ls'\n", i, j, fPrefMaps[i].registrySection, fPrefMaps[i].registryKey); ASSERT(false); break; } } } } /* * Load preferences from the registry. */ int Preferences::LoadFromRegistry(void) { CString sval; bool bval; long lval; WMSG0("Loading preferences from registry\n"); fColumnLayout.LoadFromRegistry(kColumnSect); int i; for (i = 0; i < kPrefNumLastRegistry; i++) { if (fPrefMaps[i].registryKey == nil) continue; switch (fPrefMaps[i].type) { case kBool: bval = GetPrefBool(fPrefMaps[i].num); SetPrefBool(fPrefMaps[i].num, GetBool(fPrefMaps[i].registrySection, fPrefMaps[i].registryKey, bval)); break; case kLong: lval = GetPrefLong(fPrefMaps[i].num); SetPrefLong(fPrefMaps[i].num, GetInt(fPrefMaps[i].registrySection, fPrefMaps[i].registryKey, lval)); break; case kString: sval = GetPrefString(fPrefMaps[i].num); SetPrefString(fPrefMaps[i].num, GetString(fPrefMaps[i].registrySection, fPrefMaps[i].registryKey, sval)); break; default: WMSG2("Invalid type %d on num=%d\n", fPrefMaps[i].type, i); ASSERT(false); break; } } return 0; } /* * Save preferences to the registry. */ int Preferences::SaveToRegistry(void) { WMSG0("Saving preferences to registry\n"); fColumnLayout.SaveToRegistry(kColumnSect); int i; for (i = 0; i < kPrefNumLastRegistry; i++) { if (fPrefMaps[i].registryKey == nil) continue; switch (fPrefMaps[i].type) { case kBool: WriteBool(fPrefMaps[i].registrySection, fPrefMaps[i].registryKey, GetPrefBool(fPrefMaps[i].num)); break; case kLong: WriteInt(fPrefMaps[i].registrySection, fPrefMaps[i].registryKey, GetPrefLong(fPrefMaps[i].num)); break; case kString: WriteString(fPrefMaps[i].registrySection, fPrefMaps[i].registryKey, GetPrefString(fPrefMaps[i].num)); break; default: WMSG2("Invalid type %d on num=%d\n", fPrefMaps[i].type, i); ASSERT(false); break; } } return 0; }