static nfdresult_t AllocPathSet( GSList *fileList, nfdpathset_t *pathSet ) { size_t bufSize = 0; GSList *node; nfdchar_t *p_buf; size_t count = 0; assert(fileList); assert(pathSet); pathSet->count = (size_t)g_slist_length( fileList ); assert( pathSet->count > 0 ); pathSet->indices = NFDi_Malloc( sizeof(size_t)*pathSet->count ); if ( !pathSet->indices ) { return NFD_ERROR; } /* count the total space needed for buf */ for ( node = fileList; node; node = node->next ) { assert(node->data); bufSize += strlen( (const gchar*)node->data ) + 1; } pathSet->buf = NFDi_Malloc( sizeof(nfdchar_t) * bufSize ); /* fill buf */ p_buf = pathSet->buf; for ( node = fileList; node; node = node->next ) { nfdchar_t *path = (nfdchar_t*)(node->data); size_t byteLen = strlen(path)+1; ptrdiff_t index; memcpy( p_buf, path, byteLen ); g_free(node->data); index = p_buf - pathSet->buf; assert( index >= 0 ); pathSet->indices[count] = (size_t)index; p_buf += byteLen; ++count; } g_slist_free( fileList ); return NFD_OKAY; }
// allocs the space in outStr -- call free() static void CopyNFDCharToWChar( const nfdchar_t *inStr, wchar_t **outStr ) { int inStrByteCount = static_cast<int>(strlen(inStr)); int charsNeeded = MultiByteToWideChar(CP_UTF8, 0, inStr, inStrByteCount, NULL, 0 ); assert( charsNeeded ); assert( !*outStr ); charsNeeded += 1; // terminator *outStr = (wchar_t*)NFDi_Malloc( charsNeeded * sizeof(wchar_t) ); if ( !*outStr ) return; int ret = MultiByteToWideChar(CP_UTF8, 0, inStr, inStrByteCount, *outStr, charsNeeded); (*outStr)[charsNeeded-1] = '\0'; #ifdef _DEBUG int inStrCharacterCount = static_cast<int>(NFDi_UTF8_Strlen(inStr)); assert( ret == inStrCharacterCount ); #else _NFD_UNUSED(ret); #endif }
nfdresult_t NFD_PickFolder(const nfdchar_t *defaultPath, nfdchar_t **outPath) { int commandLen = 100; char* command[commandLen]; memset(command, 0, commandLen * sizeof(char*)); command[0] = strdup("zenity"); command[1] = strdup("--file-selection"); command[2] = strdup("--directory"); command[3] = strdup("--title=Select folder"); char* stdOut = NULL; nfdresult_t result = ZenityCommon(command, commandLen, defaultPath, "", &stdOut); if(stdOut != NULL) { size_t len = strlen(stdOut); *outPath = NFDi_Malloc(len); memcpy(*outPath, stdOut, len); (*outPath)[len-1] = '\0'; // trim out the final \n with a null terminator free(stdOut); } else { *outPath = NULL; } return result; }
static nfdresult_t AllocPathSet(char* zenityList, nfdpathset_t *pathSet ) { size_t bufSize = 0; nfdchar_t *p_buf; size_t count = 0; assert(zenityList); assert(pathSet); size_t len = strlen(zenityList) + 1; pathSet->buf = NFDi_Malloc(len); int numEntries = 1; for(size_t i = 0; i < len; i++) { char ch = zenityList[i]; if(ch == '|') { numEntries++; ch = '\0'; } pathSet->buf[i] = ch; } pathSet->count = numEntries; assert( pathSet->count > 0 ); pathSet->indices = NFDi_Malloc( sizeof(size_t)*pathSet->count ); int entry = 0; pathSet->indices[0] = 0; for(size_t i = 0; i < len; i++) { char ch = zenityList[i]; if(ch == '|') { entry++; pathSet->indices[entry] = i + 1; } } return NFD_OKAY; }
nfdresult_t NFD_SaveDialog( const nfdchar_t *filterList, const nfdchar_t *defaultPath, nfdchar_t **outPath ) { GtkWidget *dialog; nfdresult_t result; if ( !gtk_init_check( NULL, NULL ) ) { NFDi_SetError(INIT_FAIL_MSG); return NFD_ERROR; } dialog = gtk_file_chooser_dialog_new( "Save File", NULL, GTK_FILE_CHOOSER_ACTION_SAVE, "_Cancel", GTK_RESPONSE_CANCEL, "_Save", GTK_RESPONSE_ACCEPT, NULL ); gtk_file_chooser_set_do_overwrite_confirmation( GTK_FILE_CHOOSER(dialog), TRUE ); /* Build the filter list */ AddFiltersToDialog(dialog, filterList); /* Set the default path */ SetDefaultPath(dialog, defaultPath); result = NFD_CANCEL; if ( gtk_dialog_run( GTK_DIALOG(dialog) ) == GTK_RESPONSE_ACCEPT ) { char *filename; filename = gtk_file_chooser_get_filename( GTK_FILE_CHOOSER(dialog) ); { size_t len = strlen(filename); *outPath = NFDi_Malloc( len + 1 ); memcpy( *outPath, filename, len + 1 ); if ( !*outPath ) { g_free( filename ); gtk_widget_destroy(dialog); return NFD_ERROR; } } g_free(filename); result = NFD_OKAY; } WaitForCleanup(); gtk_widget_destroy(dialog); WaitForCleanup(); return result; }
// allocs the space in outPath -- call free() static void CopyWCharToNFDChar( const wchar_t *inStr, nfdchar_t **outStr ) { int inStrCharacterCount = static_cast<int>(wcslen(inStr)); int bytesNeeded = WideCharToMultiByte( CP_UTF8, 0, inStr, inStrCharacterCount, NULL, 0, NULL, NULL ); assert( bytesNeeded ); bytesNeeded += 1; *outStr = (nfdchar_t*)NFDi_Malloc( bytesNeeded ); if ( !*outStr ) return; int bytesWritten = WideCharToMultiByte( CP_UTF8, 0, inStr, -1, *outStr, bytesNeeded, NULL, NULL ); assert( bytesWritten ); _NFD_UNUSED( bytesWritten ); }
static nfdresult_t AllocPathSet( IShellItemArray *shellItems, nfdpathset_t *pathSet ) { const char ERRORMSG[] = "Error allocating pathset."; assert(shellItems); assert(pathSet); // How many items in shellItems? DWORD numShellItems; HRESULT result = shellItems->GetCount(&numShellItems); if ( !SUCCEEDED(result) ) { NFDi_SetError(ERRORMSG); return NFD_ERROR; } pathSet->count = static_cast<size_t>(numShellItems); assert( pathSet->count > 0 ); pathSet->indices = (size_t*)NFDi_Malloc( sizeof(size_t)*pathSet->count ); if ( !pathSet->indices ) { return NFD_ERROR; } /* count the total bytes needed for buf */ size_t bufSize = 0; for ( DWORD i = 0; i < numShellItems; ++i ) { ::IShellItem *shellItem; result = shellItems->GetItemAt(i, &shellItem); if ( !SUCCEEDED(result) ) { NFDi_SetError(ERRORMSG); return NFD_ERROR; } // Confirm SFGAO_FILESYSTEM is true for this shellitem, or ignore it. SFGAOF attribs; result = shellItem->GetAttributes( SFGAO_FILESYSTEM, &attribs ); if ( !SUCCEEDED(result) ) { NFDi_SetError(ERRORMSG); return NFD_ERROR; } if ( !(attribs & SFGAO_FILESYSTEM) ) continue; LPWSTR name; shellItem->GetDisplayName(SIGDN_FILESYSPATH, &name); // Calculate length of name with UTF-8 encoding bufSize += GetUTF8ByteCountForWChar( name ); } assert(bufSize); pathSet->buf = (nfdchar_t*)NFDi_Malloc( sizeof(nfdchar_t) * bufSize ); memset( pathSet->buf, 0, sizeof(nfdchar_t) * bufSize ); /* fill buf */ nfdchar_t *p_buf = pathSet->buf; for (DWORD i = 0; i < numShellItems; ++i ) { ::IShellItem *shellItem; result = shellItems->GetItemAt(i, &shellItem); if ( !SUCCEEDED(result) ) { NFDi_SetError(ERRORMSG); return NFD_ERROR; } // Confirm SFGAO_FILESYSTEM is true for this shellitem, or ignore it. SFGAOF attribs; result = shellItem->GetAttributes( SFGAO_FILESYSTEM, &attribs ); if ( !SUCCEEDED(result) ) { NFDi_SetError(ERRORMSG); return NFD_ERROR; } if ( !(attribs & SFGAO_FILESYSTEM) ) continue; LPWSTR name; shellItem->GetDisplayName(SIGDN_FILESYSPATH, &name); int bytesWritten = CopyWCharToExistingNFDCharBuffer(name, p_buf); ptrdiff_t index = p_buf - pathSet->buf; assert( index >= 0 ); pathSet->indices[i] = static_cast<size_t>(index); p_buf += bytesWritten; } return NFD_OKAY; }
static nfdresult_t AddFiltersToDialog( ::IFileDialog *fileOpenDialog, const char *filterList ) { const wchar_t EMPTY_WSTR[] = L""; const wchar_t WILDCARD[] = L"*.*"; if ( !filterList || strlen(filterList) == 0 ) return NFD_OKAY; // Count rows to alloc UINT filterCount = 1; /* guaranteed to have one filter on a correct, non-empty parse */ const char *p_filterList; for ( p_filterList = filterList; *p_filterList; ++p_filterList ) { if ( *p_filterList == ';' ) ++filterCount; } assert(filterCount); if ( !filterCount ) { NFDi_SetError("Error parsing filters."); return NFD_ERROR; } /* filterCount plus 1 because we hardcode the *.* wildcard after the while loop */ COMDLG_FILTERSPEC *specList = (COMDLG_FILTERSPEC*)NFDi_Malloc( sizeof(COMDLG_FILTERSPEC) * (filterCount + 1) ); if ( !specList ) { return NFD_ERROR; } for (size_t i = 0; i < filterCount+1; ++i ) { specList[i].pszName = NULL; specList[i].pszSpec = NULL; } size_t specIdx = 0; p_filterList = filterList; char typebuf[NFD_MAX_STRLEN] = {0}; /* one per comma or semicolon */ char *p_typebuf = typebuf; char filterName[NFD_MAX_STRLEN] = {0}; char specbuf[NFD_MAX_STRLEN] = {0}; /* one per semicolon */ while ( 1 ) { if ( NFDi_IsFilterSegmentChar(*p_filterList) ) { /* append a type to the specbuf (pending filter) */ AppendExtensionToSpecBuf( typebuf, specbuf, NFD_MAX_STRLEN ); p_typebuf = typebuf; memset( typebuf, 0, sizeof(char)*NFD_MAX_STRLEN ); } if ( *p_filterList == ';' || *p_filterList == '\0' ) { /* end of filter -- add it to specList */ // Empty filter name -- Windows describes them by extension. specList[specIdx].pszName = EMPTY_WSTR; CopyNFDCharToWChar( specbuf, (wchar_t**)&specList[specIdx].pszSpec ); memset( specbuf, 0, sizeof(char)*NFD_MAX_STRLEN ); ++specIdx; if ( specIdx == filterCount ) break; } if ( !NFDi_IsFilterSegmentChar( *p_filterList )) { *p_typebuf = *p_filterList; ++p_typebuf; } ++p_filterList; } /* Add wildcard */ specList[specIdx].pszSpec = WILDCARD; specList[specIdx].pszName = EMPTY_WSTR; fileOpenDialog->SetFileTypes( filterCount+1, specList ); /* free speclist */ for ( size_t i = 0; i < filterCount; ++i ) { NFDi_Free( (void*)specList[i].pszSpec ); } NFDi_Free( specList ); return NFD_OKAY; }