Page MenuHomePhabricator

No OneTemporary

Size
771 KB
Referenced Files
None
Subscribers
None
This file is larger than 256 KB, so syntax highlighting was skipped.
diff --git a/tags/fred-0.2.0/NSIS/fred.nsh b/tags/fred-0.2.0/NSIS/fred.nsh
new file mode 100644
index 0000000..5ea15d8
--- /dev/null
+++ b/tags/fred-0.2.0/NSIS/fred.nsh
@@ -0,0 +1,875 @@
+; -----------------------------------------------------------------------------
+; Excelsior Installation Toolkit (EIT) engine
+; -----------------------------------------------------------------------------
+
+!ifndef EIT_INCLUDED
+!define EIT_INCLUDED
+
+!define _EITFUNC_UN
+
+; -----------------------------------------------------------------------------
+; Include text functions support
+
+!include "TextFunc.nsh"
+
+
+; -----------------------------------------------------------------------------
+!macro MUI_LANGUAGE_EIT LANGUAGE
+
+ ;Include a language
+
+ !verbose push
+ !verbose ${MUI_VERBOSE}
+
+ !if ${LANGUAGE} == "Brazilian"
+ !insertmacro MUI_LANGUAGE PortugueseBR
+ !else
+ !insertmacro MUI_LANGUAGE ${LANGUAGE}
+ !endif
+
+ ;Include language file
+ !insertmacro LANGFILE_INCLUDE_WITHDEFAULT "${PROJECT_SHORT_NAME}_Lng${LANGUAGE}.nsh" "${PROJECT_SHORT_NAME}_LngEnglish.nsh"
+
+ !verbose pop
+
+!macroend
+
+
+; -----------------------------------------------------------------------------
+!macro EIT_CALL_PREINSTALL INSTALL_CALLBACK_DLL
+
+ InitPluginsDir
+ SetOutPath $PLUGINSDIR
+
+ File "/oname=eit_install.dll" "${INSTALL_CALLBACK_DLL}"
+
+ System::Call '$PLUGINSDIR\eit_install.dll::_PreInstall@4(t "$INSTDIR")i .r0'
+ ${if} $0 == "error"
+ System::Call '$PLUGINSDIR\eit_install.dll::PreInstall(t "$INSTDIR")i .r0'
+ ${endif}
+ ${if} $0 != 0
+ Abort "Unexpected error in installation script"
+ ${endif}
+
+!macroend
+
+
+; -----------------------------------------------------------------------------
+!macro EIT_CALL_POSTINSTALL
+
+ System::Call '$PLUGINSDIR\eit_install.dll::_PostInstall@4(t "$INSTDIR")i .r0 ? u'
+ ${if} $0 == "error"
+ System::Call '$PLUGINSDIR\eit_install.dll::PostInstall(t "$INSTDIR")i .r0 ? u'
+ ${endif}
+ ${if} $0 != 0
+ Abort "Unexpected error in installation script"
+ ${endif}
+
+!macroend
+
+
+; -----------------------------------------------------------------------------
+!macro EIT_CALL_PREUNINSTALL UNINSTALL_CALLBACK_DLL
+
+ ;-- System::Call can't process paths with round brackets in "Program Filex(x86)"
+ ;-- so convert path to 8.3 form:
+ GetFullPathName /SHORT $1 "${UNINSTALL_CALLBACK_DLL}"
+
+ System::Call '$1::_PreUninstall@0()i ().r0 ? u'
+ ${if} $0 == "error"
+ System::Call '$1::PreUninstall()i ().r0 ? u'
+ ${endif}
+ ${if} $0 != 0
+ Abort "Unexpected error in uninstallation script"
+ ${endif}
+
+ Delete "${UNINSTALL_CALLBACK_DLL}"
+
+!macroend
+
+
+
+;------------------------------------------------------------------------------
+
+!define EIT_LOG_MODE_FILE "File "
+!define EIT_LOG_MODE_DIRECTORY "Folder " ; created folder. remove if empty, else log "can't remove folder" warning
+!define EIT_LOG_MODE_DIRECTORY_R "FolderR " ; recuesive remove this folder
+!define EIT_LOG_MODE_REGISTRY_VAL "RegValue"
+!define EIT_LOG_MODE_REGISTRY "Registry"
+!define EIT_LOG_MODE_REGISTRY_CONTEXT "InstType"
+
+!define EIT_LENGTH_LOG_MODE 8
+
+; -----------------------------------------------------------------------------
+; Declaration of variables
+
+Var eit.InstallLogHandle
+Var eit.RegistryContext
+
+
+;------------------------------------------------------------------------------
+!macro EIT_WRITE_LOG_FILE_STR STR
+
+ ${if} "${STR}" != ""
+ FileWrite $eit.InstallLogHandle "${STR}$\r$\n"
+ ${endif}
+
+!macroend
+!define EIT_WriteLogFileStr '!insertmacro EIT_WRITE_LOG_FILE_STR'
+
+
+;------------------------------------------------------------------------------
+!macro EIT_WRITE_LOG_FILE_STR_NO_NEWLINE STR
+
+ ${if} "${STR}" != ""
+ FileWrite $eit.InstallLogHandle "${STR}"
+ ${endif}
+
+!macroend
+!define EIT_WriteLogFileStrNoNewline '!insertmacro EIT_WRITE_LOG_FILE_STR_NO_NEWLINE'
+
+;------------------------------------------------------------------------------
+!macro EIT_WRITE_LOG_FILE TYPE VALUE
+
+ FileWrite $eit.InstallLogHandle "${TYPE} ${VALUE}$\r$\n"
+
+!macroend
+!define EIT_WriteLogFile '!insertmacro EIT_WRITE_LOG_FILE'
+
+
+;------------------------------------------------------------------------------
+; Adds file(s) to be extracted to the specified output name.
+!macro EIT_ADD_FILE DST_FILE SRC_FILE
+ StrCpy $0 $KeepOnUninstall
+
+ File "/oname=${DST_FILE}" "${SRC_FILE}"
+ ${if} $KeepOnUninstall == 0
+ ${EIT_WriteLogFile} "${EIT_LOG_MODE_FILE}" "${DST_FILE}"
+ ${endif}
+
+!macroend
+!define EIT_AddFile '!insertmacro EIT_ADD_FILE'
+
+
+;========= isFileExists() =====================================================
+; (* ${FileExists} does not understands last slashes in directory name *)
+; In $1 - filename
+; Out $1 - 1 or 0
+!macro EIT_IS_FILE_EXISTS
+ Push $0
+ Push $2
+
+ !define ID3445 ${__LINE__}
+ StrLen $2 $1 ; $2 := length("c:\a\b\\")
+loop_${ID3445}:
+ StrCpy $0 $1 "" -1 ; $0 := last '\'
+ StrCmp $0 "\" cut_${ID3445} ; if ($0 == "\") goto cut_${ID3445}
+ StrCmp $0 "/" cut_${ID3445} ; if ($0== "/") goto cut_${ID3445}
+ StrCmp $0 " " cut_${ID3445} ; if ($0 == " ") goto cut_${ID3445}
+
+ ${if} ${FileExists} $1
+ StrCpy $1 1
+ ${else}
+ StrCpy $1 0
+ ${endif}
+
+ Pop $2
+ Pop $0
+ goto return_${ID3445}
+cut_${ID3445}:
+ StrCpy $1 $1 -1 ; cut last char from $1
+ goto loop_${ID3445}
+return_${ID3445}:
+ !undef ID3445
+
+!macroend
+!define EIT_isFileExists '!insertmacro EIT_IS_FILE_EXISTS'
+
+
+;------------------------------------------------------------------------------
+; Postinstall runnable registration (forms function PostinstallRun() and
+; registers it as MUI_FINISHPAGE_RUN_FUNCTION
+;
+!macro EIT_POSTINSTALL_RUN POSTINSTALL_RUN_DIR POSTINSTALL_RUN_EXE POSTINSTALL_RUN_ARG
+ !define MUI_FINISHPAGE_RUN
+ !define MUI_FINISHPAGE_RUN_FUNCTION PostinstallRun
+
+ Function PostinstallRun
+ Push $0
+ Push $1
+ Push $OUTDIR
+ StrCpy $OUTDIR "${POSTINSTALL_RUN_DIR}"
+ StrCpy $0 "${POSTINSTALL_RUN_EXE}"
+ StrCpy $1 "${POSTINSTALL_RUN_ARG}"
+ ExecShell "" "$0" "$1"
+ Pop $OUTDIR
+ Pop $1
+ Pop $0
+ FunctionEnd ; PostinstallRun
+!macroend
+!define EIT_PostinstallRun '!insertmacro EIT_POSTINSTALL_RUN'
+
+
+
+; -----------------------------------------------------------------------------
+; Creates a shortcut 'link.lnk' that links to 'target.file',
+; with optional parameters 'parameters'.
+!macro EIT_CREATE_SHORTCUT LNK_FILE TARGET_FILE PARAMETERS WORKING_DIR
+
+ ; $OUTDIR is used for the working directory. You can change
+ ; it by using SetOutPath before creating the Shortcut.
+ Push $OUTDIR
+ SetOutPath '${WORKING_DIR}'
+
+ CreateShortCut "${LNK_FILE}" "${TARGET_FILE}" ${PARAMETERS}
+ ${EIT_WriteLogFile} "${EIT_LOG_MODE_FILE}" "${LNK_FILE}"
+
+ Pop $0
+ SetOutPath $0
+
+!macroend
+!define EIT_CreateShortCut '!insertmacro EIT_CREATE_SHORTCUT'
+
+
+; -----------------------------------------------------------------------------
+; Sets the context of $SMPROGRAMS and other shell folders.
+; 0/1 = the 'current user'/'all users' shell folders are used.
+!macro EIT_SET_COMMON_INSTALL_TYPE IS_COMMON
+
+ ${if} ${IS_COMMON} != 0
+ SetShellVarContext "all"
+ StrCpy $eit.RegistryContext "all"
+ ${else}
+ SetShellVarContext "current"
+ StrCpy $eit.RegistryContext "current"
+ ${endif}
+
+!macroend
+!define EIT_SetCommonInstallType '!insertmacro EIT_SET_COMMON_INSTALL_TYPE'
+
+
+
+; -----------------------------------------------------------------------------
+; Log new registry key if it was not exists before
+!macro EIT_LOG_REGISTRY_KEY ROOT_KEY SUBKEY
+
+ ClearErrors
+ EnumRegKey $0 "${ROOT_KEY}" "${SUBKEY}" "0"
+ ${if} ${Errors}
+ ClearErrors
+ ${EIT_WriteLogFile} "${EIT_LOG_MODE_REGISTRY}" "${ROOT_KEY} ${SUBKEY}"
+ ${endif}
+
+!macroend
+!define EIT_LogRegistryKey '!insertmacro EIT_LOG_REGISTRY_KEY'
+
+; -----------------------------------------------------------------------------
+; Log registry value
+!macro EIT_LOG_REGISTRY_VAL ROOT_KEY SUBKEY VAL_NAME
+
+ ${EIT_WriteLogFile} "${EIT_LOG_MODE_REGISTRY_VAL}" "${ROOT_KEY} ${SUBKEY}*${VAL_NAME}"
+
+!macroend
+!define EIT_LogRegistryVal '!insertmacro EIT_LOG_REGISTRY_VAL'
+
+; -----------------------------------------------------------------------------
+; Write a dword (32 bit integer) to the registry.
+; Only short names of root keys are allowed.
+!macro EIT_WRITE_REGISTRY_DWORD ROOT_KEY SUBKEY VAL_NAME VALUE
+
+ ${EIT_LogRegistryKey} "${ROOT_KEY}" "${SUBKEY}"
+ ${EIT_LogRegistryVal} "${ROOT_KEY}" "${SUBKEY}" "${VAL_NAME}"
+ WriteRegDWORD "${ROOT_KEY}" "${SUBKEY}" "${VAL_NAME}" "${VALUE}"
+
+!macroend
+!define EIT_WriteRegDWORD '!insertmacro EIT_WRITE_REGISTRY_DWORD'
+
+
+; -----------------------------------------------------------------------------
+; Write a string to the registry.
+; Only short names of root keys are allowed.
+!macro EIT_WRITE_REGISTRY_STR ROOT_KEY SUBKEY VAL_NAME VALUE
+
+ ${EIT_LogRegistryKey} "${ROOT_KEY}" "${SUBKEY}"
+ ${EIT_LogRegistryVal} "${ROOT_KEY}" "${SUBKEY}" "${VAL_NAME}"
+ WriteRegStr "${ROOT_KEY}" "${SUBKEY}" "${VAL_NAME}" "${VALUE}"
+
+!macroend
+!define EIT_WriteRegStr '!insertmacro EIT_WRITE_REGISTRY_STR'
+
+
+; -----------------------------------------------------------------------------
+!macro EIT_CREATE_FILE_ASSOCIATION FILE_EXT DESCRIPTION COMMAND ARGUMENTS ICON ICONIDX
+
+ ${EIT_WriteRegStr} HKCR "$(^Name).${FILE_EXT}" "" "${DESCRIPTION}"
+ ${EIT_WriteRegStr} HKCR "$(^Name).${FILE_EXT}\DefaultIcon" "" "${ICON},${ICONIDX}"
+ ${EIT_WriteRegStr} HKCR "$(^Name).${FILE_EXT}\Shell\open\command" "" "$\"${COMMAND}$\" ${ARGUMENTS}"
+ ${EIT_WriteRegStr} HKCR "$(^Name).${FILE_EXT}\Shell\open" "FriendlyAppName" "$(^Name)"
+ ${EIT_WriteRegStr} HKCR ".${FILE_EXT}" "" "$(^Name).${FILE_EXT}"
+
+!macroend
+!define EIT_CreateFileAssociation '!insertmacro EIT_CREATE_FILE_ASSOCIATION'
+
+
+; -----------------------------------------------------------------------------
+!macro EIT_SHOW_FILE_ASSOCIATION_REQUEST FILE_EXT FILE_EXT_APPLICATION DESCRIPTION COMMAND ARGUMENTS
+ !define Index "Line${__LINE__}"
+
+ StrCpy $0 "${FILE_EXT}"
+ StrCpy $1 "${FILE_EXT_APPLICATION}"
+ MessageBox MB_YESNO "$(MSG_FILEEXTS_TEMPLATE)" IDNO "L_${Index}_SkipFileAssociation"
+
+ ${EIT_CreateFileAssociation} "${FILE_EXT}" "${DESCRIPTION}" "${COMMAND}" "${ARGUMENTS}"
+
+"L_${Index}_SkipFileAssociation:"
+
+ !undef Index
+!macroend
+!define EIT_ShowFileAssociationRequest '!insertmacro EIT_SHOW_FILE_ASSOCIATION_REQUEST'
+
+
+
+; -----------------------------------------------------------------------------
+!macro EIT_FUNC_DECL_MkCleanupLogString
+
+ !ifndef MkCleanupLogString
+ !define MkCleanupLogString
+ ; -----------------------------------------------------------------------------
+ ; In:
+ ; $0 == "a\b" or ""
+ ; $1 == "c:\program files\a\c"
+ ; Out:
+ ; $0 == String to write to install.log
+ Function MkCleanupLogString
+ Push $1
+ ${EIT_isFileExists}
+ ${if} $1 == 0 ; Allow cleanup if install dir will be created
+ Pop $1
+ allow:
+ StrCpy $0 "${EIT_LOG_MODE_DIRECTORY_R} $1"
+ return
+ ${endif}
+ Pop $1
+
+ ; Install into existent directory - so cleanup is allowed only when $1 ends with $0:
+
+ StrLen $2 $0 ; $2 := length("a\b")
+ StrLen $3 $1 ; $3 := length("c:\program files\a\c")
+ ${if} $2 > 0
+ ${if} $3 > $2
+ IntOp $2 0 - $2 ; $2 := -$2
+ StrCpy $2 $1 "" $2 ; $2 := "a\c"
+ StrCmp $2 $0 allow ; if ("a\c" == "a\b") goto allow
+ ${endif}
+ ${endif}
+
+ StrCpy $0 ""
+ FunctionEnd ; MkCleanupLogString
+
+ !endif ; MkCleanupLogString
+
+!macroend ; EIT_FUNC_DECL_MkCleanupLogString
+
+
+;------------------------------------------------------------------------------
+; Determine if we'll need remove $INSTDIR recursively after uninstall and
+; push string like "FolderR c:\program files\a\b" or push "" if cleanup is not allowed
+!macro EIT_MK_CLEANUP_LOG_STRING DEFFOLDER FULLPATH
+
+ Push $0
+ Push $1
+ Push $2
+ Push $3
+
+ StrCpy $1 "${FULLPATH}"
+ !ifdef DEFAULT_FOLDER
+ StrCpy $0 "${DEFFOLDER}"
+ !else
+ StrCpy $0 ""
+ !endif
+ Call MkCleanupLogString
+
+ Pop $3
+ Pop $2
+ Pop $1
+ Exch $0
+!macroend
+!define EIT_MkCleanupLogStr '!insertmacro EIT_MK_CLEANUP_LOG_STRING'
+
+
+
+;------------------------------------------------------------------------------
+; If ${EXTRAROOT} folder in not exists then add to $0 string
+; like "FolderR c:\program files\a\b"
+!macro EIT_ADD_ROOT_CLEANUP_LOG_STRING EXTRAROOT
+ Push $1
+ StrLen $1 ${EXTRAROOT} ; $1 := length("c:\program files\a\b")
+ ${if} $1 > 3 ; more than "c:\" ({FileExists("c:\") returns FALSE!)
+ StrCpy $1 ${EXTRAROOT}
+ ${EIT_isFileExists}
+ ${if} $1 == 0 ; Allow cleanup if install dir will be created
+ StrCpy $0 "$0${EIT_LOG_MODE_DIRECTORY_R} ${EXTRAROOT}$\r$\n"
+ ${endif}
+ ${endif}
+ Pop $1
+!macroend
+!define EIT_AddRootCleanupLogStr '!insertmacro EIT_ADD_ROOT_CLEANUP_LOG_STRING'
+
+
+;------------------------------------------------------------------------------
+; In: stack = [delimeter char] [directory] [][]....
+; Out: stack = [String to write to install.log] [][]....
+Function SliceDir
+
+ Exch $0 ; chop char ; $0 := '\'
+ Exch
+ Exch $1 ; input string ; $1 := "c:\aa\bb.."
+ Push $2 ;
+ Push $3 ;
+ Push $4 ;
+ Push $5 ; .. and old $0..$5 are saved on stack
+
+ StrCpy $4 "" ; $4 := "" - accumulate string for install.log here
+ StrCpy $5 ""
+ StrCpy $2 2 ; $2 := 2 (to skip "c:\" chars )
+
+ loop: ; loop:
+ IntOp $2 $2 + 1 ; ++$2
+ StrCpy $3 $1 1 $2 ; $3 := $1[$2]
+ StrCmp $3 $0 nextpart ; if ($3 == '\') goto nextpart
+ StrCmp $3 "" nextpart0 ; if ($3 == '') goto nextpart0
+ StrCpy $5 "" ;
+ Goto loop ; goto loop
+ nextpart0:
+ StrCmp $5 $0 EOL ; To don't process "c:\zz" and "c:\zz\" twice
+ nextpart:
+ StrCpy $5 $1 $2 ; $5 := "c:\", "c:\aa", "c:\aa\bb" ...
+ ${if} $2 > 3 ; ignore "c:\"
+ ;-- create $5 and add log for it to $4
+ CreateDirectory "$5"
+ ${if} $4 != ""
+ StrCpy $4 "$4$\r$\n"
+ ${endif}
+ StrCpy $4 "$4${EIT_LOG_MODE_DIRECTORY} $5"
+ ;
+ ${endif}
+ StrCpy $5 $3 ; "\" or "" used to find possible "...\<EOL>"
+ StrCmp $3 $0 loop ; if ($3 == '\') goto loop
+ EOL:
+
+ StrCpy $0 $4
+
+ Pop $5
+ Pop $4
+ Pop $3
+ Pop $2
+ Pop $1
+ Exch $0 ; restore $4..$0 and push log string
+
+FunctionEnd ; SliceDir
+
+;------------------------------------------------------------------------------
+; Out: stack = [String to write to install.log] ....
+!macro EIT_CREATE_DIR_RECURSIVELY1 DIRECTORY
+
+ Push "${DIRECTORY}"
+ Push "\"
+ Call SliceDir
+
+!macroend
+!define EIT_CreateDirRecursively1 '!insertmacro EIT_CREATE_DIR_RECURSIVELY1'
+
+
+;------------------------------------------------------------------------------
+; Creates recursively specified directory. Used to create project root and
+; shortcut directories
+; The error flag is set if the directory couldn't be created.
+; You should always specify an absolute path.
+!macro EIT_CREATE_DIR_RECURSIVELY DIR_NAME
+
+ Push $0
+ ${EIT_CreateDirRecursively1} "${DIR_NAME}"
+ Pop $0
+ ${if} $KeepOnUninstall == 0
+ ${EIT_WriteLogFileStr} "$0"
+ ${endif}
+ Pop $0
+
+!macroend
+!define EIT_CreateDirRecursively '!insertmacro EIT_CREATE_DIR_RECURSIVELY'
+
+;------------------------------------------------------------------------------
+; Creates the specified directory. Assumed that parent directory exists
+; at this time
+; The error flag is set if the directory couldn't be created.
+; You should always specify an absolute path.
+!macro EIT_CREATE_DIRECTORY DIR_NAME
+ Push $1
+ StrCpy $1 "${DIR_NAME}"
+ ${EIT_isFileExists}
+ ${if} $1 == 0
+ CreateDirectory "${DIR_NAME}"
+ ${if} $KeepOnUninstall == 0
+ StrLen $1 "${DIR_NAME}" ;
+ ${if} $1 > 3 ; more than "c:\"
+ ${EIT_WriteLogFileStr} "${EIT_LOG_MODE_DIRECTORY} ${DIR_NAME}"
+ ${endif}
+ ${endif}
+ ${endif}
+ Pop $1
+!macroend
+!define EIT_CreateDirectory '!insertmacro EIT_CREATE_DIRECTORY'
+
+
+;------------------------------------------------------------------------------
+; Open install log and create uninstaller
+!macro EIT_START_INSTALLATION UNINSTALLER_PATH UNINSTALLER_FILE CLEANUP_EXTRAROOTS_LOGSTRS
+
+ Push $R0
+ Push $R2
+
+ !ifdef CLEANUP_DIR
+ ${EIT_MkCleanupLogStr} "${DEFAULT_FOLDER}" "$INSTDIR"
+ Pop $R2
+ !else
+ StrCpy $R2 ""
+ !endif
+
+ ${if} '${UNINSTALLER_PATH}' != '$INSTDIR\'
+ ${EIT_CreateDirRecursively1} "${UNINSTALLER_PATH}" ; it includes $INSTDIR so both this directories will be created and logged
+ Pop $R0
+ ${else}
+ ${EIT_CreateDirRecursively1} "$INSTDIR"
+ Pop $R0
+ ${endif}
+
+ SetOutPath "$INSTDIR"
+
+L_OpenInstallLog:
+ ClearErrors
+ FileOpen $eit.InstallLogHandle "${UNINSTALLER_PATH}${EIT_LOG_FILENAME}" "a"
+
+ ${if} ${Errors}
+ StrCpy $0 "${UNINSTALLER_PATH}${EIT_LOG_FILENAME}"
+ MessageBox MB_RETRYCANCEL|MB_ICONSTOP "$(^FileError_NoIgnore)" IDRETRY L_OpenInstallLog
+ Pop $R2
+ Pop $R0
+ Abort "$(^CantWrite) ${UNINSTALLER_PATH}${EIT_LOG_FILENAME}"
+ ${else}
+ FileSeek $eit.InstallLogHandle 0 END
+ ${endif}
+
+ ${EIT_WriteLogFileStr} "$R2"
+ ${EIT_WriteLogFileStrNoNewline} "${CLEANUP_EXTRAROOTS_LOGSTRS}"
+ ${EIT_WriteLogFileStr} "$R0"
+
+ ${EIT_WriteLogFile} "${EIT_LOG_MODE_FILE}" "${UNINSTALLER_PATH}${EIT_LOG_FILENAME}"
+
+ WriteUninstaller "${UNINSTALLER_PATH}${UNINSTALLER_FILE}"
+ ${EIT_WriteLogFile} "${EIT_LOG_MODE_FILE}" "${UNINSTALLER_PATH}${UNINSTALLER_FILE}"
+
+ Pop $R2
+ Pop $R0
+!macroend
+!define EIT_StartInstallation '!insertmacro EIT_START_INSTALLATION'
+
+
+;------------------------------------------------------------------------------
+!define UNINSTAL_REGISTRY_SUBKEY "Software\Microsoft\Windows\CurrentVersion\Uninstall\$(^Name)"
+
+; Close install log and add uninstall information to Add/Remove Programs
+!macro EIT_END_INSTALLATION COMPANY_NAME UNINSTALLER_PATH UNINSTALLER_FILE
+
+ ; Add uninstall information to Add/Remove Programs
+ ${EIT_WriteRegStr} SHCTX "${UNINSTAL_REGISTRY_SUBKEY}" "DisplayName" "$(^Name)"
+ ${EIT_WriteRegStr} SHCTX "${UNINSTAL_REGISTRY_SUBKEY}" "UninstallString" "${UNINSTALLER_PATH}${UNINSTALLER_FILE}"
+ ${EIT_WriteRegStr} SHCTX "${UNINSTAL_REGISTRY_SUBKEY}" "Publisher" "${COMPANY_NAME}"
+ ${EIT_WriteRegDWORD} SHCTX "${UNINSTAL_REGISTRY_SUBKEY}" "NoModify" 1
+ ${EIT_WriteRegDWORD} SHCTX "${UNINSTAL_REGISTRY_SUBKEY}" "NoRepair" 1
+
+
+ ${EIT_WriteLogFile} "${EIT_LOG_MODE_REGISTRY_CONTEXT}" "$eit.RegistryContext"
+
+ FileClose $eit.InstallLogHandle
+ SetFileAttributes "${UNINSTALLER_PATH}${EIT_LOG_FILENAME}" SYSTEM|HIDDEN
+
+!macroend
+!define EIT_EndInstallation '!insertmacro EIT_END_INSTALLATION'
+
+
+;------------------------------------------------------------------------------
+; Close and remove install log
+!macro EIT_ABORT_INSTALLATION UNINSTALLER_PATH UNINSTALLER_FILE
+
+ FileClose $eit.InstallLogHandle
+
+ ClearErrors
+ FileOpen $eit.InstallLogHandle "${UNINSTALLER_PATH}${EIT_LOG_FILENAME}" "a"
+
+ ${ifnot} ${Errors}
+ FileClose $eit.InstallLogHandle
+ ${EIT_ExecuteUninstall} "${UNINSTALLER_PATH}"
+ ${endif}
+
+ Delete "${UNINSTALLER_PATH}${EIT_LOG_FILENAME}"
+ Delete "${UNINSTALLER_PATH}${UNINSTALLER_FILE}"
+
+!macroend
+!define EIT_AbortInstallation '!insertmacro EIT_ABORT_INSTALLATION'
+
+
+;------------------------------------------------------------------------------
+!macro EIT_ExecWait CMD_LINE
+
+ ExecWait '${CMD_LINE}' $0
+
+ ${if} $0 > 0
+ Abort 'Failed to execute ${CMD_LINE} (exit code = $0)'
+ ${endif}
+
+!macroend
+!define EIT_ExecWait '!insertmacro EIT_ExecWait'
+
+;------------------------------------------------------------------------------
+!macro EIT_ExecWaitIgnoreErrors CMD_LINE
+
+ ExecWait '${CMD_LINE}' $0
+
+!macroend
+!define EIT_ExecWaitIgnoreErrors '!insertmacro EIT_ExecWaitIgnoreErrors'
+
+
+;------------------------------------------------------------------------------
+; SUBKEY_VALNAME is <SUBKEY>*<VAL_NAME>
+
+!macro EIT_DELETE_REG_VAL ROOT_KEY SUBKEY_VALNAME
+ Push $1
+ Push $2
+ Push $3
+ StrCpy $1 0 ; position
+ ;LOOP:
+ IntOp $1 $1 + 1 ; ++$1
+ StrCpy $3 ${SUBKEY_VALNAME} 1 $1 ; $3 := SUBKEY_VALNAME[$1]
+ StrCmp $3 "*" +4 ; if ($3 == '*') goto FOUND
+ StrCmp $3 "" +2 ; if ($3 == '') goto ERROR
+ Goto -4 ; goto LOOP
+ ;ERROR:
+ StrCpy $1 -1
+ ;FOUND:
+
+ ;-- Now $1 == '*' position in SUBKEY_VALNAME or -1
+ ${if} $1 > 0
+ StrCpy $2 ${SUBKEY_VALNAME} $1 0 ; $2 := SUBKEY_VALNAME[0..($1-1)] == <SUBKEY>
+ IntOp $1 $1 + 1 ; ++$1
+ StrCpy $3 ${SUBKEY_VALNAME} "" $1 ; $3 := SUBKEY_VALNAME[$1..] == <VAL_NAME>
+ DeleteRegValue "${ROOT_KEY}" "$2" "$3"
+ ${endif}
+
+ Pop $3
+ Pop $2
+ Pop $1
+!macroend
+!define EIT_DeleteRegVal '!insertmacro EIT_DELETE_REG_VAL'
+
+;------------------------------------------------------------------------------
+!macro CASE_DELETE_REGISTRY_KEY ROOT_KEY SUBKEY
+
+ ${case} "${ROOT_KEY}"
+ DeleteRegKey "${ROOT_KEY}" "${SUBKEY}"
+ ${break}
+
+!macroend
+!define case_DeleteRegistryKey '!insertmacro CASE_DELETE_REGISTRY_KEY'
+
+;------------------------------------------------------------------------------
+!macro CASE_DELETE_REGISTRY_VAL ROOT_KEY SUBKEY_VALNAME
+
+ ${case} "${ROOT_KEY}"
+ ${EIT_DeleteRegVal} "${ROOT_KEY}" "${SUBKEY_VALNAME}"
+ ${break}
+
+!macroend
+!define case_DeleteRegistryVal '!insertmacro CASE_DELETE_REGISTRY_VAL'
+
+
+;------------------------------------------------------------------------------
+; Function EIT_ExecuteUninstall is called when installtion has failed or
+; the user invoked the uninstallion process.
+!macro EIT_ExecuteUninstall
+ !ifndef ${_EITFUNC_UN}EIT_ExecuteUninstall
+ !define ${_EITFUNC_UN}EIT_ExecuteUninstall '!insertmacro ${_EITFUNC_UN}EIT_ExecuteUninstallCall'
+ !insertmacro ${_EITFUNC_UN}TrimNewLines
+
+ Function ${_EITFUNC_UN}EIT_ExecuteUninstall
+ Pop $1 ; install.log file
+
+ StrCpy $0 0 ; line count
+
+
+ DetailPrint "$(^Exec) $1"
+
+ ;-------------------------------
+ ; reading the install log
+
+ ClearErrors
+
+L_UN_OpenInstallLog:
+ SetFileAttributes "$1" NORMAL
+ FileOpen $R0 "$1" r
+
+ ${if} ${Errors}
+ MessageBox MB_RETRYCANCEL|MB_ICONSTOP "$(MSG_UNABLE_TO_READ_FILE)" IDRETRY L_UN_OpenInstallLog
+ Abort "$(MSG_UNABLE_TO_READ_FILE)"
+ ${endif}
+
+ loop:
+ FileRead $R0 $R1
+ ${if} ${Errors}
+ goto endloop
+ ${endif}
+ ${${_EITFUNC_UN}TrimNewLines} "$R1" $R1
+ Push $R1
+ IntOp $0 $0 + 1 ; line count ++
+ goto loop
+ endloop:
+
+ FileClose $R0
+
+ ;-------------------------------
+ ; executing the install log
+
+
+ ${while} $0 > 0
+
+ IntOp $0 $0 - 1 ; line count --
+
+ Pop $R0 ; current line
+ ; DetailPrint $R0
+
+ IntOp $R3 ${EIT_LENGTH_LOG_MODE} + 1
+ StrCpy $R1 $R0 ${EIT_LENGTH_LOG_MODE} ; mode
+ StrCpy $R2 $R0 "" $R3 ; operand(s)
+
+ ClearErrors
+
+ ${switch} $R1
+ ${case} "${EIT_LOG_MODE_FILE}"
+ DetailPrint "$(^Delete): $R2"
+ Delete "$R2"
+ ${break}
+
+ ${case} "${EIT_LOG_MODE_DIRECTORY}"
+ DetailPrint "^RemoveFolder: $R2"
+ RMDir "$R2"
+ ${break}
+
+ ${case} "${EIT_LOG_MODE_DIRECTORY_R}"
+ DetailPrint "^CleanFolder: $R2"
+ RMDir /r "$R2"
+ ${break}
+
+ ${case} "${EIT_LOG_MODE_REGISTRY_VAL}"
+
+ StrCpy $R3 $R2 4 ; root
+ StrCpy $R4 $R2 "" 5 ; registry key
+ DetailPrint "^Unregistering value: $R3 $R4"
+
+ ${switch} $R3
+ ${case_DeleteRegistryVal} "HKCR" "$R4"
+ ${case_DeleteRegistryVal} "HKLM" "$R4"
+ ${case_DeleteRegistryVal} "HKCU" "$R4"
+ ${case_DeleteRegistryVal} "HKCC" "$R4"
+ ${case_DeleteRegistryVal} "HKDD" "$R4"
+
+ ${case} "HKU "
+ StrCpy $R4 $R2 "" 4 ; registry key
+ ${EIT_DeleteRegVal} HKU "$R4"
+ ${break}
+
+ ${case} "SHCT"
+ StrCpy $R4 $R2 "" 6 ; registry key
+ ${EIT_DeleteRegVal} SHCTX "$R4"
+ ${break}
+
+ ${endswitch}
+ ${break}
+
+ ${case} "${EIT_LOG_MODE_REGISTRY}"
+ StrCpy $R3 $R2 4 ; root
+ StrCpy $R4 $R2 "" 5 ; registry key
+ DetailPrint "^Unregistering: $R3 $R4"
+
+ ${switch} $R3
+ ${case_DeleteRegistryKey} "HKCR" "$R4"
+ ${case_DeleteRegistryKey} "HKLM" "$R4"
+ ${case_DeleteRegistryKey} "HKCU" "$R4"
+ ${case_DeleteRegistryKey} "HKCC" "$R4"
+ ${case_DeleteRegistryKey} "HKDD" "$R4"
+
+ ${case} "HKU "
+ StrCpy $R4 $R2 "" 4 ; registry key
+ DeleteRegKey HKU "$R4"
+ ${break}
+
+ ${case} "SHCT"
+ StrCpy $R4 $R2 "" 6 ; registry key
+ DeleteRegKey SHCTX "$R4"
+ ${break}
+
+ ${endswitch}
+ ${break}
+
+ ${case} "${EIT_LOG_MODE_REGISTRY_CONTEXT}"
+ ${if} $R2 == "all"
+ SetShellVarContext all
+ ${else}
+ SetShellVarContext current
+ ${endif}
+ ${break}
+
+ ${endswitch}
+
+ ${endwhile}
+
+ System::Call 'shell32::SHChangeNotify(i 0x08000000, i 0, i 0, i 0) v'
+ FunctionEnd ; un.EIT_ExecuteUninstall
+
+ !endif
+!macroend ; EIT_ExecuteUninstall
+
+
+;------------------------------------------------------------------------------
+!macro un.EIT_ExecuteUninstall
+ !ifndef un.EIT_ExecuteUninstall
+ !undef _EITFUNC_UN
+ !define _EITFUNC_UN 'un.'
+
+ !insertmacro EIT_ExecuteUninstall
+
+ !undef _EITFUNC_UN
+ !define _EITFUNC_UN
+ !endif
+!macroend
+
+
+;------------------------------------------------------------------------------
+!macro EIT_ExecuteUninstallCall UNINSTALLER_PATH
+
+ Push "${UNINSTALLER_PATH}${EIT_LOG_FILENAME}"
+ Call EIT_ExecuteUninstall
+
+!macroend
+
+;------------------------------------------------------------------------------
+!macro un.EIT_ExecuteUninstallCall UNINSTALLER_PATH
+
+ Push "${UNINSTALLER_PATH}${EIT_LOG_FILENAME}"
+ Call un.EIT_ExecuteUninstall
+
+!macroend
+
+;------------------------------------------------------------------------------
+!insertmacro EIT_ExecuteUninstall
+!insertmacro un.EIT_ExecuteUninstall
+
+!endif ; EIT_INCLUDED
diff --git a/tags/fred-0.2.0/NSIS/fred.nsi b/tags/fred-0.2.0/NSIS/fred.nsi
new file mode 100644
index 0000000..0ab8e22
--- /dev/null
+++ b/tags/fred-0.2.0/NSIS/fred.nsi
@@ -0,0 +1,320 @@
+; installer.nsi
+; Generated by Excelsior Installer v2.2
+; Mon Jun 25 20:24:47 CEST 2012
+; -----------------------------------------------------------------------------
+; The installation script based on NSIS modern user interface
+; -----------------------------------------------------------------------------
+;
+!define PROJECT_ROOT_PATH "C:\Documents and Settings\gida\Desktop\fred-0.1.0beta4"
+!define PROJECT_NSIS_PATH "${PROJECT_ROOT_PATH}\NSIS"
+!define PROJECT_NSIS_RESOURCES_PATH "${PROJECT_NSIS_PATH}\resources"
+!define PROJECT_LONG_NAME "Forensic Registry EDitor"
+!define PROJECT_SHORT_NAME "fred"
+!define PROJECT_VERSION "0.1.0beta4"
+!define PROJECT_DEF_INSTDIR "$PROGRAMFILES\\${PROJECT_SHORT_NAME}"
+
+!define PACKAGENAME "${PROJECT_SHORT_NAME}-${PROJECT_VERSION}"
+!define EIT_LOG_FILENAME "nsis_install.log"
+!define DEF_SHORTCUTS_EXISTS
+;
+; -----------------------------------------------------------------------------
+; Include Modern UI, logic statements, file functions and EIT support
+!include "MUI2.nsh"
+!include "x64.nsh"
+!include "LogicLib.nsh"
+!include "FileFunc.nsh"
+!include "${PROJECT_SHORT_NAME}.nsh"
+!include "${PROJECT_SHORT_NAME}_PageInstallType.nsh"
+!include "${PROJECT_SHORT_NAME}_PageShortcuts.nsh"
+!include "${PROJECT_SHORT_NAME}_PageInstallInfo.nsh"
+;
+; -----------------------------------------------------------------------------
+; Configuration of the installation script
+!define COMPANY_NAME ""
+!define DEFAULT_PROGRAM_FOLDER "\${PROJECT_SHORT_NAME}"
+; Valid values for installation type: "auto" | "askuser" | "common" | "private"
+!define DESIRED_INSTALL_TYPE "auto"
+!define REGISTRY_KEY_NAME "Software\\${PROJECT_SHORT_NAME}"
+!define LICENSE_TEXT_FILE "\\?\${PROJECT_NSIS_RESOURCES_PATH}\license.txt"
+!define UNINSTALLER_RELPATH ""
+!define UNINSTALLER_FILE_NAME "Uninstall.exe"
+!define UNINSTALLER_PATH "$INSTDIR\${UNINSTALLER_RELPATH}"
+; -----------------------------------------------------------------------------
+; Declaration of variables
+Var IsCommonInstallation
+Var KeepOnUninstall
+Var InstlDirWasNotEdited
+Var LastDefaultInstalllDir
+Var StartMenuFolder
+; -----------------------------------------------------------------------------
+; General Attributes
+Name "${PROJECT_LONG_NAME}" "${PROJECT_LONG_NAME}"
+OutFile "\\?\${PROJECT_NSIS_PATH}\${PROJECT_SHORT_NAME}-${PROJECT_VERSION}-win32.exe"
+
+; Default installation folder
+InstallDir "${PROJECT_DEF_INSTDIR}"
+
+; Version Information
+VIAddVersionKey "CompanyName" ""
+VIAddVersionKey "LegalCopyright" "Copyright (c) 2011-2020 by Gillen Daniel"
+VIAddVersionKey "ProductName" "${PROJECT_LONG_NAME}"
+VIAddVersionKey "ProductVersion" "${PROJECT_VERSION}"
+VIAddVersionKey "FileDescription" "${PROJECT_SHORT_NAME} ${PROJECT_VERSION}"
+VIAddVersionKey "FileVersion" "${PROJECT_VERSION}"
+VIProductVersion "0.1.0.0"
+
+; The installer will perform a CRC on itself before allowing an install
+CRCCheck on
+; Request application privileges for Windows Vista
+RequestExecutionLevel admin
+BrandingText ""
+; -----------------------------------------------------------------------------
+; Interface Attributes and Settings
+; The interface settings provided by the NSIS compiler itself (such as
+; LicenseText, Icon, CheckBitmap, InstallColors) should not be used in
+; Modern UI scripts. The Modern UI provides equalivent or extended
+; versions of these settings.
+!define MUI_ABORTWARNING
+!define MUI_WELCOMEPAGE_TITLE_3LINES
+!define MUI_FINISHPAGE_TITLE_3LINES
+!define MUI_UNICON "${PROJECT_NSIS_RESOURCES_PATH}\xuninst.ico"
+
+!define MUI_HEADERIMAGE
+!define MUI_HEADERIMAGE_RIGHT
+
+!define MUI_HEADERIMAGE_BITMAP "${PROJECT_NSIS_RESOURCES_PATH}\xinst_header.bmp"
+!define MUI_HEADERIMAGE_UNBITMAP "${PROJECT_NSIS_RESOURCES_PATH}\xinst_header.bmp"
+
+!define MUI_WELCOMEFINISHPAGE_BITMAP "${PROJECT_NSIS_RESOURCES_PATH}\xinst_page.bmp"
+
+!define MUI_UNWELCOMEFINISHPAGE_BITMAP "${PROJECT_NSIS_RESOURCES_PATH}\xuninst_page.bmp"
+
+!define MUI_WELCOMEPAGE_TITLE "$(MSG_WELCOMEPAGE_TITLE)"
+!define MUI_WELCOMEPAGE_TEXT "$(MSG_WELCOMEPAGE_TEXT)"
+
+; -----------------------------------------------------------------------------
+; Installer Page Settings
+; Do not display the checkbox to disable the creation of Start Menu shortcuts.
+!define MUI_STARTMENUPAGE_NODISABLE
+!ifdef MUI_FINISHPAGE_RUN
+ !define MUI_FINISHPAGE_RUN_TEXT "$(MSG_FINISHPAGE_RUN_TEXT)"
+!endif
+!ifdef MUI_FINISHPAGE_SHOWREADME
+ !define MUI_FINISHPAGE_SHOWREADME_TEXT "$(MSG_FINISHPAGE_SHOWREADME_TEXT)"
+!endif
+!ifdef FEATURE_REBOOT_NEEDED
+ !define MUI_FINISHPAGE_TEXT_REBOOT "$(MSG_FINISHPAGE_REBOOT_TEXT)"
+ !define MUI_FINISHPAGE_TEXT_REBOOTNOW "$(MSG_FINISHPAGE_REBOOT_NOW)"
+ !define MUI_FINISHPAGE_TEXT_REBOOTLATER "$(MSG_FINISHPAGE_REBOOT_LATER)"
+!endif
+; Declaration of folder for shortcuts
+${EIT_MUI_PAGE_SHORTCUTS_AddFolder} EIT_MUI_SHORTCUT_FOLDER_DESKTOP
+; -----------------------------------------------------------------------------
+!ifdef CLEANUP_DIR
+ !insertmacro EIT_FUNC_DECL_MkCleanupLogString
+!endif
+; -----------------------------------------------------------------------------
+; If $INSTDIR was never edited by user - update it to default value to accept
+; installation type changes
+Function UpdateInstallDir
+ ${if} $InstlDirWasNotEdited != 0
+ StrCmp "$INSTDIR" "$LastDefaultInstalllDir" instdir_not_changed
+ StrCpy $InstlDirWasNotEdited 0 ; oops. it was changed. turn this auto-update off
+ Return
+instdir_not_changed:
+ StrCpy $INSTDIR "${PROJECT_DEF_INSTDIR}"
+ StrCpy $LastDefaultInstalllDir "$INSTDIR"
+ ${endif}
+FunctionEnd ; UpdateInstallDir
+; -----------------------------------------------------------------------------
+; Call at exit from MUI_PAGE_WELCOME:
+Function CheckAdminRights
+ Push $R1
+ StrCpy $R1 ${DESIRED_INSTALL_TYPE}
+ ; EIT_CheckAdminRights():
+ ; In: R1 = ${DESIRED_INSTALL_TYPE}
+ ; Out: R1 = 1/0 - Admin/NoAdmin
+ ; (OR exit with 'Admin rigths required' message)
+ Call EIT_CheckAdminRights
+ ${if} $R1 != 0
+ ${if} ${DESIRED_INSTALL_TYPE} != "personal"
+ ${EIT_SetCommonInstallType} 1 ; by default it was 0
+ Call UpdateInstallDir
+ ${endif}
+ ${endif}
+ Pop $R1
+FunctionEnd ; CheckAdminRights
+; -----------------------------------------------------------------------------
+; Call at exit from EIT_MUI_PAGE_INSTALLTYPE:
+Function AcceptInstallType
+ ${EIT_SetCommonInstallType} $IsCommonInstallation
+ Call UpdateInstallDir
+FunctionEnd ; AcceptInstallType
+; -----------------------------------------------------------------------------
+; Installer Pages
+!define MUI_PAGE_CUSTOMFUNCTION_LEAVE CheckAdminRights
+!insertmacro MUI_PAGE_WELCOME
+!ifdef LICENSE_TEXT_FILE
+ !insertmacro MUI_PAGE_LICENSE "${LICENSE_TEXT_FILE}"
+!endif
+!define MUI_PAGE_CUSTOMFUNCTION_LEAVE AcceptInstallType
+!insertmacro EIT_MUI_PAGE_INSTALLTYPE $IsCommonInstallation
+!insertmacro MUI_PAGE_DIRECTORY
+!define MUI_STARTMENUPAGE_DEFAULTFOLDER "${DEFAULT_PROGRAM_FOLDER}"
+ !insertmacro MUI_PAGE_STARTMENU Application $StartMenuFolder
+!insertmacro EIT_MUI_PAGE_SHORTCUTS EIT_CreateShortCut
+!insertmacro EIT_MUI_PAGE_INSTALLINFO $StartMenuFolder \
+ EIT_MUI_PAGE_SHORTCUTS_GetInstallInfo
+!insertmacro MUI_PAGE_INSTFILES
+!insertmacro MUI_PAGE_FINISH
+; -----------------------------------------------------------------------------
+; Uninstaller Page Settings
+!ifdef UNINSTALL_FEEDBACK_URL
+ !define MUI_FINISHPAGE_TEXT "$(MSG_FEEDBACK_TEXT)"
+ !define MUI_FINISHPAGE_SHOWREADME ${UNINSTALL_FEEDBACK_URL}
+ !define MUI_FINISHPAGE_SHOWREADME_TEXT "$(MSG_FEEDBACK_CHK_TEXT)"
+!endif
+; -----------------------------------------------------------------------------
+; Uninstaller Pages
+!insertmacro MUI_UNPAGE_WELCOME
+; !insertmacro MUI_UNPAGE_CONFIRM
+!insertmacro MUI_UNPAGE_INSTFILES
+!insertmacro MUI_UNPAGE_FINISH
+; -----------------------------------------------------------------------------
+; Languages
+##SUPPORTED_LANGUAGES
+!insertmacro MUI_LANGUAGE_EIT "English"
+;!insertmacro MUI_LANGUAGE_EIT "Czech"
+;!insertmacro MUI_LANGUAGE_EIT "French"
+;!insertmacro MUI_LANGUAGE_EIT "German"
+;!insertmacro MUI_LANGUAGE_EIT "Italian"
+;!insertmacro MUI_LANGUAGE_EIT "Japanese"
+;!insertmacro MUI_LANGUAGE_EIT "Polish"
+;!insertmacro MUI_LANGUAGE_EIT "Brazilian"
+;!insertmacro MUI_LANGUAGE_EIT "Russian"
+;!insertmacro MUI_LANGUAGE_EIT "Spanish"
+; -----------------------------------------------------------------------------
+; Reserve Files
+ ;If you are using solid compression, files that are required before
+;the actual installation should be stored first in the data block,
+;because this will make your installer start faster.
+ !insertmacro MUI_RESERVEFILE_LANGDLL
+; -----------------------------------------------------------------------------
+; Installer Sections
+Section "Installer Section"
+ Push $0
+ StrCpy $0 "" ; collect cleanup directopy log strings in $0
+ StrCpy $KeepOnUninstall 0
+ ; Call pre-install action of install customization DLL if it was
+ ; specified in the project
+ !ifdef INSTALL_CALLBACK_DLL
+ !insertmacro EIT_CALL_PREINSTALL "${INSTALL_CALLBACK_DLL}"
+ !endif
+ ; Set $OUTPATH, open install log and create uninstaller
+ ${EIT_StartInstallation} "${UNINSTALLER_PATH}" "${UNINSTALLER_FILE_NAME}" "$0"
+ ; Add package files to be extracted to the output path
+ ${EIT_CreateDirectory} "$INSTDIR\report_templates"
+ ${EIT_AddFile} "$INSTDIR\report_templates\NTUSER_RecentDocs.qs" "${PROJECT_ROOT_PATH}\report_templates\NTUSER_RecentDocs.qs"
+ ${EIT_AddFile} "$INSTDIR\report_templates\NTUSER_TypedUrls.qs" "${PROJECT_ROOT_PATH}\report_templates\NTUSER_TypedUrls.qs"
+ ${EIT_AddFile} "$INSTDIR\report_templates\NTUSER_WindowsLiveAccounts.qs" "${PROJECT_ROOT_PATH}\report_templates\NTUSER_WindowsLiveAccounts.qs"
+ ${EIT_AddFile} "$INSTDIR\report_templates\SAM_UserAccounts.qs" "${PROJECT_ROOT_PATH}\report_templates\SAM_UserAccounts.qs"
+ ${EIT_AddFile} "$INSTDIR\report_templates\SOFTWARE_WindowsVersion.qs" "${PROJECT_ROOT_PATH}\report_templates\SOFTWARE_WindowsVersion.qs"
+ ${EIT_AddFile} "$INSTDIR\report_templates\SYSTEM_CurrentNetworkSettings.qs" "${PROJECT_ROOT_PATH}\report_templates\SYSTEM_CurrentNetworkSettings.qs"
+ ${EIT_AddFile} "$INSTDIR\report_templates\SYSTEM_SystemTimeInfo.qs" "${PROJECT_ROOT_PATH}\report_templates\SYSTEM_SystemTimeInfo.qs"
+ ${EIT_AddFile} "$INSTDIR\report_templates\SYSTEM_UsbStorageDevices.qs" "${PROJECT_ROOT_PATH}\report_templates\SYSTEM_UsbStorageDevices.qs"
+ ${EIT_AddFile} "$INSTDIR\fred.exe" "${PROJECT_ROOT_PATH}\fred.exe"
+ ${EIT_AddFile} "$INSTDIR\libgcc_s_dw2-1.dll" "${PROJECT_ROOT_PATH}\libgcc_s_dw2-1.dll"
+ ${EIT_AddFile} "$INSTDIR\libiconv-2.dll" "${PROJECT_ROOT_PATH}\libiconv-2.dll"
+ ${EIT_AddFile} "$INSTDIR\mingwm10.dll" "${PROJECT_ROOT_PATH}\mingwm10.dll"
+ ${EIT_AddFile} "$INSTDIR\phonon4.dll" "${PROJECT_ROOT_PATH}\phonon4.dll"
+ ${EIT_AddFile} "$INSTDIR\QtCore4.dll" "${PROJECT_ROOT_PATH}\QtCore4.dll"
+ ${EIT_AddFile} "$INSTDIR\QtGui4.dll" "${PROJECT_ROOT_PATH}\QtGui4.dll"
+ ${EIT_AddFile} "$INSTDIR\QtNetwork4.dll" "${PROJECT_ROOT_PATH}\QtNetwork4.dll"
+ ${EIT_AddFile} "$INSTDIR\QtScript4.dll" "${PROJECT_ROOT_PATH}\QtScript4.dll"
+ ${EIT_AddFile} "$INSTDIR\QtWebKit4.dll" "${PROJECT_ROOT_PATH}\QtWebKit4.dll"
+ StrCpy $KeepOnUninstall 0
+ ; Create registry key
+ !ifdef REGISTRY_KEY_NAME
+ ${EIT_WriteRegStr} SHCTX "${REGISTRY_KEY_NAME}" "InstallPath" "$INSTDIR"
+ !endif
+ ; Create Start Menu shortcuts
+ !insertmacro MUI_STARTMENU_WRITE_BEGIN Application
+ ${EIT_CreateDirRecursively} "$SMPROGRAMS\$StartMenuFolder"
+ ${EIT_CreateShortCut} \
+ "$SMPROGRAMS\$StartMenuFolder\fred.lnk" "$INSTDIR\fred.exe" \
+ '""' "$INSTDIR"
+
+ ${EIT_CreateShortCut} \
+ "$SMPROGRAMS\$StartMenuFolder\Uninstall.lnk" "$INSTDIR\Uninstall.exe" \
+ '""' "$INSTDIR"
+
+ !insertmacro MUI_STARTMENU_WRITE_END
+
+ ${EIT_MUI_PAGE_SHORTCUTS_CreateShortcut} EIT_MUI_SHORTCUT_FOLDER_DESKTOP \
+ "\fred.lnk" "$INSTDIR\fred.exe" \
+ '""' "$INSTDIR"
+ ; Call post-install action of install customization DLL if it was
+ ; specified in the project
+ !ifdef INSTALL_CALLBACK_DLL
+ !insertmacro EIT_CALL_POSTINSTALL
+ !endif
+ !ifdef FEATURE_REBOOT_NEEDED
+ SetRebootFlag true
+ !endif
+ Pop $0
+ System::Call 'shell32::SHChangeNotify(i 0x08000000, i 0, i 0, i 0) v'
+SectionEnd ; Installer Sections
+; -----------------------------------------------------------------------------
+; Customization of install NSIS callbacks
+Function .onInit
+ StrCpy $InstlDirWasNotEdited 1
+ !ifdef SPLASH_FILE
+ InitPluginsDir
+ File /oname=$PLUGINSDIR\splash.bmp "${SPLASH_FILE}"
+ splash::show 1000 $PLUGINSDIR\splash
+ Pop $0
+ !endif
+ !ifdef REGISTRY_KEY_NAME
+ ReadRegStr $R0 HKLM "${REGISTRY_KEY_NAME}" "InstallPath"
+ ${if} $R0 == ''
+ ClearErrors
+ ReadRegStr $R0 HKCU "${REGISTRY_KEY_NAME}" "InstallPath"
+ ${endif}
+ ${if} $R0 != ''
+ ClearErrors
+ FileOpen $R0 "${UNINSTALLER_PATH}${EIT_LOG_FILENAME}" "r"
+ ${if} ${Errors}
+ ClearErrors
+ ${else}
+ FileClose $R0
+ MessageBox MB_YESNO "$(MSG_PREV_INST_FOUND)" IDYES L_DoInstall
+ Quit
+L_DoInstall:
+ ${endif}
+ ${endif}
+ !endif
+ StrCpy $LastDefaultInstalllDir $INSTDIR
+FunctionEnd
+; -----------------------------------------------------------------------------
+Function .onInstFailed
+ ${EIT_AbortInstallation} "${UNINSTALLER_PATH}" "${UNINSTALLER_FILE_NAME}"
+FunctionEnd
+; -----------------------------------------------------------------------------
+Function .onInstSuccess
+ ${EIT_EndInstallation} "${COMPANY_NAME}" "${UNINSTALLER_PATH}" "${UNINSTALLER_FILE_NAME}"
+FunctionEnd
+; -----------------------------------------------------------------------------
+; Uninstaller Section
+Section "un.Uninstaller Section"
+ ; Call pre-uninstall action of uninstall customization DLL if it was
+ ; specified in the project
+ !ifdef UNINSTALL_CALLBACK_DLL
+ !endif
+ ; at this point the $INSTDIR contais the path to Uninstall.exe
+ ${un.EIT_ExecuteUninstall} "$INSTDIR\"
+ RMDir "$INSTDIR"
+SectionEnd ; Uninstaller Section
+; -----------------------------------------------------------------------------
+; Customization of uninstall NSIS callbacks
+Function un.onInit
+FunctionEnd
diff --git a/tags/fred-0.2.0/NSIS/fred_LngEnglish.nsh b/tags/fred-0.2.0/NSIS/fred_LngEnglish.nsh
new file mode 100644
index 0000000..45b3ef3
--- /dev/null
+++ b/tags/fred-0.2.0/NSIS/fred_LngEnglish.nsh
@@ -0,0 +1,55 @@
+; installer_LngEnglish.nsh
+; Generated by Excelsior Installer v2.2
+; Mon Jun 25 20:24:47 CEST 2012
+; -----------------------------------------------------------------------------
+; English localization for additional messages
+
+ !insertmacro LANGFILE "English" "English"
+
+ ${LangFileString} EIT_MUI_TEXT_INSTALLTYPE_HEADER "Installation type"
+ ${LangFileString} EIT_MUI_TEXT_INSTALLTYPE_SUBHEADER "Choose the type of installation"
+ ${LangFileString} EIT_MUI_TEXT_INSTALLTYPE_DESCRIPTION "Install this application for:"
+ ${LangFileString} EIT_MUI_TEXT_INSTALLTYPE_COMMON "Anyone who uses this computer"
+ ${LangFileString} EIT_MUI_TEXT_INSTALLTYPE_PERSONAL "Current user only"
+
+ ${LangFileString} EIT_MUI_TEXT_SHORTCUTS_HEADER "Shortcut icons"
+ ${LangFileString} EIT_MUI_TEXT_SHORTCUTS_SUBHEADER "Select shortcuts you want to create"
+ ${LangFileString} EIT_MUI_TEXT_SHORTCUTS_DESCRIPTION "Create shortcut icons in the following locations:"
+ ${LangFileString} EIT_MUI_TEXT_SHORTCUTS_TODESKTOP "Desktop"
+ ${LangFileString} EIT_MUI_TEXT_SHORTCUTS_TOQUICK "Quick Launch"
+ ${LangFileString} EIT_MUI_TEXT_SHORTCUTS_TOSTARTMENU "Start Menu Root"
+ ${LangFileString} EIT_MUI_TEXT_SHORTCUTS_TOSTARTUP "Startup Folder"
+
+ ${LangFileString} EIT_MUI_TEXT_FILEASSOCIATION_HEADER "File extension associations"
+ ${LangFileString} EIT_MUI_TEXT_FILEASSOCIATION_SUBHEADER "Select file extensions you want to register"
+ ${LangFileString} EIT_MUI_TEXT_FILEASSOCIATION_DESCRIPTION "Register the following file extensions:"
+
+ ${LangFileString} EIT_MUI_TEXT_INFO_HEADER "Start installation"
+ ${LangFileString} EIT_MUI_TEXT_INFO_SUBHEADER "View current settings"
+ ${LangFileString} EIT_MUI_TEXT_INFO_DESCRIPTION "The installer is ready to install $0 on your computer. Click Next to begin the installation or Back to change the current settings listed below."
+ ${LangFileString} EIT_MUI_TEXT_INFO_DESCLABEL "Current settings:"
+
+
+ ${LangFileString} MSG_FILEEXTS_TEMPLATE "Associate *.$0 files with $1"
+ ${LangFileString} MSG_PREV_INST_FOUND "Previous installation of $(^Name) was found.$\r$\nIt is recommended to remove it before installing this version.$\r$\n$\r$\nDo you wish to continue without removing the previous installation?"
+
+ ${LangFileString} MSG_INFO_DESTINATION_DIRECTORY "Destination folder$\r$\n $0$\r$\n$\r$\n"
+ ${LangFileString} MSG_INFO_PROGRAM_FOLDER "Program folder $\r$\n $0$\r$\n$\r$\n"
+ ${LangFileString} MSG_INFO_SHORTCUTS_DESKTOP "Create shortcuts on the Desktop$\r$\n$\r$\n"
+ ${LangFileString} MSG_INFO_SHORTCUTS_STARTMENU "Create shortcuts in the Start Menu$\r$\n$\r$\n"
+ ${LangFileString} MSG_INFO_SHORTCUTS_QUICKLAUNCH "Create shortcuts on the Quick Launch$\r$\n$\r$\n"
+ ${LangFileString} MSG_INFO_SHORTCUTS_STARTUP "Create shortcuts in the Startup Folder$\r$\n$\r$\n"
+
+ ${LangFileString} MSG_FINISHPAGE_REBOOT_TEXT "Please, remove disks from drives and click Finish to complete setup."
+ ${LangFileString} MSG_FINISHPAGE_REBOOT_NOW "Yes, I want to restart my computer now."
+ ${LangFileString} MSG_FINISHPAGE_REBOOT_LATER "No, I will restart my computer later."
+
+ ${LangFileString} MSG_FEEDBACK_CHK_TEXT "Yes, take me to the feedback form when I click OK."
+
+ ${LangFileString} MSG_NO_RIGHTS "Administrator privileges are required to install this application"
+ ${LangFileString} MSG_UNABLE_TO_READ_FILE "Unable to read file $1"
+ ${LangFileString} MSG_WIN_64_REQUIRED "This installation package can be run on the 64-bit Windows only."
+
+
+ ${LangFileString} MSG_WELCOMEPAGE_TITLE "Welcome to ${PROJECT_LONG_NAME} v${PROJECT_VERSION} Installer"
+ ${LangFileString} MSG_WELCOMEPAGE_TEXT "This Installer will guide you through the installation of the software on your computer. To proceed, click Next."
diff --git a/tags/fred-0.2.0/NSIS/fred_PageInstallInfo.nsh b/tags/fred-0.2.0/NSIS/fred_PageInstallInfo.nsh
new file mode 100644
index 0000000..7d74e63
--- /dev/null
+++ b/tags/fred-0.2.0/NSIS/fred_PageInstallInfo.nsh
@@ -0,0 +1,178 @@
+; -----------------------------------------------------------------------------
+; Page Start Installation
+;
+; Export:
+; Macro EIT_MUI_PAGE_INSTALLINFO is used to set the Page.
+; -----------------------------------------------------------------------------
+
+!include MUI2.nsh
+!include LogicLib.nsh
+!include WinMessages.nsh
+!include FileFunc.nsh
+!include nsDialogs.nsh
+
+
+
+; -----------------------------------------------------------------------------
+; Page interface settings and variables
+!macro EIT_MUI_INSTALLINFOPAGE_INTERFACE
+
+ !ifndef EIT_MUI_INSTALLINFOPAGE_INTERFACE
+ !define EIT_MUI_INSTALLINFOPAGE_INTERFACE
+
+ Var eit.mui.InstallInfoPage
+ Var eit.mui.InstallInfoPage.Description
+ Var eit.mui.InstallInfoPage.Label
+ Var eit.mui.InstallInfoPage.EditText
+
+ !endif
+
+ !ifndef MUI_${MUI_PAGE_UNINSTALLER_PREFIX}WELCOMEFINISHPAGE_BITMAPS
+ !insertmacro MUI_DEFAULT MUI_${MUI_PAGE_UNINSTALLER_PREFIX}WELCOMEFINISHPAGE_BITMAP "${NSISDIR}\Contrib\Graphics\Wizard\win.bmp"
+ !endif
+
+!macroend ; EIT_MUI_INSTALLINFOPAGE_INTERFACE
+
+
+; -----------------------------------------------------------------------------
+; Interface initialization
+!macro EIT_MUI_INSTALLINFOPAGE_GUIINIT
+
+ !ifndef EIT_MUI_${MUI_PAGE_UNINSTALLER_PREFIX}INSTALLINFOPAGE_GUINIT
+ !define EIT_MUI_${MUI_PAGE_UNINSTALLER_PREFIX}INSTALLINFOPAGE_GUINIT
+
+ Function ${MUI_PAGE_UNINSTALLER_FUNCPREFIX}eit.mui.InstallInfoPage.GUIInit
+
+ !ifdef MUI_${MUI_PAGE_UNINSTALLER_PREFIX}PAGE_FUNCTION_GUIINIT
+ Call "${MUI_${MUI_PAGE_UNINSTALLER_PREFIX}PAGE_FUNCTION_GUIINIT}"
+ !endif
+
+ FunctionEnd ; eit.mui.InstallTypePage.GUIInit
+
+ !insertmacro MUI_SET MUI_${MUI_PAGE_UNINSTALLER_PREFIX}PAGE_FUNCTION_GUIINIT \
+ ${MUI_PAGE_UNINSTALLER_FUNCPREFIX}eit.mui.InstallInfoPage.GUIInit
+
+ !endif
+
+!macroend ; EIT_MUI_INSTALLINFOPAGE_GUIINIT
+
+
+; -----------------------------------------------------------------------------
+; Page declaration
+!macro EIT_MUI_PAGEDECLARATION_INSTALLINFO ${START_MENU_FOLDER} ${GET_SHORTCUT_INFO}
+
+ !insertmacro MUI_SET EIT_MUI_${MUI_PAGE_UNINSTALLER_PREFIX}INSTALLINFOPAGE ""
+ !insertmacro EIT_MUI_INSTALLINFOPAGE_INTERFACE
+
+ !insertmacro EIT_MUI_INSTALLINFOPAGE_GUIINIT
+ !define EIT_MUI_INSTALLINFOPAGE_START_MENU_FOLDER ${START_MENU_FOLDER}
+ !define EIT_MUI_INSTALLINFOPAGE_GET_SHORTCUT_INFO ${GET_SHORTCUT_INFO}
+
+ !insertmacro MUI_DEFAULT EIT_MUI_INSTALLINFOPAGE_HEADER "$(EIT_MUI_${MUI_PAGE_UNINSTALLER_PREFIX}TEXT_INFO_HEADER)"
+ !insertmacro MUI_DEFAULT EIT_MUI_INSTALLINFOPAGE_SUBHEADER "$(EIT_MUI_${MUI_PAGE_UNINSTALLER_PREFIX}TEXT_INFO_SUBHEADER)"
+ !insertmacro MUI_DEFAULT EIT_MUI_INSTALLINFOPAGE_DESCRIPTION "$(EIT_MUI_${MUI_PAGE_UNINSTALLER_PREFIX}TEXT_INFO_DESCRIPTION)"
+ !insertmacro MUI_DEFAULT EIT_MUI_INSTALLINFOPAGE_LABEL "$(EIT_MUI_${MUI_PAGE_UNINSTALLER_PREFIX}TEXT_INFO_DESCLABEL)"
+
+ !insertmacro MUI_DEFAULT EIT_MUI_MSG_DESTINATION_DIRECTORY "$(${MUI_PAGE_UNINSTALLER_PREFIX}MSG_INFO_DESTINATION_DIRECTORY)"
+ !insertmacro MUI_DEFAULT EIT_MUI_MSG_INFO_PROGRAM_FOLDER "$(${MUI_PAGE_UNINSTALLER_PREFIX}MSG_INFO_PROGRAM_FOLDER)"
+
+ !insertmacro MUI_PAGE_FUNCTION_FULLWINDOW
+
+ PageEx ${MUI_PAGE_UNINSTALLER_FUNCPREFIX}custom
+
+ PageCallbacks ${MUI_PAGE_UNINSTALLER_FUNCPREFIX}EIT_MUI_InstallInfoPage.Pre_${MUI_UNIQUEID} \
+ ${MUI_PAGE_UNINSTALLER_FUNCPREFIX}EIT_MUI_InstallInfoPage.Leave_${MUI_UNIQUEID}
+
+ PageExEnd
+
+ !insertmacro EIT_MUI_FUNCTION_INSTALLINFOPAGE ${MUI_PAGE_UNINSTALLER_FUNCPREFIX}EIT_MUI_InstallInfoPage.Pre_${MUI_UNIQUEID} \
+ ${MUI_PAGE_UNINSTALLER_FUNCPREFIX}EIT_MUI_InstallInfoPage.Leave_${MUI_UNIQUEID}
+
+ !insertmacro MUI_UNSET EIT_MUI_INSTALLINFOPAGE_HEADER
+ !insertmacro MUI_UNSET EIT_MUI_INSTALLINFOPAGE_SUBHEADER
+ !insertmacro MUI_UNSET EIT_MUI_INSTALLINFOPAGE_DESCRIPTION
+
+ !insertmacro MUI_UNSET EIT_MUI_MSG_DESTINATION_DIRECTORY
+ !insertmacro MUI_UNSET EIT_MUI_MSG_INFO_PROGRAM_FOLDER
+
+!macroend ; EIT_MUI_PAGEDECLARATION_INSTALLINFO
+
+
+; -----------------------------------------------------------------------------
+!macro EIT_MUI_PAGE_INSTALLINFO START_MENU_FOLDER GET_SHORTCUT_INFO
+
+ !verbose push
+ !verbose ${MUI_VERBOSE}
+
+ !insertmacro MUI_PAGE_INIT
+ !insertmacro EIT_MUI_PAGEDECLARATION_INSTALLINFO ${START_MENU_FOLDER} \
+ ${GET_SHORTCUT_INFO}
+
+ !verbose pop
+
+!macroend ; EIT_MUI_PAGE_INSTALLINFO
+
+
+; -----------------------------------------------------------------------------
+; Page functions
+!macro EIT_MUI_FUNCTION_INSTALLINFOPAGE PRE LEAVE
+
+ ; ---------------------------------------------------------------------------
+ Function "${PRE}"
+
+ !insertmacro MUI_PAGE_FUNCTION_CUSTOM PRE
+ !insertmacro MUI_HEADER_TEXT_PAGE ${EIT_MUI_INSTALLINFOPAGE_HEADER} \
+ ${EIT_MUI_INSTALLINFOPAGE_SUBHEADER}
+
+ nsDialogs::Create /NOUNLOAD 1018
+ Pop $eit.mui.InstallInfoPage
+
+ ${if} $eit.mui.InstallInfoPage == error
+ Abort
+ ${endif}
+
+ ; Description text
+ StrCpy $0 "$(^Name)"
+ ${NSD_CreateLabel} 0u 0u 300u 24u "${EIT_MUI_INSTALLINFOPAGE_DESCRIPTION}"
+ Pop $eit.mui.InstallInfoPage.Description
+
+ ; Label text
+ ${NSD_CreateLabel} 0u 28u 300u 8u "${EIT_MUI_INSTALLINFOPAGE_LABEL}"
+ Pop $eit.mui.InstallInfoPage.Label
+
+ ; Info text
+ nsDialogs::CreateControl /NOUNLOAD ${__NSD_Text_CLASS} \
+ ${DEFAULT_STYLES}|${ES_MULTILINE}|${WS_VSCROLL}|${ES_READONLY}|${WS_GROUP}|{SS_BLACKFRAME} \
+ ${WS_EX_STATICEDGE} \
+ 0u 40u 300u 98u ""
+ Pop $eit.mui.InstallInfoPage.EditText
+
+ StrCpy $0 "$INSTDIR"
+ StrCpy $R1 "${EIT_MUI_MSG_DESTINATION_DIRECTORY}"
+
+ !ifdef DEF_SHORTCUTS_EXISTS
+ StrCpy $0 "${EIT_MUI_INSTALLINFOPAGE_START_MENU_FOLDER}"
+ StrCpy $R1 "$R1${EIT_MUI_MSG_INFO_PROGRAM_FOLDER}"
+ !endif
+
+ ${${EIT_MUI_INSTALLINFOPAGE_GET_SHORTCUT_INFO}}
+ StrCpy $R1 "$R1$R0"
+
+ SendMessage $eit.mui.InstallInfoPage.EditText ${WM_SETTEXT} 0 "STR:$R1"
+
+; StrCpy $0 "1234"
+; SendMessage $eit.mui.InstallInfoPage.EditText ${WM_SETTEXT} 0 "STR:${EIT_MUI_MSG_INFO_PROGRAM_FOLDER}"
+
+ nsDialogs::Show
+
+ FunctionEnd ; PRE
+
+
+ ; ---------------------------------------------------------------------------
+ Function "${LEAVE}"
+
+ !insertmacro MUI_PAGE_FUNCTION_CUSTOM LEAVE
+
+ FunctionEnd ; LEAVE
+
+!macroend ; EIT_MUI_FUNCTION_INSTALLINFOPAGE
diff --git a/tags/fred-0.2.0/NSIS/fred_PageInstallType.nsh b/tags/fred-0.2.0/NSIS/fred_PageInstallType.nsh
new file mode 100644
index 0000000..956fde2
--- /dev/null
+++ b/tags/fred-0.2.0/NSIS/fred_PageInstallType.nsh
@@ -0,0 +1,245 @@
+; -----------------------------------------------------------------------------
+; Page Istallation Type
+;
+; Export:
+; Function EIT_CheckAdminRights. It should be executed in the LEAVE
+; function of Page Welcom. If installation type common is required and
+; process has not administrator privileges the installation will be
+; terminated.
+;
+; Macro MUI_PAGE_INSTALLTYPE. It is used to set the page. It has one
+; argument a boolean variable. The value '1' will be assigned to the
+; given variable, if the common installation type should be used.
+; Otherwise the value '0' will be assigned.
+; -----------------------------------------------------------------------------
+
+!include MUI2.nsh
+!include LogicLib.nsh
+!include WinMessages.nsh
+!include FileFunc.nsh
+!include nsDialogs.nsh
+
+; -----------------------------------------------------------------------------
+; Declaration of variables
+
+Var eit.HasAdminRigth
+
+
+; -----------------------------------------------------------------------------
+; Check that administrator privileges are granted
+; Parameters: register $R1 must include disired installation type. The valid
+; values for installation type: "auto" | "askuser" | "common" | "private".
+; If installation type common is required and process has not administrator
+; privileges the installation will be terminated.
+Function EIT_CheckAdminRights
+; In: $R1 == ${DESIRED_INSTALL_TYPE}
+; Out: $R1 == 1/0 - Admin/NoAdmin
+
+ ; eit.HasAdminRigth := 1 only if the user has administrative rights:
+ StrCpy $eit.HasAdminRigth 0
+ ClearErrors
+ UserInfo::GetName
+ IfErrors Win9x
+ Goto WinOk
+ Win9x:
+ StrCpy $eit.HasAdminRigth 1
+ WinOk:
+ Pop $0
+ UserInfo::GetAccountType
+ Pop $1
+ ${if} $1 == "Admin"
+ StrCpy $eit.HasAdminRigth 1
+ ${endif}
+
+ ; It it is not have Admin rights and Common install type is selected then HALT
+ ${if} "$R1" == "common"
+ ${if} $eit.HasAdminRigth != 1
+ MessageBox MB_OK|MB_ICONSTOP "$(MSG_NO_RIGHTS)"
+ Quit
+ ${endif}
+ ${endif}
+ StrCpy $R1 "$eit.HasAdminRigth"
+FunctionEnd ; EIT_CheckAdminRights
+
+
+; -----------------------------------------------------------------------------
+; Page interface settings and variables
+!macro EIT_MUI_INSTALLTYPEPAGE_INTERFACE
+
+ !ifndef EIT_MUI_INSTALLTYPEPAGE_INTERFACE
+ !define EIT_MUI_INSTALLTYPEPAGE_INTERFACE
+
+ Var eit.mui.InstallTypePage
+ Var eit.mui.InstallTypePage.Description
+ Var eit.mui.InstallTypePage.Common
+ Var eit.mui.InstallTypePage.Personal
+
+ !endif
+
+ !ifndef MUI_${MUI_PAGE_UNINSTALLER_PREFIX}WELCOMEFINISHPAGE_BITMAPS
+ !insertmacro MUI_DEFAULT MUI_${MUI_PAGE_UNINSTALLER_PREFIX}WELCOMEFINISHPAGE_BITMAP "${NSISDIR}\Contrib\Graphics\Wizard\win.bmp"
+ !endif
+
+!macroend ; EIT_MUI_INSTALLTYPEPAGE_INTERFACE
+
+
+; -----------------------------------------------------------------------------
+; Interface initialization
+!macro EIT_MUI_INSTALLTYPEPAGE_GUIINIT
+
+ !ifndef EIT_MUI_${MUI_PAGE_UNINSTALLER_PREFIX}INSTALLTYPEPAGE_GUINIT
+ !define EIT_MUI_${MUI_PAGE_UNINSTALLER_PREFIX}INSTALLTYPEPAGE_GUINIT
+
+ Function ${MUI_PAGE_UNINSTALLER_FUNCPREFIX}eit.mui.InstallTypePage.GUIInit
+
+ !ifdef MUI_${MUI_PAGE_UNINSTALLER_PREFIX}PAGE_FUNCTION_GUIINIT
+ Call "${MUI_${MUI_PAGE_UNINSTALLER_PREFIX}PAGE_FUNCTION_GUIINIT}"
+ !endif
+
+ FunctionEnd ; eit.mui.InstallTypePage.GUIInit
+
+ !insertmacro MUI_SET MUI_${MUI_PAGE_UNINSTALLER_PREFIX}PAGE_FUNCTION_GUIINIT \
+ ${MUI_PAGE_UNINSTALLER_FUNCPREFIX}eit.mui.InstallTypePage.GUIInit
+
+ !endif
+
+!macroend ; EIT_MUI_INSTALLTYPEPAGE_GUIINIT
+
+
+; -----------------------------------------------------------------------------
+; Page declaration
+!macro EIT_MUI_PAGEDECLARATION_INSTALLTYPE ${COMMON_SELECTED}
+
+ !insertmacro MUI_SET EIT_MUI_${MUI_PAGE_UNINSTALLER_PREFIX}INSTALLTYPEPAGE ""
+ !insertmacro EIT_MUI_INSTALLTYPEPAGE_INTERFACE
+
+ !insertmacro EIT_MUI_INSTALLTYPEPAGE_GUIINIT
+ !define EIT_MUI_INSTALLTYPEPAGE_COMMON_SELECTED ${COMMON_SELECTED}
+
+ !insertmacro MUI_DEFAULT EIT_MUI_INSTALLTYPEPAGE_HEADER "$(EIT_MUI_${MUI_PAGE_UNINSTALLER_PREFIX}TEXT_INSTALLTYPE_HEADER)"
+ !insertmacro MUI_DEFAULT EIT_MUI_INSTALLTYPEPAGE_SUBHEADER "$(EIT_MUI_${MUI_PAGE_UNINSTALLER_PREFIX}TEXT_INSTALLTYPE_SUBHEADER)"
+ !insertmacro MUI_DEFAULT EIT_MUI_INSTALLTYPEPAGE_DESCRIPTION "$(EIT_MUI_${MUI_PAGE_UNINSTALLER_PREFIX}TEXT_INSTALLTYPE_DESCRIPTION)"
+ !insertmacro MUI_DEFAULT EIT_MUI_INSTALLTYPEPAGE_COMMON "$(EIT_MUI_${MUI_PAGE_UNINSTALLER_PREFIX}TEXT_INSTALLTYPE_COMMON)"
+ !insertmacro MUI_DEFAULT EIT_MUI_INSTALLTYPEPAGE_PERSONAL "$(EIT_MUI_${MUI_PAGE_UNINSTALLER_PREFIX}TEXT_INSTALLTYPE_PERSONAL)"
+
+ !insertmacro MUI_PAGE_FUNCTION_FULLWINDOW
+
+ PageEx ${MUI_PAGE_UNINSTALLER_FUNCPREFIX}custom
+
+ PageCallbacks ${MUI_PAGE_UNINSTALLER_FUNCPREFIX}EIT_MUI_InstallTypePage.Pre_${MUI_UNIQUEID} \
+ ${MUI_PAGE_UNINSTALLER_FUNCPREFIX}EIT_MUI_InstallTypePage.Leave_${MUI_UNIQUEID}
+
+ PageExEnd
+
+ !insertmacro EIT_MUI_FUNCTION_INSTALLTYPEPAGE ${MUI_PAGE_UNINSTALLER_FUNCPREFIX}EIT_MUI_InstallTypePage.Pre_${MUI_UNIQUEID} \
+ ${MUI_PAGE_UNINSTALLER_FUNCPREFIX}EIT_MUI_InstallTypePage.Leave_${MUI_UNIQUEID}
+
+ !insertmacro MUI_UNSET EIT_MUI_INSTALLTYPEPAGE_HEADER
+ !insertmacro MUI_UNSET EIT_MUI_INSTALLTYPEPAGE_SUBHEADER
+ !insertmacro MUI_UNSET EIT_MUI_INSTALLTYPEPAGE_DESCRIPTION
+ !insertmacro MUI_UNSET EIT_MUI_INSTALLTYPEPAGE_COMMON
+ !insertmacro MUI_UNSET EIT_MUI_INSTALLTYPEPAGE_PERSONAL
+
+!macroend ; EIT_MUI_PAGEDECLARATION_INSTALLTYPE
+
+
+; -----------------------------------------------------------------------------
+; Parameter COMMON_SELECTED must be a boolean variable. The value '1'
+; will be assigned to the given variable, if the common installation type
+; should be used. Otherwise the value '0' is assigned.
+!macro EIT_MUI_PAGE_INSTALLTYPE COMMON_SELECTED
+
+ !verbose push
+ !verbose ${MUI_VERBOSE}
+
+ !insertmacro MUI_PAGE_INIT
+ !insertmacro EIT_MUI_PAGEDECLARATION_INSTALLTYPE ${COMMON_SELECTED}
+
+ !verbose pop
+
+!macroend ; EIT_MUI_PAGE_INSTALLTYPE
+
+
+; -----------------------------------------------------------------------------
+; Page functions
+!macro EIT_MUI_FUNCTION_INSTALLTYPEPAGE PRE LEAVE
+
+ ; ---------------------------------------------------------------------------
+ Function "${PRE}"
+
+ ${switch} ${DESIRED_INSTALL_TYPE}
+ ${case} "common"
+ ${if} $eit.HasAdminRigth == 1
+ StrCpy ${EIT_MUI_INSTALLTYPEPAGE_COMMON_SELECTED} 1
+ ${else}
+ MessageBox MB_OK|MB_ICONSTOP "Internal error: Admin expected" ; was not abandoned in CheckAdmin()?
+ Quit
+ ${endif}
+ Abort
+ ${break}
+
+ ${case} "personal"
+ StrCpy ${EIT_MUI_INSTALLTYPEPAGE_COMMON_SELECTED} 0
+ Abort
+ ${break}
+
+ ${case} "auto"
+ ${if} $eit.HasAdminRigth == 1
+ StrCpy ${EIT_MUI_INSTALLTYPEPAGE_COMMON_SELECTED} 1
+ ${else}
+ StrCpy ${EIT_MUI_INSTALLTYPEPAGE_COMMON_SELECTED} 0
+ ${endif}
+ Abort
+ ${break}
+ ${endswitch}
+
+ !insertmacro MUI_PAGE_FUNCTION_CUSTOM PRE
+
+ !insertmacro MUI_HEADER_TEXT_PAGE ${EIT_MUI_INSTALLTYPEPAGE_HEADER} \
+ ${EIT_MUI_INSTALLTYPEPAGE_SUBHEADER}
+
+ nsDialogs::Create /NOUNLOAD 1018
+ Pop $eit.mui.InstallTypePage
+
+ ${if} $eit.mui.InstallTypePage == error
+ Abort
+ ${endif}
+
+ ; Description text
+ ${NSD_CreateLabel} 0u 0u 300u 8u "${EIT_MUI_INSTALLTYPEPAGE_DESCRIPTION}"
+ Pop $eit.mui.InstallTypePage.Description
+
+ ; Radio buttons
+ ${NSD_CreateRadioButton} 16u 20u 284u 8u "${EIT_MUI_INSTALLTYPEPAGE_COMMON}"
+ Pop $eit.mui.InstallTypePage.Common
+
+ ${NSD_CreateRadioButton} 16u 36u 284u 8u "${EIT_MUI_INSTALLTYPEPAGE_PERSONAL}"
+ Pop $eit.mui.InstallTypePage.Personal
+
+ ${if} ${EIT_MUI_INSTALLTYPEPAGE_COMMON_SELECTED} != 0
+ ${NSD_Check} $eit.mui.InstallTypePage.Common
+ ${else}
+ ${NSD_Check} $eit.mui.InstallTypePage.Personal
+ ${endif}
+
+ nsDialogs::Show
+
+ FunctionEnd ; PRE
+
+
+ ; ---------------------------------------------------------------------------
+ Function "${LEAVE}"
+
+ ${NSD_GetState} $eit.mui.InstallTypePage.Common $R0
+
+ ${if} $R0 == ${BST_CHECKED}
+ StrCpy ${EIT_MUI_INSTALLTYPEPAGE_COMMON_SELECTED} 1
+ ${else}
+ StrCpy ${EIT_MUI_INSTALLTYPEPAGE_COMMON_SELECTED} 0
+ ${endif}
+
+ !insertmacro MUI_PAGE_FUNCTION_CUSTOM LEAVE
+
+ FunctionEnd ; LEAVE
+
+!macroend ; EIT_MUI_FUNCTION_INSTALLTYPEPAGE
diff --git a/tags/fred-0.2.0/NSIS/fred_PageShortcuts.nsh b/tags/fred-0.2.0/NSIS/fred_PageShortcuts.nsh
new file mode 100644
index 0000000..85957b3
--- /dev/null
+++ b/tags/fred-0.2.0/NSIS/fred_PageShortcuts.nsh
@@ -0,0 +1,374 @@
+; -----------------------------------------------------------------------------
+; Page Shortcut Icons
+;
+; Export:
+; Macro EIT_MUI_PAGE_SHORTCUTS is used to set the Page.
+; -----------------------------------------------------------------------------
+
+!include MUI2.nsh
+!include LogicLib.nsh
+!include WinMessages.nsh
+!include FileFunc.nsh
+!include nsDialogs.nsh
+
+; -----------------------------------------------------------------------------
+; Places where shortcuts can be created:
+
+!define EIT_MUI_SHORTCUT_FOLDER_DESKTOP DESKTOP
+!define EIT_MUI_SHORTCUT_FOLDER_QUICKLAUNCH QUICKLAUNCH
+!define EIT_MUI_SHORTCUT_FOLDER_STARTMENU STARTMENU
+!define EIT_MUI_SHORTCUT_FOLDER_STARTUP STARTUP
+
+!define EIT_MUI_SHORTCUT_STATE_ENABLE ${BST_CHECKED}
+
+; -----------------------------------------------------------------------------
+; Aply the givemn action to all possible shortcut entries
+!macro EIT_MUI_SHORTCUTS_ITERATE_ENTRIES ACTION ARGUMENTS
+
+ ${${ACTION}} ${EIT_MUI_SHORTCUT_FOLDER_DESKTOP} ${ARGUMENTS}
+ ${${ACTION}} ${EIT_MUI_SHORTCUT_FOLDER_QUICKLAUNCH} ${ARGUMENTS}
+ ${${ACTION}} ${EIT_MUI_SHORTCUT_FOLDER_STARTMENU} ${ARGUMENTS}
+ ${${ACTION}} ${EIT_MUI_SHORTCUT_FOLDER_STARTUP} ${ARGUMENTS}
+
+!macroend
+!define EIT_MUI_SHORTCUTS_IterateEntries '!insertmacro EIT_MUI_SHORTCUTS_ITERATE_ENTRIES'
+
+
+; -----------------------------------------------------------------------------
+; Define variables and mocros for the given shortcut folder
+!macro EIT_MUI_SHORTCUTS_DEFINE_ENTRY ENTRY_NAME SHORTCUT_FOLDER
+
+ !ifndef EIT_MUI_SHORTCUTS_ENTRY_DEFINED
+ !if "${ENTRY_NAME}" == "${SHORTCUT_FOLDER}"
+ !define EIT_MUI_SHORTCUTS_ENTRY_DEFINED
+
+ !ifndef EIT_MUI_SHORTCUTS_FOLDER_${ENTRY_NAME}_ENABLED
+ !define EIT_MUI_SHORTCUTS_FOLDER_${ENTRY_NAME}_ENABLED
+
+ Var eit.mui.ShortcutsPage.${ENTRY_NAME}
+ Var eit.mui.ShortcutsPage.${ENTRY_NAME}.State
+
+ !ifndef EIT_MUI_SHORTCUTS_ENABLED
+ !define EIT_MUI_SHORTCUTS_ENABLED
+ !endif
+
+ !endif
+
+ !endif
+ !endif
+
+!macroend ; EIT_MUI_SHORTCUTS_DEFINE_ENTRY
+!define EIT_MUI_SHORTCUTS_DefineEntry '!insertmacro EIT_MUI_SHORTCUTS_DEFINE_ENTRY'
+
+
+; -----------------------------------------------------------------------------
+; Add on the Page a shortcut folder
+!macro EIT_MUI_PAGE_SHORTCUTS_ADD_FOLDER SHORTCUT_FOLDER
+
+ !ifdef EIT_MUI_SHORTCUTS_ENTRY_DEFINED
+ !undef EIT_MUI_SHORTCUTS_ENTRY_DEFINED
+ !endif
+
+ ${EIT_MUI_SHORTCUTS_IterateEntries} EIT_MUI_SHORTCUTS_DefineEntry ${${SHORTCUT_FOLDER}}
+
+ !ifndef EIT_MUI_SHORTCUTS_ENTRY_DEFINED
+ !error "Shortcut folder '${SHORTCUT_FOLDER}' is unsupported"
+ !else
+ !undef EIT_MUI_SHORTCUTS_ENTRY_DEFINED
+ !endif
+
+!macroend ; EIT_MUI_PAGE_SHORTCUTS_ADD_FOLDER
+!define EIT_MUI_PAGE_SHORTCUTS_AddFolder '!insertmacro EIT_MUI_PAGE_SHORTCUTS_ADD_FOLDER'
+
+
+; -----------------------------------------------------------------------------
+; Page interface settings and variables
+!macro EIT_MUI_SHORTCUTSPAGE_INTERFACE
+
+ !ifndef EIT_MUI_SHORTCUTSPAGE_INTERFACE
+ !define EIT_MUI_SHORTCUTSPAGE_INTERFACE
+
+ Var eit.mui.ShortcutsPage
+ Var eit.mui.ShortcutsPage.Description
+ Var eit.mui.ShortcutsPage.y
+
+ !endif
+
+ !ifndef MUI_${MUI_PAGE_UNINSTALLER_PREFIX}WELCOMEFINISHPAGE_BITMAPS
+ !insertmacro MUI_DEFAULT MUI_${MUI_PAGE_UNINSTALLER_PREFIX}WELCOMEFINISHPAGE_BITMAP "${NSISDIR}\Contrib\Graphics\Wizard\win.bmp"
+ !endif
+
+!macroend ; EIT_MUI_SHORTCUTSPAGE_INTERFACE
+
+
+; -----------------------------------------------------------------------------
+; Set initial state for the given file association entry
+!macro EIT_MUI_SHORTCUTS_INIT_ENTRY ENTRY_NAME
+
+ !ifdef EIT_MUI_SHORTCUTS_FOLDER_${ENTRY_NAME}_ENABLED
+
+ StrCpy $eit.mui.ShortcutsPage.${ENTRY_NAME}.State ${EIT_MUI_SHORTCUT_STATE_ENABLE}
+
+ !endif
+
+!macroend
+!define EIT_MUI_SHORTCUTS_InitEntry '!insertmacro EIT_MUI_SHORTCUTS_INIT_ENTRY'
+
+
+; -----------------------------------------------------------------------------
+; Interface initialization
+!macro EIT_MUI_SHORTCUTSPAGE_GUIINIT
+
+ !ifndef EIT_MUI_${MUI_PAGE_UNINSTALLER_PREFIX}SHORTCUTSPAGE_GUINIT
+ !define EIT_MUI_${MUI_PAGE_UNINSTALLER_PREFIX}SHORTCUTSPAGE_GUINIT
+
+ Function ${MUI_PAGE_UNINSTALLER_FUNCPREFIX}eit.mui.ShortcutsPage.GUIInit
+
+ ${EIT_MUI_SHORTCUTS_IterateEntries} EIT_MUI_SHORTCUTS_InitEntry ""
+
+ !ifdef MUI_${MUI_PAGE_UNINSTALLER_PREFIX}PAGE_FUNCTION_GUIINIT
+ Call "${MUI_${MUI_PAGE_UNINSTALLER_PREFIX}PAGE_FUNCTION_GUIINIT}"
+ !endif
+
+ FunctionEnd ; eit.mui.ShortcutsPage.GUIInit
+
+ !insertmacro MUI_SET MUI_${MUI_PAGE_UNINSTALLER_PREFIX}PAGE_FUNCTION_GUIINIT \
+ ${MUI_PAGE_UNINSTALLER_FUNCPREFIX}eit.mui.ShortcutsPage.GUIInit
+
+ !endif
+
+!macroend ; EIT_MUI_SHORTCUTSPAGE_GUIINIT
+
+
+; -----------------------------------------------------------------------------
+; Page declaration
+!macro EIT_MUI_PAGEDECLARATION_SHORTCUTS ${CREATE_SHORTCUT}
+
+ !insertmacro MUI_SET EIT_MUI_${MUI_PAGE_UNINSTALLER_PREFIX}SHORTCUTSPAGE ""
+ !insertmacro EIT_MUI_SHORTCUTSPAGE_INTERFACE
+
+ !insertmacro EIT_MUI_SHORTCUTSPAGE_GUIINIT
+ !define EIT_MUI_SHORTCUTSPAGE_CREATE_SHORTCUT ${CREATE_SHORTCUT}
+
+ !insertmacro MUI_DEFAULT EIT_MUI_SHORTCUTSPAGE_HEADER "$(EIT_MUI_${MUI_PAGE_UNINSTALLER_PREFIX}TEXT_SHORTCUTS_HEADER)"
+ !insertmacro MUI_DEFAULT EIT_MUI_SHORTCUTSPAGE_SUBHEADER "$(EIT_MUI_${MUI_PAGE_UNINSTALLER_PREFIX}TEXT_SHORTCUTS_SUBHEADER)"
+ !insertmacro MUI_DEFAULT EIT_MUI_SHORTCUTSPAGE_DESCRIPTION "$(EIT_MUI_${MUI_PAGE_UNINSTALLER_PREFIX}TEXT_SHORTCUTS_DESCRIPTION)"
+ !insertmacro MUI_DEFAULT EIT_MUI_SHORTCUTSPAGE_DESKTOP "$(EIT_MUI_${MUI_PAGE_UNINSTALLER_PREFIX}TEXT_SHORTCUTS_TODESKTOP)"
+ !insertmacro MUI_DEFAULT EIT_MUI_SHORTCUTSPAGE_QUICKLAUNCH "$(EIT_MUI_${MUI_PAGE_UNINSTALLER_PREFIX}TEXT_SHORTCUTS_TOQUICK)"
+ !insertmacro MUI_DEFAULT EIT_MUI_SHORTCUTSPAGE_STARTMENU "$(EIT_MUI_${MUI_PAGE_UNINSTALLER_PREFIX}TEXT_SHORTCUTS_TOSTARTMENU)"
+ !insertmacro MUI_DEFAULT EIT_MUI_SHORTCUTSPAGE_STARTUP "$(EIT_MUI_${MUI_PAGE_UNINSTALLER_PREFIX}TEXT_SHORTCUTS_TOSTARTUP)"
+
+ !insertmacro MUI_PAGE_FUNCTION_FULLWINDOW
+
+ PageEx ${MUI_PAGE_UNINSTALLER_FUNCPREFIX}custom
+
+ PageCallbacks ${MUI_PAGE_UNINSTALLER_FUNCPREFIX}EIT_MUI_ShortcutsPage.Pre_${MUI_UNIQUEID} \
+ ${MUI_PAGE_UNINSTALLER_FUNCPREFIX}EIT_MUI_ShortcutsPage.Leave_${MUI_UNIQUEID}
+
+ PageExEnd
+
+ !insertmacro EIT_MUI_FUNCTION_SHORTCUTSPAGE ${MUI_PAGE_UNINSTALLER_FUNCPREFIX}EIT_MUI_ShortcutsPage.Pre_${MUI_UNIQUEID} \
+ ${MUI_PAGE_UNINSTALLER_FUNCPREFIX}EIT_MUI_ShortcutsPage.Leave_${MUI_UNIQUEID}
+
+ !insertmacro MUI_UNSET EIT_MUI_SHORTCUTSPAGE_HEADER
+ !insertmacro MUI_UNSET EIT_MUI_SHORTCUTSPAGE_SUBHEADER
+ !insertmacro MUI_UNSET EIT_MUI_SHORTCUTSPAGE_DESCRIPTION
+ !insertmacro MUI_UNSET EIT_MUI_SHORTCUTSPAGE_DESKTOP
+ !insertmacro MUI_UNSET EIT_MUI_SHORTCUTSPAGE_QUICKLAUNCH
+ !insertmacro MUI_UNSET EIT_MUI_SHORTCUTSPAGE_STARTMENU
+ !insertmacro MUI_UNSET EIT_MUI_SHORTCUTSPAGE_STARTUP
+
+!macroend ; EIT_MUI_PAGEDECLARATION_SHORTCUTS
+
+
+; -----------------------------------------------------------------------------
+; Parameter 'CREATE_SHORTCUT' is a macro to be used to create Shortcut for
+; the items whitch are selected by the user.
+!macro EIT_MUI_PAGE_SHORTCUTS CREATE_SHORTCUT
+
+ !ifdef EIT_MUI_SHORTCUTS_ENABLED
+ !verbose push
+ !verbose ${MUI_VERBOSE}
+
+ !insertmacro MUI_PAGE_INIT
+ !insertmacro EIT_MUI_PAGEDECLARATION_SHORTCUTS ${CREATE_SHORTCUT}
+
+ !verbose pop
+ !endif
+
+!macroend ; EIT_MUI_PAGE_SHORTCUTS
+
+
+; -----------------------------------------------------------------------------
+!macro EIT_MUI_SHORTCUTS_CREATE_CHECKBOX ENTRY_NAME YPOS
+
+ !ifdef EIT_MUI_SHORTCUTS_FOLDER_${ENTRY_NAME}_ENABLED
+
+ ${NSD_CreateCheckBox} 16u ${YPOS}u 284u 8u "${EIT_MUI_SHORTCUTSPAGE_${ENTRY_NAME}}"
+ Pop $eit.mui.ShortcutsPage.${ENTRY_NAME}
+
+ ${NSD_SetState} $eit.mui.ShortcutsPage.${ENTRY_NAME} \
+ $eit.mui.ShortcutsPage.${ENTRY_NAME}.State
+
+ IntOp ${YPOS} ${YPOS} + 16
+
+ !endif
+
+!macroend ; EIT_MUI_SHORTCUTS_CREATE_CHECKBOX
+!define EIT_MUI_SHORTCUTS_CreateCheckbox '!insertmacro EIT_MUI_SHORTCUTS_CREATE_CHECKBOX'
+
+
+; -----------------------------------------------------------------------------
+!macro EIT_MUI_SHORTCUTS_SAVE_CHECKBOX_STATE ENTRY_NAME
+
+ !ifdef EIT_MUI_SHORTCUTS_FOLDER_${ENTRY_NAME}_ENABLED
+
+ ${NSD_GetState} $eit.mui.ShortcutsPage.${ENTRY_NAME} \
+ $eit.mui.ShortcutsPage.${ENTRY_NAME}.State
+
+ !endif
+
+!macroend ; EIT_MUI_SHORTCUTS_SAVE_CHECKBOX_STATE
+!define EIT_MUI_SHORTCUTS_SaveCheckboxState '!insertmacro EIT_MUI_SHORTCUTS_SAVE_CHECKBOX_STATE'
+
+
+; -----------------------------------------------------------------------------
+; Page functions
+!macro EIT_MUI_FUNCTION_SHORTCUTSPAGE PRE LEAVE
+
+ ; ---------------------------------------------------------------------------
+ Function "${PRE}"
+
+ !ifndef EIT_MUI_SHORTCUTS_ENABLED
+ Abort
+ !endif
+
+ !insertmacro MUI_PAGE_FUNCTION_CUSTOM PRE
+ !insertmacro MUI_HEADER_TEXT_PAGE ${EIT_MUI_SHORTCUTSPAGE_HEADER} \
+ ${EIT_MUI_SHORTCUTSPAGE_SUBHEADER}
+
+ nsDialogs::Create /NOUNLOAD 1018
+ Pop $eit.mui.ShortcutsPage
+
+ ${if} $eit.mui.ShortcutsPage == error
+ Abort
+ ${endif}
+
+ ; Description text
+ ${NSD_CreateLabel} 0u 0u 300u 8u "${EIT_MUI_SHORTCUTSPAGE_DESCRIPTION}"
+ Pop $eit.mui.ShortcutsPage.Description
+
+ ; CheckBoxes
+ StrCpy $eit.mui.ShortcutsPage.y 20
+ ${EIT_MUI_SHORTCUTS_IterateEntries} EIT_MUI_SHORTCUTS_CreateCheckbox \
+ $eit.mui.ShortcutsPage.y
+
+ nsDialogs::Show
+
+ FunctionEnd ; PRE
+
+
+ ; ---------------------------------------------------------------------------
+ Function "${LEAVE}"
+
+ ${EIT_MUI_SHORTCUTS_IterateEntries} EIT_MUI_SHORTCUTS_SaveCheckboxState ""
+
+ !insertmacro MUI_PAGE_FUNCTION_CUSTOM LEAVE
+
+ FunctionEnd ; LEAVE
+
+!macroend ; EIT_MUI_FUNCTION_SHORTCUTSPAGE
+
+
+; -----------------------------------------------------------------------------
+!macro EIT_MUI_SHORTCUTS_PROCESS_SHORTCUT ENTRY_NAME SHORTCUT_FOLDER
+
+ !if "${ENTRY_NAME}" == "${SHORTCUT_FOLDER}"
+
+ ${if} "$eit.mui.ShortcutsPage.${ENTRY_NAME}.State" == "${EIT_MUI_SHORTCUT_STATE_ENABLE}"
+
+ ${${EIT_MUI_SHORTCUTSPAGE_CREATE_SHORTCUT}} \
+ "${EIT_MUI_SHORTCUT_FOLDER_LOCATION_${ENTRY_NAME}}\${EIT_MUI_SHORTCUTS_LNK_FILE}" \
+ "${EIT_MUI_SHORTCUTS_TARGET_FILE}" \
+ '${${EIT_MUI_SHORTCUTS_PARAMETERS}}' \
+ "${EIT_MUI_SHORTCUTS_WORKING_DIR}"
+
+ ${endif}
+
+ !endif
+
+!macroend ; EIT_MUI_SHORTCUTS_PROCESS_SHORTCUT
+!define EIT_MUI_SHORTCUTS_ProcessShortcut '!insertmacro EIT_MUI_SHORTCUTS_PROCESS_SHORTCUT'
+
+
+; -----------------------------------------------------------------------------
+; Create selected shortcuts.
+!macro EIT_MUI_PAGE_SHORTCUTS_CREATE_SHORTCUT SHORTCUT_FOLDER \
+ LNK_FILE TARGET_FILE PARAMETERS WORKING_DIR
+
+ !ifdef EIT_MUI_SHORTCUTS_ENABLED
+
+ !insertmacro MUI_DEFAULT EIT_MUI_SHORTCUT_FOLDER_LOCATION_DESKTOP $DESKTOP
+ !insertmacro MUI_DEFAULT EIT_MUI_SHORTCUT_FOLDER_LOCATION_QUICKLAUNCH $QUICKLAUNCH
+ !insertmacro MUI_DEFAULT EIT_MUI_SHORTCUT_FOLDER_LOCATION_STARTMENU $STARTMENU
+ !insertmacro MUI_DEFAULT EIT_MUI_SHORTCUT_FOLDER_LOCATION_STARTUP $SMSTARTUP
+
+ !insertmacro MUI_SET EIT_MUI_SHORTCUTS_LNK_FILE "${LNK_FILE}"
+ !insertmacro MUI_SET EIT_MUI_SHORTCUTS_TARGET_FILE "${TARGET_FILE}"
+ !insertmacro MUI_SET EIT_MUI_SHORTCUTS_PARAMETERS PARAMETERS
+ !insertmacro MUI_SET EIT_MUI_SHORTCUTS_WORKING_DIR "${WORKING_DIR}"
+
+ ${EIT_MUI_SHORTCUTS_IterateEntries} EIT_MUI_SHORTCUTS_ProcessShortcut ${${SHORTCUT_FOLDER}}
+
+ !insertmacro MUI_UNSET EIT_MUI_SHORTCUTS_LNK_FILE
+ !insertmacro MUI_UNSET EIT_MUI_SHORTCUTS_TARGET_FILE
+ !insertmacro MUI_UNSET EIT_MUI_SHORTCUTS_PARAMETERS
+ !insertmacro MUI_UNSET EIT_MUI_SHORTCUTS_WORKING_DIR
+
+ !insertmacro MUI_UNSET EIT_MUI_SHORTCUT_FOLDER_LOCATION_DESKTOP
+ !insertmacro MUI_UNSET EIT_MUI_SHORTCUT_FOLDER_LOCATION_QUICKLAUNCH
+ !insertmacro MUI_UNSET EIT_MUI_SHORTCUT_FOLDER_LOCATION_STARTMENU
+ !insertmacro MUI_UNSET EIT_MUI_SHORTCUT_FOLDER_LOCATION_STARTUP
+
+ !endif
+
+!macroend ; EIT_MUI_PAGE_SHORTCUTS_CREATE_SHORTCUTS
+!define EIT_MUI_PAGE_SHORTCUTS_CreateShortcut '!insertmacro EIT_MUI_PAGE_SHORTCUTS_CREATE_SHORTCUT'
+
+
+; -----------------------------------------------------------------------------
+!macro EIT_MUI_SHORTCUTS_GET_SHORTCUT_INFO ENTRY_NAME OUT_INFO
+
+ ${if} "$eit.mui.ShortcutsPage.${ENTRY_NAME}.State" == "${EIT_MUI_SHORTCUT_STATE_ENABLE}"
+
+ StrCpy ${OUT_INFO} "${OUT_INFO}${EIT_MUI_MSG_INFO_SHORTCUTS_${ENTRY_NAME}}"
+
+ ${endif}
+
+!macroend ; EIT_MUI_SHORTCUTS_GET_SHORTCUT_INFO
+!define EIT_MUI_SHORTCUTS_GetShortcutInfo '!insertmacro EIT_MUI_SHORTCUTS_GET_SHORTCUT_INFO'
+
+
+; -----------------------------------------------------------------------------
+; Out: $R0 = Return information of selected shortcuts.
+!macro EIT_MUI_PAGE_SHORTCUTS_GET_INSTALLINFO
+
+ StrCpy $R0 ""
+ !ifdef EIT_MUI_SHORTCUTS_ENABLED
+
+ !insertmacro MUI_DEFAULT EIT_MUI_MSG_INFO_SHORTCUTS_DESKTOP "$(${MUI_PAGE_UNINSTALLER_PREFIX}MSG_INFO_SHORTCUTS_DESKTOP)"
+ !insertmacro MUI_DEFAULT EIT_MUI_MSG_INFO_SHORTCUTS_QUICKLAUNCH "$(${MUI_PAGE_UNINSTALLER_PREFIX}MSG_INFO_SHORTCUTS_QUICKLAUNCH)"
+ !insertmacro MUI_DEFAULT EIT_MUI_MSG_INFO_SHORTCUTS_STARTMENU "$(${MUI_PAGE_UNINSTALLER_PREFIX}MSG_INFO_SHORTCUTS_STARTMENU)"
+ !insertmacro MUI_DEFAULT EIT_MUI_MSG_INFO_SHORTCUTS_STARTUP "$(${MUI_PAGE_UNINSTALLER_PREFIX}MSG_INFO_SHORTCUTS_STARTUP)"
+
+ ${EIT_MUI_SHORTCUTS_IterateEntries} EIT_MUI_SHORTCUTS_GetShortcutInfo $R0
+
+ !insertmacro MUI_UNSET EIT_MUI_MSG_INFO_SHORTCUTS_DESKTOP
+ !insertmacro MUI_UNSET EIT_MUI_MSG_INFO_SHORTCUTS_QUICKLAUNCH
+ !insertmacro MUI_UNSET EIT_MUI_MSG_INFO_SHORTCUTS_STARTMENU
+ !insertmacro MUI_UNSET EIT_MUI_MSG_INFO_SHORTCUTS_STARTUP
+
+ !endif
+
+!macroend ; EIT_MUI_PAGE_SHORTCUTS_GET_INSTALLINFO
+!define EIT_MUI_PAGE_SHORTCUTS_GetInstallInfo '!insertmacro EIT_MUI_PAGE_SHORTCUTS_GET_INSTALLINFO'
diff --git a/tags/fred-0.2.0/NSIS/resources/license.txt b/tags/fred-0.2.0/NSIS/resources/license.txt
new file mode 100644
index 0000000..39f194f
--- /dev/null
+++ b/tags/fred-0.2.0/NSIS/resources/license.txt
@@ -0,0 +1,17 @@
+Copyright (C) 2011-2020 by Gillen Daniel and licensed under GPLv3.
+
+This program uses Richard W.M. Jones's hivex library
+
+Copyright (C) 2009-2010 Red Hat Inc.
+Derived from code by Petter Nordahl-Hagen under a compatible license:
+Copyright (C) 1997-2007 Petter Nordahl-Hagen.
+Derived from code by Markus Stephany under a compatible license:
+Copyright (C) 2000-2004 Markus Stephany.
+
+This program uses a modified version of the QHexEdit widget by Simon Winfried
+
+Copyright (c) 2010 by Simon Winfried
+
+This program uses Qt
+
+Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
\ No newline at end of file
diff --git a/tags/fred-0.2.0/NSIS/resources/xinst_header.bmp b/tags/fred-0.2.0/NSIS/resources/xinst_header.bmp
new file mode 100644
index 0000000..941af82
Binary files /dev/null and b/tags/fred-0.2.0/NSIS/resources/xinst_header.bmp differ
diff --git a/tags/fred-0.2.0/NSIS/resources/xinst_page.bmp b/tags/fred-0.2.0/NSIS/resources/xinst_page.bmp
new file mode 100644
index 0000000..292b813
Binary files /dev/null and b/tags/fred-0.2.0/NSIS/resources/xinst_page.bmp differ
diff --git a/tags/fred-0.2.0/NSIS/resources/xuninst.ico b/tags/fred-0.2.0/NSIS/resources/xuninst.ico
new file mode 100644
index 0000000..94db1b2
Binary files /dev/null and b/tags/fred-0.2.0/NSIS/resources/xuninst.ico differ
diff --git a/tags/fred-0.2.0/NSIS/resources/xuninst_page.bmp b/tags/fred-0.2.0/NSIS/resources/xuninst_page.bmp
new file mode 100644
index 0000000..1d544e3
Binary files /dev/null and b/tags/fred-0.2.0/NSIS/resources/xuninst_page.bmp differ
diff --git a/tags/fred-0.2.0/README b/tags/fred-0.2.0/README
new file mode 100644
index 0000000..4e80084
--- /dev/null
+++ b/tags/fred-0.2.0/README
@@ -0,0 +1,226 @@
+FRED README FILE REVISION 1
+
+Table of contents
+ 0.0 Author and license stuff
+ 1.0 What is fred? - A short description
+ 2.0 Installation instructions
+ 2.1 Prerequisits
+ 2.1.1 Linux
+ 2.1.2 Mac OSX
+ 2.1.3 Windows
+ 2.2 Installing a prebuild binary package
+ 2.3 Installing from source
+ 2.3.1 Shared vs static libhivex
+ 2.3.2 Linux
+ 2.3.2.1 Prerequisites
+ 2.3.2.2 Compiling
+ 2.3.2.3 Packaging
+ 2.3.3 Mac OSX
+ 2.3.3.1 Prerequisites
+ 2.3.3.2 Compiling
+ 2.3.3.3 Packaging
+ 2.3.4 Windows
+ 2.3.5 Crosscompiling for Windows
+ 2.3.5.1 Prerequisites
+ 2.3.5.1.1 Compiler
+ 2.3.5.1.2 Qt
+ 2.3.5.2 Compiling
+ 2.3.5.3 Packaging
+
+0.0 Author and license stuff
+ fred Copyright (c) 2011-2020 by Gillen Daniel <gillen.dan@pinguin.lu>
+
+ This program is free software: you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free Software
+ Foundation, either version 3 of the License, or (at your option) any later
+ version.
+
+ This program is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program. If not, see <http://www.gnu.org/licenses/>.
+
+1.0 What is fred? - A short description
+ Forensic Registry EDitor (fred) is a cross-platform M$ registry hive editor.
+ This project was born out of the need for a reasonably good registry hive
+ viewer for Linux to conduct forensic analysis. Therefore it includes some
+ functions not found in normal "free" registry editors like a hex viewer with
+ data interpreter and a reporting function that can easily be extended with
+ custom ECMAScript report templates.
+
+2.0 Installation instructions
+ 2.1 Prerequisits
+ If you are not going to use my prebuild packages, in addition to the
+ prerequisits below you probably will also need Richard W.M. Jones's libhivex
+ available from https://github.com/libguestfs/hivex.
+
+ 2.1.1 Linux
+ Any Linux with Qt v4.x libraries.
+
+ 2.1.2 Mac OSX
+ OSX v10.5 or above with Qt v4.x libraries.
+
+ 2.1.3 Windows
+ Windows XP or newer with Qt v4.x libraries.
+
+ 2.2 Installing a prebuild binary package
+ Chances are I provide prebuild binary packages for your OS (generally
+ Debian/Ubuntu, Mac OSX and Windows). If so, you can simply download them
+ from https://www.pinguin.lu.
+
+ ForDebian/Ubuntu, add my repository and execute the following command:
+
+ $ sudo apt-get install fred fred-reports
+
+ For Mac OSX and Windows, execute the installer and follow the on-screen
+ instructions.
+
+ If I have no prebuild binary packages for your OS, you will have to compile
+ fred by yourself. In this case, read the instructions under "Installing from
+ source".
+
+ 2.3 Installing from source
+ Start by getting the source code from https://www.pinguin.lu and unpacking
+ it to some temporary directory. Under Linux and Mac OSX, use:
+
+ $ cd /some/temp/dir/
+ $ tar xfvz fred-x.x.x.tar.gz
+
+ Under Windows, use 7zip or alike to decompress the tar.gz file.
+
+ 2.3.1 Shared vs static libhivex
+ When compiling fred from source, you have two possibilities how to include
+ libhivex. When using Linux, chances are your distribution has a package
+ for it available. In this case, you may install the binary and developper
+ version of it and go ahead to build fred. If your distribution has no
+ libhivex package available (Mac OSX and Windows definitely haven't), or
+ you want to use the latest version of it available that might fix some
+ bugs, make sure you use the "--static-hivex" command line option when
+ running my bootstrap.sh script. This will checkout, compile and statically
+ link the latest libhivex compatible with fred while building.
+
+ 2.3.2 Linux
+ 2.3.2.1 Prerequisites
+ TODO
+
+ 2.3.2.2 Compiling
+ Compiling under Linux for Linux should be very simple. Just execute the
+ following commands:
+
+ $ cd /path/to/fred/source/
+ $ ./autogen.sh --platform=linux
+
+ Or, if you want to use the static libhivex:
+
+ $ cd /path/to/fred/source/
+ $ ./autogen.sh --static-hivex --platform=linux
+
+ 2.3.2.3 Packaging
+ TODO
+
+ 2.3.3 Mac OSX
+ 2.3.3.1 Prerequisites
+ In order to compile fred under Mac OSX, you need to install the
+ following software:
+
+ - XCode from Apple
+ - Git from http://code.google.com/p/git-osx-installer/
+ - MacPorts from http://www.macports.org
+ - Qt 4.8.x library from http://qt-project.org
+
+ Aditionally, after installing MacPorts, install the following packages:
+
+ $ sudo port install ocaml libxml2 pkgconfig autoconf gettext
+
+ 2.3.3.2 Compiling
+ Compilation should be straight forward executing the following command:
+
+ $ cd /path/to/fred/source/
+ $ ./autogen.sh --static-hivex --platform=mac
+
+ 2.3.3.3 Packaging
+ TODO
+
+ 2.3.4 Windows
+ Until beta5, fred for Windows was build under Windows. But it was a pain
+ in the bud to do so. Therefore I switched to crosscompiling under Linux
+ which works very well. If you want to build fred under Windows, good luck
+ and please, don't contact me if you have any problems! My only answer will
+ be:
+
+ Crosscompile under Linux!
+
+ 2.3.5 Crosscompiling for Windows
+ 2.3.5.1 Prerequisites
+ The following instructions are for Debian / Ubuntu like distros. If you
+ are using another distro, you will need to get the compiler and Qt on
+ your own.
+
+ 2.3.5.1.1 Compiler
+ You need the mingw-w64 gcc and g++ compiler. When using Debian/Ubuntu
+ install the following packages:
+
+ $ sudo apt-get install mingw-w64 mingw-w64-tools g++-mingw-w64 \
+ gcc-mingw-w64 mingw-ocaml autopoint
+
+ 2.3.5.1.2 Qt
+ After you have a compiler, you will need to crosscompile Qt as it is
+ currently not available as package. Start by getting the source:
+
+ $ cd /some/temp/dir/
+ $ QTU="http://download.qt-project.org/archive/qt/4.8/4.8.4"
+ $ QTP="qt-everywhere-opensource-src-4.8.4"
+ $ wget $QTU/$QTP.tar.gz
+ $ tar xfvz $QTP.tar.gz
+ $ cd $QTP
+
+ Unfortunately, Qt won't build until you apply three small patches:
+
+ $ SRC="/path/to/fred/source/qt_patches"
+ $ patch -p1 <"$SRC/mingw32-qt-4.8.0-no-webkit-tests.patch"
+ $ patch -p1 <"$SRC/qt-4.8.4-fix-sse-suppport-build-regression.patch"
+ $ patch -p1 <"$SRC/qt-4.8.0-fix-include-windows-h.patch"
+
+ Now configure, compile and install Qt (I compiled it on my dual Xeon
+ machine with 40 cores (using make -j40) in 09:27 minutes. It might
+ take a bit longer on your machine :-p):
+
+ $ sudo ./configure -prefix /opt/qt-4.8.4-mingw -opensource \
+ -no-qt3support -no-multimedia -no-audio-backend \
+ -no-phonon -no-phonon-backend -no-javascript-jit \
+ -nomake examples -nomake demos -nomake docs \
+ -xplatform win32-g++-4.6 \
+ -device-option CROSS_COMPILE=i686-w64-mingw32-
+ $ sudo make
+ $ sudo make install
+
+ If you are asking you why the heck I used sudo to run configure, well,
+ Qt likes to copy some files to the prefix dir in that step which will
+ fail if you aren't root.
+
+ 2.3.5.3 LIBXML2
+ $ wget ftp://xmlsoft.org/libxml2/libxml2-2.9.1.tar.gz
+ $ tar xfvz libxml2-2.9.1.tar.gz
+ $ cd libxml2-2.9.1/
+ $ ./configure --prefix /opt/libxml2-2.9.1-mingw --host i686-w64-mingw32 --without-python
+ $ make
+ $ sudo make install
+
+ TODO
+
+ 2.3.5.3 Compiling
+ If all the above worked, you are ready to crosscompile fred:
+
+ $ cd /path/to/fred/source/
+ $ cd hivex/gnulib; patch -p1 <../../hivex_patches/gnulib.patch; cd -
+ $ ./autogen.sh --static-hivex --platform=win32
+
+ The build process of hivex will probably complain and might even fail
+ with an error but normally the lib gets build before that without errors,
+ so just ignore it.
+
+ 2.3.5.4 Packaging
+ TODO
+
diff --git a/tags/fred-0.2.0/argparser.cpp b/tags/fred-0.2.0/argparser.cpp
new file mode 100644
index 0000000..7f8ea2e
--- /dev/null
+++ b/tags/fred-0.2.0/argparser.cpp
@@ -0,0 +1,133 @@
+/*******************************************************************************
+* fred Copyright (c) 2011-2020 by Gillen Daniel <gillen.dan@pinguin.lu> *
+* *
+* Forensic Registry EDitor (fred) is a cross-platform M$ registry hive editor *
+* with special feautures useful during forensic analysis. *
+* *
+* This program is free software: you can redistribute it and/or modify it *
+* under the terms of the GNU General Public License as published by the Free *
+* Software Foundation, either version 3 of the License, or (at your option) *
+* any later version. *
+* *
+* This program is distributed in the hope that it will be useful, but WITHOUT *
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or *
+* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for *
+* more details. *
+* *
+* You should have received a copy of the GNU General Public License along with *
+* this program. If not, see <http://www.gnu.org/licenses/>. *
+*******************************************************************************/
+
+#include "argparser.h"
+
+ArgParser::ArgParser(QStringList args) {
+ this->argv=QStringList(args);
+ this->argc=this->argv.count();
+ this->error_msg="";
+ this->parsed_args.clear();
+}
+
+QString ArgParser::GetErrorMsg() {
+ QString msg=this->error_msg;
+ this->error_msg="";
+ return msg;
+}
+
+bool ArgParser::ParseArgs() {
+ int i=0;
+ int sep_pos=0;
+ QString cur_arg="";
+ QString cur_arg_param="";
+
+ while(i+1<this->argc) {
+ // Get current argument
+ cur_arg=this->argv.at(++i);
+
+ if(cur_arg.size()>1) {
+ // Check for short mode command line args
+ if(cur_arg[0]=='-' && cur_arg[1]!='-') {
+ if(cur_arg=="-?" || cur_arg=="-h") {
+ this->parsed_args.insert(cur_arg.mid(1),QString());
+ continue;
+ } else if(cur_arg=="-v") {
+ this->parsed_args.insert(cur_arg.mid(1),QString());
+ continue;
+ } else {
+ // Unknown argument
+ this->SetError(QString("Unknown command line argument '%1'!")
+ .arg(cur_arg));
+ return false;
+ }
+ }
+
+ // Check for long mode command line args
+ if(cur_arg[0]=='-' && cur_arg[1]=='-') {
+ // Extract argument parameter if there is one
+ sep_pos=cur_arg.indexOf('=');
+ if(sep_pos!=-1) {
+ cur_arg_param=cur_arg.mid(sep_pos+1);
+ // Remove parameter from arg
+ cur_arg=cur_arg.left(sep_pos);
+ } else {
+ cur_arg_param="";
+ }
+
+ if(cur_arg=="--") {
+ // Stop processing arguments. Anything that follows this argument is
+ // considered to be a hive to open
+ i++;
+ break;
+ } else if(cur_arg=="--dump-report") {
+ this->parsed_args.insert(cur_arg.mid(2),cur_arg_param);
+ continue;
+ } else if(cur_arg=="--fullscreen") {
+ this->parsed_args.insert(cur_arg.mid(2),cur_arg_param);
+ continue;
+ } else if(cur_arg=="--help") {
+ this->parsed_args.insert(cur_arg.mid(2),QString());
+ continue;
+ } else if(cur_arg=="--maximized") {
+ this->parsed_args.insert(cur_arg.mid(2),cur_arg_param);
+ continue;
+ } else if(cur_arg=="--version") {
+ this->parsed_args.insert(cur_arg.mid(2),QString());
+ continue;
+ } else {
+ // Unknown argument
+ this->SetError(QString("Unknown command line argument '%1'!")
+ .arg(cur_arg));
+ return false;
+ }
+ }
+ }
+
+ // Found argument not beginning with '-' or '--'
+ if(i+1==this->argc) {
+ // If this is the last argument, it should be a hive file
+ this->parsed_args.insert(QString("hive-file"),cur_arg);
+ break;
+ } else {
+ // If it isn't the last argument, there is an error
+ this->SetError(QString("Unknown command line argument '%1'!")
+ .arg(cur_arg));
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool ArgParser::IsSet(QString arg) {
+ return this->parsed_args.contains(arg);
+}
+
+QString ArgParser::GetArgVal(QString arg) {
+ // If arg is not in parsed_args, the following will return a
+ // "default-constructed value" which should be a QString() according to the
+ // docs.
+ return this->parsed_args[arg];
+}
+
+void ArgParser::SetError(QString msg) {
+ this->error_msg=msg;
+}
diff --git a/tags/fred-0.2.0/argparser.h b/tags/fred-0.2.0/argparser.h
new file mode 100644
index 0000000..c3547eb
--- /dev/null
+++ b/tags/fred-0.2.0/argparser.h
@@ -0,0 +1,45 @@
+/*******************************************************************************
+* fred Copyright (c) 2011-2020 by Gillen Daniel <gillen.dan@pinguin.lu> *
+* *
+* Forensic Registry EDitor (fred) is a cross-platform M$ registry hive editor *
+* with special feautures useful during forensic analysis. *
+* *
+* This program is free software: you can redistribute it and/or modify it *
+* under the terms of the GNU General Public License as published by the Free *
+* Software Foundation, either version 3 of the License, or (at your option) *
+* any later version. *
+* *
+* This program is distributed in the hope that it will be useful, but WITHOUT *
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or *
+* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for *
+* more details. *
+* *
+* You should have received a copy of the GNU General Public License along with *
+* this program. If not, see <http://www.gnu.org/licenses/>. *
+*******************************************************************************/
+
+#ifndef ARGPARSER_H
+#define ARGPARSER_H
+
+#include <QString>
+#include <QStringList>
+#include <QHash>
+
+class ArgParser {
+ public:
+ ArgParser(QStringList args);
+ QString GetErrorMsg();
+ bool ParseArgs();
+ bool IsSet(QString arg);
+ QString GetArgVal(QString arg);
+
+ private:
+ QStringList argv;
+ int argc;
+ QString error_msg;
+ QHash<QString,QString> parsed_args;
+
+ void SetError(QString msg=QString());
+};
+
+#endif // ARGPARSER_H
diff --git a/tags/fred-0.2.0/autogen.sh b/tags/fred-0.2.0/autogen.sh
new file mode 100755
index 0000000..0df1645
--- /dev/null
+++ b/tags/fred-0.2.0/autogen.sh
@@ -0,0 +1,328 @@
+#!/bin/bash
+
+# -----------------------------------------------------------------------------
+# Default command line options.
+# -----------------------------------------------------------------------------
+
+DEFOPT_CREATE_PACKAGE=0
+DEFOPT_JOBS=1
+DEFOPT_ONLY_BOOTSTRAP=0
+DEFOPT_PLATFORM="linux"
+DEFOPT_STATIC_HIVEX=0
+
+DEFOPT_LINUX_QMAKE=`which qmake`
+
+DEFOPT_WIN32_COMPILER_SUFFIX="i686-w64-mingw32"
+DEFOPT_WIN32_QMAKE="/opt/qt-4.8.4-mingw/bin/qmake"
+#DEFOPT_WIN32_DLL_PATH="/usr/i686-w64-mingw32/bin"
+DEFOPT_WIN32_QTDLL_PATH="/opt/qt-4.8.4-mingw/bin"
+
+# -----------------------------------------------------------------------------
+# ------------------ DO NOT CHANGE ANYTHING BELOW THIS LINE -------------------
+# -----------------------------------------------------------------------------
+
+WIN32_DLLS="libgcc_s_sjlj-1.dll libstdc++-6.dll libiconv-2.dll libwinpthread-1.dll"
+WIN32_QTDLLS="QtCore4.dll QtGui4.dll QtScript4.dll QtWebKit4.dll QtNetwork4.dll QtWebKit4.dll"
+
+# Try to make somehow sure we are running in bash and not some other shell
+if [ -z "$BASH_VERSION" ]; then
+ echo "ERROR: This script must be run in a bash shell! Try using \"bash $0\""
+ exit 1
+fi
+
+# -----------------------------------------------------------------------------
+# Function declarations
+# -----------------------------------------------------------------------------
+
+# Print usage and exit
+PrintUsage() {
+ echo
+ echo "Usage:"
+ echo " $0 [options]"
+ echo
+ echo "Options:"
+ echo " --create-package[=0..1] (Def.: $DEFOPT_CREATE_PACKAGE) : Package fred after building (Only supported on Debian/Ubuntu and Win32)."
+ echo " --help: Print this help message."
+ echo " --jobs=<number> (Def.: $DEFOPT_JOBS) : Specify how many make jobs should be run simultaneously."
+ echo " --linux-qmake=<qmakebin> (Def.: $DEFOPT_LINUX_QMAKE) : Specify the linux qmake binary to use."
+ echo " --only-bootstrap[=0..1] (Def.: $DEFOPT_ONLY_BOOTSTRAP) : Only bootstrap, but do not compile fred."
+ echo " --platform=<platform> (Def.: $DEFOPT_PLATFORM) : Specify the platform fred should be build for. Available platforms are 'linux' and 'win32'."
+ echo " --static-hivex[=0..1] (Def.: $DEFOPT_STATIC_HIVEX): Build and link in-tree hivex statically."
+ echo " --win32-compiler-suffix=<suffix> (Def.: $DEFOPT_WIN32_COMPILER_SUFFIX) : Specify the win32 crosscompiler suffix to use."
+# echo " --win32-dll-path=<path> (Def.: $DEFOPT_WIN32_DLL_PATH) : Specify path to mingw dll's"
+ echo " --win32-qmake=<qmakebin> (Def.: $DEFOPT_WIN32_QMAKE) : Specify the win32 qmake binary to use."
+ echo " --win32-qtdll-path=<path> (Def.: $DEFOPT_WIN32_QTDLL_PATH) : Specify path to Qt dll's"
+ echo
+ exit 1
+}
+
+# Extract argument value
+get_arg_val() {
+ local TMP=`echo "$1" | cut -d= -f2`
+ if [ "$1" = "$TMP" ]; then
+ # No arg specified for option, assume 1
+ echo 1
+ else
+ if [[ -z "$TMP" || $(echo -n "$TMP" | sed 's/[0-9]//g' | wc -c) -ne 0 ]]; then
+ echo "ERROR: Non-integer arg for option '$1' specified!" 1>&2
+ exit 1
+ fi
+ echo $TMP
+ fi
+}
+
+# -----------------------------------------------------------------------------
+# Parse command line args
+# -----------------------------------------------------------------------------
+
+# Load defaults
+OPT_CREATE_PACKAGE=$DEFOPT_CREATE_PACKAGE
+OPT_JOBS=$DEFOPT_JOBS
+OPT_ONLY_BOOTSTRAP=$DEFOPT_ONLY_BOOTSTRAP
+OPT_PLATFORM="$DEFOPT_PLATFORM"
+OPT_STATIC_HIVEX=$DEFOPT_STATIC_HIVEX
+OPT_LINUX_QMAKE="$DEFOPT_LINUX_QMAKE"
+OPT_WIN32_COMPILER_SUFFIX="$DEFOPT_WIN32_COMPILER_SUFFIX"
+OPT_WIN32_QMAKE="$DEFOPT_WIN32_QMAKE"
+#OPT_WIN32_DLL_PATH="$DEFOPT_WIN32_DLL_PATH"
+OPT_WIN32_QTDLL_PATH="$DEFOPT_WIN32_QTDLL_PATH"
+
+# Parse specified options
+shopt extglob &>/dev/null
+EXTGLOB=$?
+shopt -s extglob &>/dev/null
+while :; do
+ case "$1" in
+ --create-package?(=[01]))
+ OPT_CREATE_PACKAGE=$(get_arg_val "$1") || PrintUsage
+ shift
+ ;;
+ --help)
+ PrintUsage
+ ;;
+ --jobs=*)
+ OPT_JOBS=$(get_arg_val "$1") || PrintUsage
+ shift
+ ;;
+ --linux-qmake=*)
+ TMP=`echo "$1" | cut -d= -f2`
+ if [[ -z "$TMP" || "$1" = "$TMP" ]]; then
+ echo "ERROR: No option arg for '$1' specified!"
+ PrintUsage
+ fi
+ if [ ! -x "$TMP" ]; then
+ echo "ERROR: The specified linux qmake binary '$TMP' does not exist or is not executable!"
+ exit 1
+ fi
+ OPT_LINUX_QMAKE="$TMP"
+ shift
+ ;;
+ --only-bootstrap?(=[01]))
+ OPT_ONLY_BOOTSTRAP=$(get_arg_val "$1") || PrintUsage
+ shift
+ ;;
+ --platform=*)
+ TMP=`echo "$1" | cut -d= -f2`
+ if [[ -z "$TMP" || "$1" = "$TMP" ]]; then
+ echo "ERROR: No option arg for '$1' specified!"
+ PrintUsage
+ fi
+ TMP=`echo "$TMP" | tr "[A-Z]" "[a-z]"`
+ if [[ "$TMP" != "linux" && "$TMP" != "win32" ]]; then
+ echo "ERROR: Unsupported platform '$TMP' specified!"
+ PrintUsage
+ fi
+ OPT_PLATFORM="$TMP"
+ shift
+ ;;
+ --static-hivex?(=[01]))
+ OPT_STATIC_HIVEX=$(get_arg_val "$1") || PrintUsage
+ shift
+ ;;
+ --win32-compiler-suffix=*)
+ TMP=`echo "$1" | cut -d= -f2`
+ if [[ -z "$TMP" || "$1" = "$TMP" ]]; then
+ echo "ERROR: No option arg for '$1' specified!"
+ PrintUsage
+ fi
+ if [[ ! -x "$(which \"${TMP}-gcc\")" || ! -x "$(which \"${TMP}-g++\")" ]]; then
+ echo "ERROR: Couldn't find '${TMP}-gcc' or '${TMP}-g++'!"
+ echo "ERROR: The specified win32 compiler suffix does not seem to be correct!"
+ exit 1
+ fi
+ OPT_WIN32_COMPILER_SUFFIX="$TMP"
+ shift
+ ;;
+ --win32-qmake=*)
+ TMP=`echo "$1" | cut -d= -f2`
+ if [[ -z "$TMP" || "$1" = "$TMP" ]]; then
+ echo "ERROR: No option arg for '$1' specified!"
+ PrintUsage
+ fi
+ if [ ! -x "$TMP" ]; then
+ echo "ERROR: The specified win32 qmake binary '$TMP' does not exist or is not executable!"
+ exit 1
+ fi
+ OPT_WIN32_QMAKE="$TMP"
+ shift
+ ;;
+ --win32-qtdll-path=*)
+ TMP=`echo "$1" | cut -d= -f2`
+ if [[ -z "$TMP" || "$1" = "$TMP" ]]; then
+ echo "ERROR: No option arg for '$1' specified!"
+ PrintUsage
+ fi
+ if [ ! -d "$TMP" ]; then
+ echo "ERROR: The specified Qt dll path '$TMP' does not exist or is not a directory!"
+ exit 1
+ fi
+ OPT_WIN32_QTDLL_PATH="$TMP"
+ shift
+ ;;
+ --*)
+ echo "ERROR: Unknown option / Wrong option arg '$1' specified!" 1>&2
+ PrintUsage
+ ;;
+ *)
+ break
+ ;;
+ esac
+done
+if [ $EXTGLOB -ne 0 ]; then
+ shopt -u extglob &>/dev/null
+fi
+
+# -----------------------------------------------------------------------------
+# Check command line args
+# -----------------------------------------------------------------------------
+
+if [ "$OPT_PLATFORM" = "linux" ]; then
+ if [ ! -x "$OPT_LINUX_QMAKE" ]; then
+ echo "ERROR: Couldn't find qmake! Consider specifying it with --linux-qmake."
+ exit 1
+ fi
+fi
+
+if [ "$OPT_PLATFORM" = "win32" ]; then
+ if [ ! -x "$OPT_WIN32_QMAKE" ]; then
+ echo "ERROR: Couldn't find qmake! Consider specifying it with --win32-qmake."
+ exit 1
+ fi
+fi
+
+# -----------------------------------------------------------------------------
+# Build
+# -----------------------------------------------------------------------------
+
+# Get script directory and cd to it
+SCRIPT_DIR=`dirname "$0"`
+(
+ cd "$SCRIPT_DIR"
+
+ # When requested to build static, init, bootstrap, configure and make hivex
+ if [ $OPT_STATIC_HIVEX -eq 1 ]; then
+ echo "-----------------------------------------------------------------------------"
+ echo "Bootstrapping fred"
+ echo "-----------------------------------------------------------------------------"
+ (
+ cd ..
+ git submodule init
+ git submodule update
+ )
+
+ echo "-----------------------------------------------------------------------------"
+ echo "Bootstrapping hivex"
+ echo "-----------------------------------------------------------------------------"
+ (
+ cd hivex
+ if [ "$OPT_PLATFORM" = "linux" ]; then
+ ./autogen.sh --disable-ocaml --disable-perl --disable-python --disable-ruby --disable-shared || exit 1
+ fi
+ if [ "$OPT_PLATFORM" = "win32" ]; then
+ PKG_CONFIG_PATH=/usr/i686-w64-mingw32/lib/pkgconfig ./autogen.sh --host=$OPT_WIN32_COMPILER_SUFFIX --disable-ocaml --disable-perl --disable-python --disable-ruby --disable-shared || exit 1
+ fi
+ )
+ [ $? -ne 0 ] && exit 1
+
+ echo "-----------------------------------------------------------------------------"
+ echo "Building hivex"
+ echo "-----------------------------------------------------------------------------"
+ (
+ cd hivex
+ make clean &>/dev/null
+ make CFLAGS="-O2 -mno-ms-bitfields" -j$OPT_JOBS || exit 1
+ )
+ [ $? -ne 0 ] && [ "$OPT_PLATFORM" != "win32" ] && exit 1
+ fi
+
+ # Exit if we had only to bootstrap
+ [ $OPT_ONLY_BOOTSTRAP -eq 1 ] && exit 0
+
+ # Building is done while packaging on Linux
+ if [[ ! ( "$OPT_PLATFORM" = "linux" && $OPT_CREATE_PACKAGE -eq 1 ) ]]; then
+ echo "-----------------------------------------------------------------------------"
+ echo "Building fred"
+ echo "-----------------------------------------------------------------------------"
+ make distclean &>/dev/null
+ if [ "$OPT_PLATFORM" = "linux" ]; then
+ if [ $OPT_STATIC_HIVEX -eq 0 ]; then
+ $OPT_LINUX_QMAKE -qt=qt5 || exit 1
+ else
+ $OPT_LINUX_QMAKE -qt=qt5 HIVEX_STATIC=1 || exit 1
+ fi
+ make clean &>/dev/null
+ make -j$OPT_JOBS release || exit 1
+ fi
+ if [ "$OPT_PLATFORM" = "win32" ]; then
+ if [ $OPT_STATIC_HIVEX -eq 0 ]; then
+ $OPT_WIN32_QMAKE || exit 1
+ else
+ $OPT_WIN32_QMAKE HIVEX_STATIC=1 || exit 1
+ fi
+ make clean &>/dev/null
+ make -j$OPT_JOBS release || exit 1
+ fi
+ fi
+
+ # Exit if we don't need to package fred
+ [ $OPT_CREATE_PACKAGE -eq 0 ] && exit 0
+
+ echo "-----------------------------------------------------------------------------"
+ echo "Packaging fred"
+ echo "-----------------------------------------------------------------------------"
+ if [ "$OPT_PLATFORM" = "linux" ]; then
+ if [ ! -x "$(which dpkg-buildpackage)" ]; then
+ echo "ERROR: Couldn't find dpkg-buildpackage!"
+ exit 1
+ fi
+ dpkg-buildpackage -rfakeroot -b || exit 1
+ fi
+ if [ "$OPT_PLATFORM" = "win32" ]; then
+ # Delete old package directory if it exists and (re)create it
+ rm -rf fred-win32 &>/dev/null
+ mkdir fred-win32
+ # Copy fred.exe
+ cp -v release/fred.exe fred-win32/
+ # Find and copy mingw dll's
+ for F in $WIN32_DLLS; do
+ find /usr -name "$F" -path "*/$OPT_WIN32_COMPILER_SUFFIX/*" -exec cp -v "{}" fred-win32/ \; || exit 1
+ done
+ # Copy Qt dll's
+ for F in $WIN32_QTDLLS; do
+ cp -v "$OPT_WIN32_QTDLL_PATH/$F" fred-win32/ || exit 1
+ done
+ # Copy report templates
+ cp -rv report_templates fred-win32/ || exit 1
+ fi
+)
+
+if [ $? -eq 0 ]; then
+ echo "-----------------------------------------------------------------------------"
+ echo "All done."
+ echo "-----------------------------------------------------------------------------"
+else
+ echo "-----------------------------------------------------------------------------"
+ echo "An error occured while building! See output above for details."
+ echo "-----------------------------------------------------------------------------"
+fi
+
diff --git a/tags/fred-0.2.0/compileinfo.sh b/tags/fred-0.2.0/compileinfo.sh
new file mode 100755
index 0000000..f1c0eb8
--- /dev/null
+++ b/tags/fred-0.2.0/compileinfo.sh
@@ -0,0 +1,46 @@
+#!/bin/bash
+
+PWD=""
+if [ $# -eq 1 ]; then
+ PWD="$1"
+ PWD="${PWD%/}/"
+fi
+
+echo '// Automatically generated file. See project file and compileinfo.sh for further informations.'
+#head -n 1 debian/changelog | awk '{
+# Version = $2
+# gsub ("\\(", "", Version)
+# gsub ("\\)", "", Version)
+# print "const char *pCompileInfoVersion = \"" Version "\";"}'
+
+echo '#define APP_NAME "fred"'
+echo '#define APP_NAME_LONG "Forensic Registry EDitor"'
+echo '#define APP_TITLE "Forensic Registry EDitor (fred)"'
+echo '#define APP_COPYRIGHT "Copyright (c) 2011-2020 by Gillen Daniel"'
+echo '#define APP_DEVELOPPER_EMAIL "gillen.dan@pinguin.lu"'
+echo '#define APP_DESCRIPTION "Forensic Registry EDitor (fred) is a cross-platform M$ registry hive editor with special features useful during forensic analysis."'
+date '+#define APP_COMPILETIME "%Y/%m/%d %H:%M:%S"'
+
+GOT_VERSION=0
+
+if [[ $GOT_VERSION -eq 0 && -f "$PWD"debian/changelog ]]; then
+ # Get version and release timestamp from debian/changelog file
+ CUR_LINE=0
+ while read LINE; do
+ CUR_LINE=$(($CUR_LINE+1))
+ if [ $CUR_LINE -eq 1 ]; then
+ # first line contains version
+ echo "$LINE" | awk '{ Version = $2
+ gsub ("\\(", "", Version)
+ gsub ("\\)", "", Version)
+ print "#define APP_VERSION \"" Version "\"" }'
+ break
+ fi
+ done <"$PWD"debian/changelog
+ GOT_VERSION=1
+fi
+
+if [ $GOT_VERSION -eq 0 ]; then
+ echo '#define APP_VERSION "0.0.0alpha0"'
+fi
+
diff --git a/tags/fred-0.2.0/datainterpretertable.cpp b/tags/fred-0.2.0/datainterpretertable.cpp
new file mode 100644
index 0000000..0f47519
--- /dev/null
+++ b/tags/fred-0.2.0/datainterpretertable.cpp
@@ -0,0 +1,111 @@
+/*******************************************************************************
+* fred Copyright (c) 2011-2020 by Gillen Daniel <gillen.dan@pinguin.lu> *
+* *
+* Forensic Registry EDitor (fred) is a cross-platform M$ registry hive editor *
+* with special feautures useful during forensic analysis. *
+* *
+* This program is free software: you can redistribute it and/or modify it *
+* under the terms of the GNU General Public License as published by the Free *
+* Software Foundation, either version 3 of the License, or (at your option) *
+* any later version. *
+* *
+* This program is distributed in the hope that it will be useful, but WITHOUT *
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or *
+* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for *
+* more details. *
+* *
+* You should have received a copy of the GNU General Public License along with *
+* this program. If not, see <http://www.gnu.org/licenses/>. *
+*******************************************************************************/
+
+#include <QHeaderView>
+#include <QFontMetrics>
+#include <QMenu>
+#include <QApplication>
+#include <QClipboard>
+
+#include "datainterpretertable.h"
+
+DataInterpreterTable::DataInterpreterTable(QWidget *p_parent)
+ : QTableWidget(p_parent)
+{
+ this->setColumnCount(2);
+ this->setTextElideMode(Qt::ElideNone);
+ this->horizontalHeader()->setHidden(true);
+ this->verticalHeader()->setHidden(true);
+ this->setSelectionBehavior(QAbstractItemView::SelectRows);
+ this->setSelectionMode(QAbstractItemView::SingleSelection);
+
+ // Create context menu actions
+ this->p_action_copy_value=new QAction(tr("Copy value"),this);
+ this->connect(this->p_action_copy_value,
+ SIGNAL(triggered()),
+ this,
+ SLOT(SlotCopyValue()));
+}
+
+DataInterpreterTable::~DataInterpreterTable() {
+ // Free table widget items
+ this->ClearValues();
+
+ // Delete context menu actions
+ delete this->p_action_copy_value;
+}
+
+void DataInterpreterTable::AddValue(QString name, QString value) {
+ QTableWidgetItem *p_name_item=new QTableWidgetItem(name);
+ p_name_item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
+ QTableWidgetItem *p_value_item=new QTableWidgetItem(value);
+ p_value_item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
+ this->setRowCount(this->rowCount()+1);
+ this->setItem(this->rowCount()-1,0,p_name_item);
+ this->setItem(this->rowCount()-1,1,p_value_item);
+ this->resizeColumnsToContents();
+ this->resizeRowsToContents();
+}
+
+void DataInterpreterTable::ClearValues() {
+ // Free all items
+ while(this->rowCount()>0) {
+ delete this->item(0,0);
+ delete this->item(0,1);
+ this->setRowCount(this->rowCount()-1);
+ }
+}
+
+int DataInterpreterTable::sizeHintForColumn(int column) const {
+ int size_hint=0;
+ int i=0;
+ int item_width=0;
+ QFontMetrics fm(this->fontMetrics());
+
+ // Find string that needs the most amount of space
+ for(i=0;i<this->rowCount();i++) {
+ item_width=fm.width(this->item(i,column)->text())+10;
+ if(item_width>size_hint) size_hint=item_width;
+ }
+
+ return size_hint;
+}
+
+void DataInterpreterTable::contextMenuEvent(QContextMenuEvent *p_event) {
+ // Only show context menu when a node is selected
+ if(this->selectedIndexes().count()!=2) return;
+ // Only show context menu when user clicked on selected row
+ if(!(this->indexAt(p_event->pos())==this->selectedIndexes().at(0) ||
+ this->indexAt(p_event->pos())==this->selectedIndexes().at(1)))
+ {
+ return;
+ }
+
+ // Create context menu and add actions
+ QMenu context_menu(this);
+ context_menu.addAction(this->p_action_copy_value);
+ context_menu.exec(p_event->globalPos());
+}
+
+void DataInterpreterTable::SlotCopyValue() {
+ QApplication::clipboard()->
+ setText(this->selectedIndexes().at(1).data().toString(),
+ QClipboard::Clipboard);
+}
diff --git a/tags/fred-0.2.0/datainterpretertable.h b/tags/fred-0.2.0/datainterpretertable.h
new file mode 100644
index 0000000..4ec9053
--- /dev/null
+++ b/tags/fred-0.2.0/datainterpretertable.h
@@ -0,0 +1,68 @@
+/*******************************************************************************
+* fred Copyright (c) 2011-2020 by Gillen Daniel <gillen.dan@pinguin.lu> *
+* *
+* Forensic Registry EDitor (fred) is a cross-platform M$ registry hive editor *
+* with special feautures useful during forensic analysis. *
+* *
+* This program is free software: you can redistribute it and/or modify it *
+* under the terms of the GNU General Public License as published by the Free *
+* Software Foundation, either version 3 of the License, or (at your option) *
+* any later version. *
+* *
+* This program is distributed in the hope that it will be useful, but WITHOUT *
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or *
+* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for *
+* more details. *
+* *
+* You should have received a copy of the GNU General Public License along with *
+* this program. If not, see <http://www.gnu.org/licenses/>. *
+*******************************************************************************/
+
+#ifndef DATAINTERPRETERTABLE_H
+#define DATAINTERPRETERTABLE_H
+
+#include <QWidget>
+#include <QTableWidget>
+#include <QContextMenuEvent>
+#include <QAction>
+
+class DataInterpreterTable : public QTableWidget {
+ Q_OBJECT
+
+ public:
+ DataInterpreterTable(QWidget *p_parent=0);
+ ~DataInterpreterTable();
+
+ /*
+ * AddValue
+ *
+ * Add a value pair (name,value) to data interprter.
+ */
+ void AddValue(QString name, QString value);
+ /*
+ * ClearValues
+ *
+ * Remove all value pairs from table
+ */
+ void ClearValues();
+
+ protected:
+ /*
+ * sizeHintForColumn
+ *
+ * Needed reimplementation in order to allow resizeColumnsToContent
+ * to resize hidden columns too.
+ */
+ int sizeHintForColumn(int column) const;
+ void contextMenuEvent(QContextMenuEvent *p_event);
+
+ private:
+ QAction *p_action_copy_value;
+
+ private slots:
+ void SlotCopyValue();
+
+
+};
+
+#endif // DATAINTERPRETERTABLE_H
diff --git a/tags/fred-0.2.0/datainterpreterwidget.cpp b/tags/fred-0.2.0/datainterpreterwidget.cpp
new file mode 100644
index 0000000..d5cddac
--- /dev/null
+++ b/tags/fred-0.2.0/datainterpreterwidget.cpp
@@ -0,0 +1,201 @@
+/*******************************************************************************
+* fred Copyright (c) 2011-2020 by Gillen Daniel <gillen.dan@pinguin.lu> *
+* *
+* Forensic Registry EDitor (fred) is a cross-platform M$ registry hive editor *
+* with special feautures useful during forensic analysis. *
+* *
+* This program is free software: you can redistribute it and/or modify it *
+* under the terms of the GNU General Public License as published by the Free *
+* Software Foundation, either version 3 of the License, or (at your option) *
+* any later version. *
+* *
+* This program is distributed in the hope that it will be useful, but WITHOUT *
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or *
+* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for *
+* more details. *
+* *
+* You should have received a copy of the GNU General Public License along with *
+* this program. If not, see <http://www.gnu.org/licenses/>. *
+*******************************************************************************/
+
+#include "datainterpreterwidget.h"
+#include "registryhive.h"
+
+DataInterpreterWidget::DataInterpreterWidget(QWidget *p_parent) :
+ QWidget(p_parent)
+{
+ // Init private vars
+ this->data=QByteArray();
+ this->endianness=DataInterpreterWidget::Endianness_LittleEndian;
+
+ // Set widget layout. Setting it's parent to "this" will also call
+ // this->SetLayout.
+ this->p_widget_layout=new QVBoxLayout(this);
+
+ // Create sub-widgets
+ this->p_data_interpreter_table=new DataInterpreterTable();
+ this->p_endianness_selector_layout=new QHBoxLayout();
+ this->p_endianness_selector_le=new QRadioButton(tr("Little endian"));
+ this->p_endianness_selector_be=new QRadioButton(tr("Big endian"));
+
+ // Add endianness selector buttons to their layout
+ this->p_endianness_selector_layout->addWidget(this->p_endianness_selector_le);
+ this->p_endianness_selector_layout->addWidget(this->p_endianness_selector_be);
+
+ // Add sub-widgets to our layout
+ this->p_widget_layout->addWidget(this->p_data_interpreter_table);
+ this->p_widget_layout->addLayout(this->p_endianness_selector_layout);
+
+ // Configure widget and sub-widgets
+ this->setContentsMargins(0,0,0,0);
+ this->p_widget_layout->setContentsMargins(0,0,0,0);
+ this->p_endianness_selector_layout->setContentsMargins(0,0,0,0);
+ this->p_endianness_selector_le->setContentsMargins(0,0,0,0);
+ this->p_endianness_selector_be->setContentsMargins(0,0,0,0);
+
+ // Set initial endianness selector state
+ this->p_endianness_selector_le->setChecked(
+ (this->endianness==DataInterpreterWidget::Endianness_LittleEndian));
+ this->p_endianness_selector_be->setChecked(
+ (this->endianness==DataInterpreterWidget::Endianness_BigEndian));
+
+ // Connect signals
+ this->connect(this->p_endianness_selector_le,
+ SIGNAL(clicked(bool)),
+ this,
+ SLOT(SlotEndiannessSelectorLeClicked(bool)));
+ this->connect(this->p_endianness_selector_be,
+ SIGNAL(clicked(bool)),
+ this,
+ SLOT(SlotEndiannessSelectorBeClicked(bool)));
+}
+
+DataInterpreterWidget::~DataInterpreterWidget() {
+ delete this->p_endianness_selector_le;
+ delete this->p_endianness_selector_be;
+ delete this->p_endianness_selector_layout;
+ delete this->p_data_interpreter_table;
+ delete this->p_widget_layout;
+}
+
+void DataInterpreterWidget::SetData(QByteArray new_data) {
+ // Save new data and interpret it
+ this->data=new_data;
+ this->InterpretData();
+}
+
+void DataInterpreterWidget::InterpretData() {
+ // Get data length
+ int data_length=this->data.size();
+
+ // Remove old values from data interpreter table
+ this->p_data_interpreter_table->ClearValues();
+
+ if(data_length>=1) {
+ this->p_data_interpreter_table->AddValue("int8:",
+ RegistryHive::KeyValueToString(
+ this->data,
+ "int8"));
+ this->p_data_interpreter_table->AddValue("uint8:",
+ RegistryHive::KeyValueToString(
+ this->data,
+ "uint8"));
+ }
+ if(data_length>=2) {
+ this->p_data_interpreter_table->AddValue(
+ "int16:",
+ RegistryHive::KeyValueToString(
+ this->data,
+ "int16",
+ 0,
+ 0,
+ this->endianness==DataInterpreterWidget::Endianness_LittleEndian));
+ this->p_data_interpreter_table->AddValue(
+ "uint16:",
+ RegistryHive::KeyValueToString(
+ this->data,
+ "uint16",
+ 0,
+ 0,
+ this->endianness==DataInterpreterWidget::Endianness_LittleEndian));
+ }
+ if(data_length>=4) {
+ this->p_data_interpreter_table->AddValue(
+ "int32:",
+ RegistryHive::KeyValueToString(
+ this->data,
+ "int32",
+ 0,
+ 0,
+ this->endianness==DataInterpreterWidget::Endianness_LittleEndian));
+ this->p_data_interpreter_table->AddValue(
+ "uint32:",
+ RegistryHive::KeyValueToString(
+ this->data,
+ "uint32",
+ 0,
+ 0,
+ this->endianness==DataInterpreterWidget::Endianness_LittleEndian));
+ this->p_data_interpreter_table->AddValue(
+ "unixtime:",
+ RegistryHive::KeyValueToString(
+ this->data,
+ "unixtime",
+ 0,
+ 0,
+ this->endianness==DataInterpreterWidget::Endianness_LittleEndian));
+ }
+ if(data_length>=8) {
+ this->p_data_interpreter_table->AddValue(
+ "int64:",
+ RegistryHive::KeyValueToString(
+ this->data,
+ "int64",
+ 0,
+ 0,
+ this->endianness==DataInterpreterWidget::Endianness_LittleEndian));
+ this->p_data_interpreter_table->AddValue(
+ "uint64:",
+ RegistryHive::KeyValueToString(
+ this->data,
+ "uint64",
+ 0,
+ 0,
+ this->endianness==DataInterpreterWidget::Endianness_LittleEndian));
+/*
+ TODO: Check how one could implement this
+ this->p_data_interpreter_table->AddValue(
+ "unixtime64:",
+ RegistryHive::KeyValueToString(
+ this->data,
+ "unixtime64",
+ 0,
+ 0,
+ this->endianness==DataInterpreterWidget::Endianness_LittleEndian));
+*/
+ this->p_data_interpreter_table->AddValue(
+ "filetime64:",
+ RegistryHive::KeyValueToString(
+ this->data,
+ "filetime",
+ 0,
+ 0,
+ this->endianness==DataInterpreterWidget::Endianness_LittleEndian));
+ }
+}
+
+void DataInterpreterWidget::SlotEndiannessSelectorLeClicked(bool checked) {
+ if(checked) {
+ // Save selected endianness and update interpreted values
+ this->endianness=DataInterpreterWidget::Endianness_LittleEndian;
+ this->InterpretData();
+ }
+}
+
+void DataInterpreterWidget::SlotEndiannessSelectorBeClicked(bool checked) {
+ if(checked) {
+ // Save selected endianness and update interpreted values
+ this->endianness=DataInterpreterWidget::Endianness_BigEndian;
+ this->InterpretData();
+ }
+}
diff --git a/tags/fred-0.2.0/datainterpreterwidget.h b/tags/fred-0.2.0/datainterpreterwidget.h
new file mode 100644
index 0000000..8cd4036
--- /dev/null
+++ b/tags/fred-0.2.0/datainterpreterwidget.h
@@ -0,0 +1,72 @@
+/*******************************************************************************
+* fred Copyright (c) 2011-2020 by Gillen Daniel <gillen.dan@pinguin.lu> *
+* *
+* Forensic Registry EDitor (fred) is a cross-platform M$ registry hive editor *
+* with special feautures useful during forensic analysis. *
+* *
+* This program is free software: you can redistribute it and/or modify it *
+* under the terms of the GNU General Public License as published by the Free *
+* Software Foundation, either version 3 of the License, or (at your option) *
+* any later version. *
+* *
+* This program is distributed in the hope that it will be useful, but WITHOUT *
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or *
+* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for *
+* more details. *
+* *
+* You should have received a copy of the GNU General Public License along with *
+* this program. If not, see <http://www.gnu.org/licenses/>. *
+*******************************************************************************/
+
+#ifndef DATAINTERPRETERWIDGET_H
+#define DATAINTERPRETERWIDGET_H
+
+#include <QWidget>
+#include <QVBoxLayout>
+#include <QHBoxLayout>
+#include <QRadioButton>
+#include <QString>
+#include <QByteArray>
+
+#include "datainterpretertable.h"
+
+class DataInterpreterWidget : public QWidget {
+ Q_OBJECT
+
+ public:
+ enum Endianness {
+ Endianness_LittleEndian=0,
+ Endianness_BigEndian
+ };
+
+ explicit DataInterpreterWidget(QWidget *p_parent=0);
+ ~DataInterpreterWidget();
+
+ /*
+ * SetData
+ *
+ * Set data to be interpreted (will also interpret it).
+ */
+ void SetData(QByteArray new_data);
+
+ private:
+ // Widget layout
+ QVBoxLayout *p_widget_layout;
+ // Sub-widgets
+ DataInterpreterTable *p_data_interpreter_table;
+ QHBoxLayout *p_endianness_selector_layout;
+ QRadioButton *p_endianness_selector_le;
+ QRadioButton *p_endianness_selector_be;
+ // Vars
+ QByteArray data;
+ int endianness;
+
+ void InterpretData();
+
+ private slots:
+ void SlotEndiannessSelectorLeClicked(bool checked);
+ void SlotEndiannessSelectorBeClicked(bool checked);
+
+};
+
+#endif // DATAINTERPRETERWIDGET_H
diff --git a/tags/fred-0.2.0/debian/changelog b/tags/fred-0.2.0/debian/changelog
new file mode 100644
index 0000000..fdc57b1
--- /dev/null
+++ b/tags/fred-0.2.0/debian/changelog
@@ -0,0 +1,74 @@
+fred (0.2.0) stable; urgency=low
+
+ * Ported to Qt5. Thanks to Wincent Balin for doing all the work and providing me
+ the patches.
+
+ -- Gillen Daniel <Gillen.Dan@pinguin.lu> Mon, 16 Mar 2020 13:00:00 +0100
+
+fred (0.1.1) stable; urgency=low
+
+ * Added "Last added" field to NTUSER_TypedUrls report
+
+ -- Daniel Gillen <gillen.dan@pinguin.lu> Tue, 30 Sep 2014 15:15:00 +0200
+
+fred (0.1.0) stable; urgency=low
+
+ * Minor Qt fixes
+
+ -- Daniel Gillen <gillen.dan@pinguin.lu> Tue, 30 Sep 2014 14:00:00 +0200
+
+fred (0.1.0beta5) stable; urgency=low
+
+ * Added write support
+ * New reporting system
+
+ -- Daniel Gillen <gillen.dan@pinguin.lu> Thu, 18 Jun 2013 15:00:00 +0200
+
+fred (0.1.0beta4) unstable; urgency=low
+
+ * Fixed some minor UI bugs
+ * Massive code cleanup in mainwindow.cpp
+ * Added ability to switch data interpreter's endianness
+ * Added ability in hex editor to select and copy selected bytes / text
+
+ -- Daniel Gillen <gillen.dan@pinguin.lu> Mon, 25 Jun 2012 00:00:00 +0200
+
+fred (0.1.0beta3) unstable; urgency=low
+
+ * Added search functionality
+ * Added various context menus to copy values to clipboard
+ * Now linking statically against libhivex to support older Debian / Ubuntu distros
+ * Some small fixes to ease portability
+
+ -- Daniel Gillen <gillen.dan@pinguin.lu> Sun, 04 Sep 2011 00:15:00 +0200
+
+fred (0.1.0beta2) unstable; urgency=low
+
+ * Fixed some more bugs and subclassed QTreeView and QTableView
+
+ -- Daniel Gillen <gillen.dan@pinguin.lu> Tue, 23 Aug 2011 17:00:00 +0200
+
+fred (0.1.0beta1) unstable; urgency=low
+
+ * Fixed some minor bugs and added more report templates
+
+ -- Daniel Gillen <gillen.dan@pinguin.lu> Mon, 22 Aug 2011 08:00:00 +0200
+
+fred (0.1.0alpha3) unstable; urgency=low
+
+ * Added data report engine and 2 basic report templates
+
+ -- Daniel Gillen <gillen.dan@pinguin.lu> Wed, 17 Aug 2011 11:30:00 +0200
+
+fred (0.1.0alpha2) unstable; urgency=low
+
+ * Integrated hexeditor into main window.
+ * Added data interpreters
+
+ -- Daniel Gillen <gillen.dan@pinguin.lu> Tue, 09 Aug 2011 17:00:00 +0200
+
+fred (0.1.0alpha1) unstable; urgency=low
+
+ * First public release
+
+ -- Daniel Gillen <gillen.dan@pinguin.lu> Sat, 06 Aug 2011 22:00:00 +0200
diff --git a/tags/fred-0.2.0/debian/compat b/tags/fred-0.2.0/debian/compat
new file mode 100644
index 0000000..7ed6ff8
--- /dev/null
+++ b/tags/fred-0.2.0/debian/compat
@@ -0,0 +1 @@
+5
diff --git a/tags/fred-0.2.0/debian/control b/tags/fred-0.2.0/debian/control
new file mode 100644
index 0000000..90bb441
--- /dev/null
+++ b/tags/fred-0.2.0/debian/control
@@ -0,0 +1,27 @@
+Source: fred
+Section: x11
+Priority: optional
+Maintainer: Gillen Daniel <gillen.dan@pinguin.lu>
+Uploaders: Gillen Daniel <gillen.dan@pinguin.lu>
+Build-Depends: debhelper (>= 5), qtbase5-dev (>= 5.8), qtscript5-dev, qtwebengine5-dev, qtpositioning5-dev, libhivex-dev
+Standards-Version: 3.8.2
+Homepage: https://www.pinguin.lu
+
+Package: fred
+Architecture: any
+Depends: ${shlibs:Depends}
+Recommends: fred-reports
+Description: Forensic Registry EDitor
+ Forensic Registry EDitor (fred) is a cross-platform M$ registry
+ hive editor with special features useful during forensic
+ analysis.
+
+Package: fred-reports
+Architecture: any
+Depends: ${shlibs:Depends}
+Description: Forensic Registry EDitor
+ Forensic Registry EDitor (fred) is a cross-platform M$ registry
+ hive editor with special features useful during forensic
+ analysis.
+ .
+ This package contains the report-templates for fred.
diff --git a/tags/fred-0.2.0/debian/control.shared b/tags/fred-0.2.0/debian/control.shared
new file mode 100644
index 0000000..3fd6e4d
--- /dev/null
+++ b/tags/fred-0.2.0/debian/control.shared
@@ -0,0 +1,27 @@
+Source: fred
+Section: x11
+Priority: optional
+Maintainer: Gillen Daniel <gillen.dan@pinguin.lu>
+Uploaders: Gillen Daniel <gillen.dan@pinguin.lu>
+Build-Depends: debhelper (>= 5), libqt4-dev, libhivex-dev
+Standards-Version: 3.8.2
+Homepage: https://www.pinguin.lu
+
+Package: fred
+Architecture: any
+Depends: ${shlibs:Depends}
+Recommends: fred-reports
+Description: Forensic Registry EDitor
+ Forensic Registry EDitor (fred) is a cross-platform M$ registry
+ hive editor with special feautures useful during forensic
+ analysis.
+
+Package: fred-reports
+Architecture: any
+Depends: ${shlibs:Depends}
+Description: Forensic Registry EDitor
+ Forensic Registry EDitor (fred) is a cross-platform M$ registry
+ hive editor with special feautures useful during forensic
+ analysis.
+ .
+ This package contains the report-templates for fred.
diff --git a/tags/fred-0.2.0/debian/copyright b/tags/fred-0.2.0/debian/copyright
new file mode 100644
index 0000000..d9710fd
--- /dev/null
+++ b/tags/fred-0.2.0/debian/copyright
@@ -0,0 +1,28 @@
+This package was debianised by Daniel Gillen <gillen.dan@pinguin.lu>
+
+Upstream Author: Daniel Gillen <gillen.dan@pinguin.lu>
+
+Copyright: Copyright (c) 2001 by Daniel Gillen <gillen.dan@pinguin.lu>
+
+License:
+
+ This package is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This package is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this package; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+On Debian systems, the complete text of the GNU General
+Public License can be found in `/usr/share/common-licenses/GPL-2'.
+
+The Debian packaging is © 2008 by Guy Voncken <vogu00@gmail.com>
+and © 2009 by Michael Prokop <mika@debian.org>
+and is licensed under the GPL, see above.
diff --git a/tags/fred-0.2.0/debian/fred-reports.install b/tags/fred-0.2.0/debian/fred-reports.install
new file mode 100644
index 0000000..42ea7c5
--- /dev/null
+++ b/tags/fred-0.2.0/debian/fred-reports.install
@@ -0,0 +1,17 @@
+report_templates/NTUSER_Autoruns.qs usr/share/fred/report_templates/
+report_templates/NTUSER_LaunchedApplications.qs usr/share/fred/report_templates/
+report_templates/NTUSER_RecentDocs.qs usr/share/fred/report_templates/
+report_templates/NTUSER_TypedUrls.qs usr/share/fred/report_templates/
+report_templates/NTUSER_Windows7_SearchKeywords.qs usr/share/fred/report_templates/
+report_templates/NTUSER_Windows7_TypedPaths.qs usr/share/fred/report_templates/
+report_templates/NTUSER_WindowsLiveAccounts.qs usr/share/fred/report_templates/
+report_templates/SAM_UserAccounts.qs usr/share/fred/report_templates/
+report_templates/SOFTWARE_Autoruns.qs usr/share/fred/report_templates/
+report_templates/SOFTWARE_ProfileList.qs usr/share/fred/report_templates/
+report_templates/SOFTWARE_WindowsVersion.qs usr/share/fred/report_templates/
+report_templates/SYSTEM_BackupRestore.qs usr/share/fred/report_templates/
+report_templates/SYSTEM_CurrentNetworkSettings.qs usr/share/fred/report_templates/
+report_templates/SYSTEM_Services.qs usr/share/fred/report_templates/
+report_templates/SYSTEM_ShutdownTime.qs usr/share/fred/report_templates/
+report_templates/SYSTEM_SystemTimeInfo.qs usr/share/fred/report_templates/
+report_templates/SYSTEM_UsbStorageDevices.qs usr/share/fred/report_templates/
diff --git a/tags/fred-0.2.0/debian/fred.dirs b/tags/fred-0.2.0/debian/fred.dirs
new file mode 100644
index 0000000..7344f38
--- /dev/null
+++ b/tags/fred-0.2.0/debian/fred.dirs
@@ -0,0 +1,4 @@
+usr/bin
+usr/share/applications
+usr/share/pixmaps
+usr/share/fred
diff --git a/tags/fred-0.2.0/debian/fred.install b/tags/fred-0.2.0/debian/fred.install
new file mode 100644
index 0000000..7b9c38e
--- /dev/null
+++ b/tags/fred-0.2.0/debian/fred.install
@@ -0,0 +1,2 @@
+resources/fred.desktop usr/share/applications/
+resources/fred.png usr/share/pixmaps/
diff --git a/tags/fred-0.2.0/debian/fred.menu b/tags/fred-0.2.0/debian/fred.menu
new file mode 100644
index 0000000..0e5adb1
--- /dev/null
+++ b/tags/fred-0.2.0/debian/fred.menu
@@ -0,0 +1,3 @@
+?package(fred):needs="X11" section="Applications/System/Security"\
+ title="fred" command="/usr/bin/fred"\
+ hints="System"
diff --git a/tags/fred-0.2.0/debian/rules b/tags/fred-0.2.0/debian/rules
new file mode 100755
index 0000000..c96ada0
--- /dev/null
+++ b/tags/fred-0.2.0/debian/rules
@@ -0,0 +1,98 @@
+#!/usr/bin/make -f
+# -*- makefile -*-
+# Sample debian/rules that uses debhelper.
+# This file was originally written by Joey Hess and Craig Small.
+# As a special exception, when this file is copied by dh-make into a
+# dh-make output file, you may use that output file without restriction.
+# This special exception was added by Craig Small in version 0.37 of dh-make.
+
+# Uncomment this to turn on verbose mode.
+#export DH_VERBOSE=1
+
+configure: configure-stamp
+configure-stamp:
+ dh_testdir
+ # Add here commands to configure the package.
+ qmake -qt=qt5 DEFINES+="SYSTEM_REPORT_TEMPLATE_DIR=\'\\\"/usr/share/fred/report_templates\\\"\'"
+
+ touch configure-stamp
+
+
+build: build-stamp
+
+build-stamp: configure-stamp
+ dh_testdir
+
+ # Add here commands to compile the package.
+ # Optimised make for fast compilation on multi-core machines
+ $(MAKE) -j$(shell cat /proc/cpuinfo | grep ^processor | wc -l)
+ lrelease -qt=qt5 fred.pro
+
+ touch $@
+
+clean:
+ dh_testdir
+ dh_testroot
+ rm -f build-stamp configure-stamp
+ # dpkg-buildpackage starts with cleaning, so we have to be sure that there's a Makefile (and thus call qmake-qt4)
+ qmake -qt=qt5
+
+ # Add here commands to clean up after the build process.
+ $(MAKE) clean
+ # remove leftover files:
+ rm -f fred
+ rm -f compileinfo.cpp
+ #rm -f fred_*.qm
+ dh_clean
+
+install: build
+ dh_testdir
+ dh_testroot
+ dh_clean -k
+ dh_installdirs
+
+ # Add here commands to install the package into debian/fred.
+ # $(MAKE) DESTDIR=$(CURDIR)/debian/fred install
+
+ cp fred debian/fred/usr/bin
+ #cp fred_*.qm debian/fred/usr/share/fred
+
+
+# Build architecture-independent files here.
+binary-indep: build install
+# We have nothing to do by default.
+
+# Build architecture-dependent files here.
+binary-arch: build install
+ dh_testdir
+ dh_testroot
+ dh_installchangelogs
+# dh_installdocs
+# dh_installexamples
+ dh_install
+ dh_installmenu
+# dh_installdebconf
+# dh_installlogrotate
+# dh_installemacsen
+# dh_installpam
+# dh_installmime
+# dh_python
+# dh_installinit
+# dh_installcron
+# dh_installinfo
+# dh_installman
+ dh_link
+ dh_strip
+ dh_compress
+ dh_fixperms
+# dh_perl
+# dh_makeshlibs
+ dh_installdeb
+ dh_shlibdeps
+ dh_gencontrol
+ dh_md5sums
+ dh_builddeb
+
+binary: binary-indep binary-arch
+.PHONY: build clean binary-indep binary-arch binary install configure
+
diff --git a/tags/fred-0.2.0/dlgabout.cpp b/tags/fred-0.2.0/dlgabout.cpp
new file mode 100644
index 0000000..31ae695
--- /dev/null
+++ b/tags/fred-0.2.0/dlgabout.cpp
@@ -0,0 +1,74 @@
+/*******************************************************************************
+* fred Copyright (c) 2011-2020 by Gillen Daniel <gillen.dan@pinguin.lu> *
+* *
+* Forensic Registry EDitor (fred) is a cross-platform M$ registry hive editor *
+* with special feautures useful during forensic analysis. *
+* *
+* This program is free software: you can redistribute it and/or modify it *
+* under the terms of the GNU General Public License as published by the Free *
+* Software Foundation, either version 3 of the License, or (at your option) *
+* any later version. *
+* *
+* This program is distributed in the hope that it will be useful, but WITHOUT *
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or *
+* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for *
+* more details. *
+* *
+* You should have received a copy of the GNU General Public License along with *
+* this program. If not, see <http://www.gnu.org/licenses/>. *
+*******************************************************************************/
+
+#include "dlgabout.h"
+#include "ui_dlgabout.h"
+
+#include "compileinfo.h"
+
+DlgAbout::DlgAbout(QWidget *parent) :
+ QDialog(parent),
+ m_ui(new Ui::DlgAbout)
+{
+ m_ui->setupUi(this);
+ this->setWindowTitle(tr("About %1").arg(APP_NAME));
+
+ // Update dialog with current infos
+ this->m_ui->LblAbout->setText(
+ this->m_ui->LblAbout->text().replace("%APP_NAME_LONG%",APP_NAME_LONG));
+ this->m_ui->LblAbout->setText(
+ this->m_ui->LblAbout->text().replace("%APP_NAME%",APP_NAME));
+ this->m_ui->LblAbout->setText(
+ this->m_ui->LblAbout->text().replace("%APP_COPYRIGHT%",APP_COPYRIGHT));
+ this->m_ui->TextEditInfo->setPlainText(
+ this->m_ui->TextEditInfo->toPlainText().replace("%APP_NAME%",APP_NAME));
+ this->m_ui->TextEditInfo->setPlainText(
+ this->m_ui->TextEditInfo->toPlainText().replace("%APP_VERSION%",
+ APP_VERSION));
+ this->m_ui->TextEditInfo->setPlainText(
+ this->m_ui->TextEditInfo->toPlainText().replace("%APP_DESCRIPTION%",
+ APP_DESCRIPTION));
+ this->m_ui->TextEditCopyright->setPlainText(
+ this->m_ui->TextEditCopyright->toPlainText().replace("%APP_COPYRIGHT%",
+ APP_COPYRIGHT));
+ this->m_ui->TextEditCopyright->setPlainText(
+ this->m_ui->TextEditCopyright->toPlainText()
+ .replace("%APP_DEVELOPPER_EMAIL%",
+ APP_DEVELOPPER_EMAIL));
+}
+
+DlgAbout::~DlgAbout() {
+ delete m_ui;
+}
+
+void DlgAbout::changeEvent(QEvent *e) {
+ QDialog::changeEvent(e);
+ switch (e->type()) {
+ case QEvent::LanguageChange:
+ m_ui->retranslateUi(this);
+ break;
+ default:
+ break;
+ }
+}
+
+void DlgAbout::on_btnClose_clicked() {
+ this->accept();
+}
diff --git a/tags/fred-0.2.0/dlgabout.h b/tags/fred-0.2.0/dlgabout.h
new file mode 100644
index 0000000..2999eb2
--- /dev/null
+++ b/tags/fred-0.2.0/dlgabout.h
@@ -0,0 +1,47 @@
+/*******************************************************************************
+* fred Copyright (c) 2011-2020 by Gillen Daniel <gillen.dan@pinguin.lu> *
+* *
+* Forensic Registry EDitor (fred) is a cross-platform M$ registry hive editor *
+* with special feautures useful during forensic analysis. *
+* *
+* This program is free software: you can redistribute it and/or modify it *
+* under the terms of the GNU General Public License as published by the Free *
+* Software Foundation, either version 3 of the License, or (at your option) *
+* any later version. *
+* *
+* This program is distributed in the hope that it will be useful, but WITHOUT *
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or *
+* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for *
+* more details. *
+* *
+* You should have received a copy of the GNU General Public License along with *
+* this program. If not, see <http://www.gnu.org/licenses/>. *
+*******************************************************************************/
+
+#ifndef DLGABOUT_H
+#define DLGABOUT_H
+
+#include <QDialog>
+
+namespace Ui {
+ class DlgAbout;
+}
+
+class DlgAbout : public QDialog {
+ Q_OBJECT
+
+ public:
+ DlgAbout(QWidget *parent = 0);
+ ~DlgAbout();
+
+ protected:
+ void changeEvent(QEvent *e);
+
+ private:
+ Ui::DlgAbout *m_ui;
+
+ private slots:
+ void on_btnClose_clicked();
+};
+
+#endif // DLGABOUT_H
diff --git a/tags/fred-0.2.0/dlgabout.ui b/tags/fred-0.2.0/dlgabout.ui
new file mode 100644
index 0000000..3fdc2b5
--- /dev/null
+++ b/tags/fred-0.2.0/dlgabout.ui
@@ -0,0 +1,415 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>DlgAbout</class>
+ <widget class="QDialog" name="DlgAbout">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>540</width>
+ <height>363</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Dialog</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <widget class="QFrame" name="frame">
+ <property name="frameShape">
+ <enum>QFrame::NoFrame</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>QFrame::Raised</enum>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QLabel" name="label_2">
+ <property name="maximumSize">
+ <size>
+ <width>80</width>
+ <height>80</height>
+ </size>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ <property name="pixmap">
+ <pixmap resource="fred.qrc">:/icons/resources/fred.png</pixmap>
+ </property>
+ <property name="scaledContents">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="LblAbout">
+ <property name="frameShape">
+ <enum>QFrame::NoFrame</enum>
+ </property>
+ <property name="text">
+ <string>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
+&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
+p, li { white-space: pre-wrap; }
+&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'Droid Sans'; font-size:10pt; font-weight:400; font-style:normal;&quot;&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif'; font-size:12pt; font-weight:600;&quot;&gt;%APP_NAME_LONG% (%APP_NAME%)&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;%APP_COPYRIGHT%&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="indent">
+ <number>10</number>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QTabWidget" name="tabWidget">
+ <property name="currentIndex">
+ <number>0</number>
+ </property>
+ <widget class="QWidget" name="tab">
+ <attribute name="title">
+ <string>Info</string>
+ </attribute>
+ <layout class="QVBoxLayout" name="verticalLayout_2">
+ <item>
+ <widget class="QTextEdit" name="TextEditInfo">
+ <property name="minimumSize">
+ <size>
+ <width>500</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="readOnly">
+ <bool>true</bool>
+ </property>
+ <property name="html">
+ <string>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
+&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
+p, li { white-space: pre-wrap; }
+&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'Droid Sans'; font-size:10pt; font-weight:400; font-style:normal;&quot;&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;%APP_NAME% version %APP_VERSION%&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;%APP_DESCRIPTION%&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;%APP_NAME% is licensed under GPLv3.&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;Look at the documentation, the source code or the %APP_NAME% website (&lt;/span&gt;&lt;a href=&quot;https://www.pinguin.lu&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;https://www.pinguin.lu&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;) for more information.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QWidget" name="tab_3">
+ <attribute name="title">
+ <string>Copyright</string>
+ </attribute>
+ <layout class="QVBoxLayout" name="verticalLayout_3">
+ <item>
+ <widget class="QTextEdit" name="TextEditCopyright">
+ <property name="minimumSize">
+ <size>
+ <width>500</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="readOnly">
+ <bool>true</bool>
+ </property>
+ <property name="html">
+ <string>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
+&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
+p, li { white-space: pre-wrap; }
+&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'Droid Sans'; font-size:10pt; font-weight:400; font-style:normal;&quot;&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;%APP_COPYRIGHT% &amp;lt;%APP_DEVELOPPER_EMAIL%&amp;gt;&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;This program uses &lt;/span&gt;Richard W.M. Jones's&lt;span style=&quot; font-family:'Sans Serif'; font-size:9pt;&quot;&gt; hivex library&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;Copyright (C) 2009-2010 Red Hat Inc.&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;Derived from code by Petter Nordahl-Hagen under a compatible license:&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;Copyright (C) 1997-2007 Petter Nordahl-Hagen.&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;Derived from code by Markus Stephany under a compatible license:&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;Copyright (C) 2000-2004 Markus Stephany.&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;This program uses a modified version of the QHexEdit widget by Simon Winfried&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;Copyright (c) 2010 by Simon Winfried&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QWidget" name="tab_4">
+ <attribute name="title">
+ <string>GPL</string>
+ </attribute>
+ <layout class="QVBoxLayout" name="verticalLayout_4">
+ <item>
+ <widget class="QTextEdit" name="textEdit_3">
+ <property name="readOnly">
+ <bool>true</bool>
+ </property>
+ <property name="html">
+ <string>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
+&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
+p, li { white-space: pre-wrap; }
+&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'Droid Sans'; font-size:10pt; font-weight:400; font-style:normal;&quot;&gt;
+&lt;p align=&quot;center&quot; style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif'; font-size:11pt; font-weight:600;&quot;&gt;GNU GENERAL PUBLIC LICENSE&lt;/span&gt;&lt;/p&gt;
+&lt;p align=&quot;center&quot; style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif'; font-size:11pt; font-weight:600;&quot;&gt;Version 3, 29 June 2007&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:11pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;Copyright (C) 2007 Free Software Foundation, Inc. &amp;lt;http://fsf.org/&amp;gt;&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed.&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
+&lt;p align=&quot;center&quot; style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif'; font-size:11pt; font-weight:600;&quot;&gt;Preamble&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;The GNU General Public License is a free, copyleft license for software and other kinds of works.&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too.&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things.&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others.&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights.&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it.&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions.&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users.&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free.&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;The precise terms and conditions for copying, distribution and modification follow.&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
+&lt;p align=&quot;center&quot; style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif'; font-size:11pt; font-weight:600;&quot;&gt;TERMS AND CONDITIONS&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif'; font-size:9pt; text-decoration: underline;&quot;&gt;0. Definitions.&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;&amp;quot;This License&amp;quot; refers to version 3 of the GNU General Public License.&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;&amp;quot;Copyright&amp;quot; also means copyright-like laws that apply to other kinds of works, such as semiconductor masks.&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;&amp;quot;The Program&amp;quot; refers to any copyrightable work licensed under this License. Each licensee is addressed as &amp;quot;you&amp;quot;. &amp;quot;Licensees&amp;quot; and &amp;quot;recipients&amp;quot; may be individuals or organizations.&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;To &amp;quot;modify&amp;quot; a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a &amp;quot;modified version&amp;quot; of the earlier work or a work &amp;quot;based on&amp;quot; the earlier work.&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;A &amp;quot;covered work&amp;quot; means either the unmodified Program or a work based on the Program.&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;To &amp;quot;propagate&amp;quot; a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well.&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;To &amp;quot;convey&amp;quot; a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying.&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;An interactive user interface displays &amp;quot;Appropriate Legal Notices&amp;quot; to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion.&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif'; font-size:9pt; text-decoration: underline;&quot;&gt;1. Source Code.&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;The &amp;quot;source code&amp;quot; for a work means the preferred form of the work for making modifications to it. &amp;quot;Object code&amp;quot; means any non-source form of a work.&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;A &amp;quot;Standard Interface&amp;quot; means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language.&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;The &amp;quot;System Libraries&amp;quot; of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A &amp;quot;Major Component&amp;quot;, in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it.&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;The &amp;quot;Corresponding Source&amp;quot; for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work.&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source.&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;The Corresponding Source for a work in source code form is that same work.&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif'; font-size:9pt; text-decoration: underline;&quot;&gt;2. Basic Permissions.&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law.&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you.&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary.&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif'; font-size:9pt; text-decoration: underline;&quot;&gt;3. Protecting Users' Legal Rights From Anti-Circumvention Law.&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures.&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures.&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif'; font-size:9pt; text-decoration: underline;&quot;&gt;4. Conveying Verbatim Copies.&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program.&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee.&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif'; font-size:9pt; text-decoration: underline;&quot;&gt;5. Conveying Modified Source Versions.&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions:&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;a) The work must carry prominent notices stating that you modified it, and giving a relevant date.&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to &amp;quot;keep intact all notices&amp;quot;.&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it.&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so.&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an &amp;quot;aggregate&amp;quot; if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate.&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif'; font-size:9pt; text-decoration: underline;&quot;&gt;6. Conveying Non-Source Forms.&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways:&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange.&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge.&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b.&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements.&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d.&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work.&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;A &amp;quot;User Product&amp;quot; is either (1) a &amp;quot;consumer product&amp;quot;, which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, &amp;quot;normally used&amp;quot; refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product.&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;&amp;quot;Installation Information&amp;quot; for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made.&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM).&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network.&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying.&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif'; font-size:9pt; text-decoration: underline;&quot;&gt;7. Additional Terms.&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;&amp;quot;Additional permissions&amp;quot; are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions.&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission.&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms:&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;d) Limiting the use for publicity purposes of names of licensors or authors of the material; or&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors.&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;All other non-permissive additional terms are considered &amp;quot;further restrictions&amp;quot; within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying.&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms.&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way.&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif'; font-size:9pt; text-decoration: underline;&quot;&gt;8. Termination.&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11).&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation.&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice.&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10.&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif'; font-size:9pt; text-decoration: underline;&quot;&gt;9. Acceptance Not Required for Having Copies.&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so.&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif'; font-size:9pt; text-decoration: underline;&quot;&gt;10. Automatic Licensing of Downstream Recipients.&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License.&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;An &amp;quot;entity transaction&amp;quot; is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts.&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it.&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif'; font-size:9pt; text-decoration: underline;&quot;&gt;11. Patents.&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;A &amp;quot;contributor&amp;quot; is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's &amp;quot;contributor version&amp;quot;.&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;A contributor's &amp;quot;essential patent claims&amp;quot; are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, &amp;quot;control&amp;quot; includes the right to grant patent sublicenses in a manner consistent with the requirements of this License.&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version.&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;In the following three paragraphs, a &amp;quot;patent license&amp;quot; is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To &amp;quot;grant&amp;quot; such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party.&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. &amp;quot;Knowingly relying&amp;quot; means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid.&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it.&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;A patent license is &amp;quot;discriminatory&amp;quot; if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007.&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law.&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif'; font-size:9pt; text-decoration: underline;&quot;&gt;12. No Surrender of Others' Freedom.&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program.&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif'; font-size:9pt; text-decoration: underline;&quot;&gt;13. Use with the GNU Affero General Public License.&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such.&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif'; font-size:9pt; text-decoration: underline;&quot;&gt;14. Revised Versions of this License.&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns.&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License &amp;quot;or any later version&amp;quot; applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation.&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program.&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version.&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif'; font-size:9pt; text-decoration: underline;&quot;&gt;15. Disclaimer of Warranty.&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM &amp;quot;AS IS&amp;quot; WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif'; font-size:9pt; text-decoration: underline;&quot;&gt;16. Limitation of Liability.&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif'; font-size:9pt; text-decoration: underline;&quot;&gt;17. Interpretation of Sections 15 and 16.&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="btnClose">
+ <property name="text">
+ <string>&amp;Close</string>
+ </property>
+ <property name="icon">
+ <iconset>
+ <normaloff>:/icons/cross.png</normaloff>:/icons/cross.png</iconset>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources>
+ <include location="fred.qrc"/>
+ </resources>
+ <connections/>
+</ui>
diff --git a/tags/fred-0.2.0/dlgaddkey.cpp b/tags/fred-0.2.0/dlgaddkey.cpp
new file mode 100644
index 0000000..e8bd094
--- /dev/null
+++ b/tags/fred-0.2.0/dlgaddkey.cpp
@@ -0,0 +1,441 @@
+/*******************************************************************************
+* fred Copyright (c) 2011-2020 by Gillen Daniel <gillen.dan@pinguin.lu> *
+* *
+* Forensic Registry EDitor (fred) is a cross-platform M$ registry hive editor *
+* with special feautures useful during forensic analysis. *
+* *
+* This program is free software: you can redistribute it and/or modify it *
+* under the terms of the GNU General Public License as published by the Free *
+* Software Foundation, either version 3 of the License, or (at your option) *
+* any later version. *
+* *
+* This program is distributed in the hope that it will be useful, but WITHOUT *
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or *
+* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for *
+* more details. *
+* *
+* You should have received a copy of the GNU General Public License along with *
+* this program. If not, see <http://www.gnu.org/licenses/>. *
+*******************************************************************************/
+
+#include <QString>
+#include <QStringList>
+#include <QMessageBox>
+#include <QRegExp>
+#include <QtEndian>
+
+#include <QDebug>
+
+#include <stdlib.h>
+
+#include "dlgaddkey.h"
+#include "ui_dlgaddkey.h"
+
+#include "registryhive.h"
+
+DlgAddKey::DlgAddKey(QWidget *p_parent,
+ QString key_name,
+ QString key_value_type,
+ QByteArray key_value) :
+ QDialog(p_parent),
+ ui(new Ui::DlgAddKey)
+{
+ this->p_current_widget=NULL;
+ ui->setupUi(this);
+ this->ansi_encoded=false;
+
+ // Create widgets
+ this->CreateValueWidgets();
+
+ // Set dialog title
+ if(key_name.isEmpty() && key_value_type.isEmpty() && key_value.isEmpty()) {
+ // If no values were passed, we consider this the ddd key dialog
+ this->setWindowTitle(tr("Add key"));
+ } else {
+ // If a value was passed, this is considered the edit key dialog
+ this->setWindowTitle(tr("Edit key"));
+ this->ui->EdtKeyName->setEnabled(false);
+ this->ui->CmbKeyType->setEnabled(false);
+ }
+
+ // Preload key value type values
+ QStringList value_types=RegistryHive::GetKeyValueTypes();
+ this->ui->CmbKeyType->addItems(value_types);
+
+ // Load values
+ if(!key_name.isEmpty()) this->ui->EdtKeyName->setText(key_name);
+ if(!key_value_type.isEmpty())
+ this->ui->CmbKeyType->setCurrentIndex(value_types.indexOf(key_value_type));
+ if(!key_value.isEmpty()) this->SetValueWidgetData(key_value,key_value_type);
+
+ // Connect signals
+ this->connect(this->p_number_widget_rb_dec,
+ SIGNAL(clicked(bool)),
+ this,
+ SLOT(SlotNumberWidgetRbDecClicked(bool)));
+ this->connect(this->p_number_widget_rb_hex,
+ SIGNAL(clicked(bool)),
+ this,
+ SLOT(SlotNumberWidgetRbHexClicked(bool)));
+}
+
+DlgAddKey::~DlgAddKey() {
+ this->DestroyValueWidgets();
+ delete ui;
+}
+
+QString DlgAddKey::KeyName() {
+ return this->ui->EdtKeyName->text();
+}
+
+QString DlgAddKey::KeyType() {
+ return this->ui->CmbKeyType->currentText();
+}
+
+QByteArray DlgAddKey::KeyValue() {
+ return this->GetValueWidgetData();
+}
+
+void DlgAddKey::on_BtnCancel_clicked() {
+ this->reject();
+}
+
+void DlgAddKey::on_BtnOk_clicked() {
+ QString key_value_type=this->KeyType();
+
+ // Check entered data for correctness
+ if(key_value_type=="REG_MULTI_SZ") {
+ // REG_MULTI_SZ's can't contain empty sub-strings
+ QString cur_data=this->p_text_widget_text_edit->toPlainText();
+ QString new_data=cur_data;
+ // TODO: Do we need to check for \r\n on Windows??
+ new_data.replace(QRegExp("\n\n*"),"\n");
+ if(new_data.startsWith("\n")) new_data.remove(0,1);
+ if(new_data.endsWith("\n")) new_data.chop(1);
+ if(cur_data!=new_data) {
+ if(QMessageBox::information(this,
+ tr("Invalid data"),
+ tr("A REG_MULTI_SZ can not contain empty "
+ "sub-strings! If you continue, they "
+ "will be removed."),
+ QMessageBox::Yes,
+ QMessageBox::No)==QMessageBox::Yes)
+ {
+ this->p_text_widget_text_edit->setPlainText(new_data);
+ } else {
+ return;
+ }
+ }
+ } else if(key_value_type=="REG_DWORD" ||
+ key_value_type=="REG_DWORD_BIG_ENDIAN")
+ {
+ bool ok=false;
+ if(this->p_number_widget_rb_dec->isChecked()) {
+ this->p_number_widget_line_edit->text().toUInt(&ok);
+ } else {
+ this->p_number_widget_line_edit->text().toUInt(&ok,16);
+ }
+ if(!ok) {
+ QMessageBox::information(this,
+ tr("Invalid data"),
+ tr("The value you entered could not be "
+ "converted to a %1! Please correct it.")
+ .arg(key_value_type),
+ QMessageBox::Ok);
+ return;
+ }
+ } else if(key_value_type=="REG_QWORD") {
+ bool ok=false;
+ if(this->p_number_widget_rb_dec->isChecked()) {
+ this->p_number_widget_line_edit->text().toULongLong(&ok);
+ } else {
+ this->p_number_widget_line_edit->text().toULongLong(&ok,16);
+ }
+ if(!ok) {
+ QMessageBox::information(this,
+ tr("Invalid data"),
+ tr("The value you entered could not be "
+ "converted to a %1! Please correct it.")
+ .arg(key_value_type),
+ QMessageBox::Ok);
+ return;
+ }
+ }
+
+ this->accept();
+}
+
+void DlgAddKey::on_CmbKeyType_currentIndexChanged(const QString &arg1) {
+ // Remove current widget from grid layout
+ if(this->p_current_widget!=NULL) {
+ this->ui->gridLayout->removeWidget(this->p_current_widget);
+ this->p_current_widget->setVisible(false);
+ this->p_current_widget=NULL;
+ }
+
+ // Add new widget for selected value type
+ if(arg1=="REG_SZ" || arg1=="REG_EXPAND_SZ") {
+ // Line edit widget for REG_SZ and REG_EXPAND_SZ
+ this->ui->gridLayout->addWidget(this->p_line_widget,2,1);
+ this->p_current_widget=this->p_line_widget;
+ } else if(arg1=="REG_MULTI_SZ") {
+ // Text edit widget for REG_MULTI_SZ
+ this->ui->gridLayout->addWidget(this->p_text_widget,2,1);
+ this->p_current_widget=this->p_text_widget;
+ } else if(arg1=="REG_DWORD" ||
+ arg1=="REG_DWORD_BIG_ENDIAN" ||
+ arg1=="REG_QWORD")
+ {
+ // Number widget for REG_DWORD, REG_DWORD_BIG_ENDIAN and REG_QWORD
+ this->ui->gridLayout->addWidget(this->p_number_widget,2,1);
+ this->p_current_widget=this->p_number_widget;
+ } else if(arg1=="REG_BINARY" ||
+ arg1=="REG_LINK" ||
+ arg1=="REG_RESOURCE_LIST" ||
+ arg1=="REG_FULL_RESOURCE_DESC" ||
+ arg1=="REG_RESOURCE_REQ_LIST")
+ {
+ // Binary widget for all other types
+ this->ui->gridLayout->addWidget(this->p_binary_widget,2,1);
+ this->p_current_widget=this->p_binary_widget;
+ }
+
+ if(arg1!="REG_NONE") {
+ this->p_current_widget->setVisible(true);
+ this->ui->LblKeyValue->setVisible(true);
+ } else {
+ this->ui->LblKeyValue->setVisible(false);
+ }
+}
+
+void DlgAddKey::SlotNumberWidgetRbDecClicked(bool checked) {
+ if(checked) {
+ bool ok=false;
+ if(this->KeyType()=="REG_QWORD") {
+ quint64 num=this->p_number_widget_line_edit->text().toULongLong(&ok,16);
+ if(ok) {
+ // Convert number to dec
+ this->p_number_widget_line_edit->setText(QString("%1").arg(num));
+ }
+ } else {
+ quint32 num=this->p_number_widget_line_edit->text().toUInt(&ok,16);
+ if(ok) {
+ // Convert number to dec
+ this->p_number_widget_line_edit->setText(QString("%1").arg(num));
+ }
+ }
+ if(!ok) {
+ QMessageBox::warning(this,
+ tr("Errror"),
+ tr("Unable to convert entered value to decimal!"),
+ QMessageBox::Ok);
+ this->p_number_widget_rb_hex->setChecked(true);
+ }
+ }
+}
+
+void DlgAddKey::SlotNumberWidgetRbHexClicked(bool checked) {
+ if(checked) {
+ bool ok=false;
+ if(this->KeyType()=="REG_QWORD") {
+ quint64 num=this->p_number_widget_line_edit->text().toULongLong(&ok);
+ if(ok) {
+ // Convert number to hex
+ this->p_number_widget_line_edit->setText(QString("%1")
+ .arg(num,16,16,QChar('0')));
+ }
+ } else {
+ quint32 num=this->p_number_widget_line_edit->text().toUInt(&ok);
+ if(ok) {
+ // Convert number to hex
+ this->p_number_widget_line_edit->setText(QString("%1")
+ .arg(num,8,16,QChar('0')));
+ }
+ }
+ if(!ok) {
+ QMessageBox::warning(this,
+ tr("Errror"),
+ tr("Unable to convert entered value to hex!"),
+ QMessageBox::Ok);
+ this->p_number_widget_rb_dec->setChecked(true);
+ }
+ }
+}
+
+void DlgAddKey::CreateValueWidgets() {
+ this->p_line_widget=new QWidget();
+ this->p_line_widget_layout=new QHBoxLayout(this->p_line_widget);
+ //this->p_line_widget_layout_rb_ansi=new QRadioButton(tr("Ansi"));
+ //this->p_line_widget_layout_rb_unicode=new QRadioButton(tr("Unicode"));
+ //this->p_line_widget_layout_rb_unicode->setChecked(true);
+ this->p_line_widget_line_edit=new QLineEdit();
+ this->p_line_widget->setContentsMargins(0,0,0,0);
+ this->p_line_widget_layout->setContentsMargins(0,0,0,0);
+ this->p_line_widget_layout->addWidget(this->p_line_widget_line_edit);
+ //this->p_line_widget_layout->addWidget(this->p_line_widget_layout_rb_ansi);
+ //this->p_line_widget_layout->addWidget(this->p_line_widget_layout_rb_unicode);
+
+ this->p_text_widget=new QWidget();
+ this->p_text_widget_layout=new QHBoxLayout(this->p_text_widget);
+ this->p_text_widget_text_edit=new QPlainTextEdit();
+ this->p_text_widget->setContentsMargins(0,0,0,0);
+ this->p_text_widget_layout->setContentsMargins(0,0,0,0);
+ this->p_text_widget_layout->addWidget(this->p_text_widget_text_edit);
+
+ this->p_number_widget=new QWidget();
+ this->p_number_widget_layout=new QHBoxLayout(this->p_number_widget);
+ this->p_number_widget_line_edit=new QLineEdit();
+ this->p_number_widget_rb_dec=new QRadioButton(tr("Dec base"));
+ this->p_number_widget_rb_dec->setChecked(true);
+ this->p_number_widget_rb_hex=new QRadioButton(tr("Hex base"));
+ this->p_number_widget->setContentsMargins(0,0,0,0);
+ this->p_number_widget_layout->setContentsMargins(0,0,0,0);
+ this->p_number_widget_layout->addWidget(this->p_number_widget_line_edit);
+ this->p_number_widget_layout->addWidget(this->p_number_widget_rb_dec);
+ this->p_number_widget_layout->addWidget(this->p_number_widget_rb_hex);
+
+ this->p_binary_widget=new QWidget();
+ this->p_binary_widget_layout=new QHBoxLayout(this->p_binary_widget);
+ this->p_binary_widget_hex_edit=new HexEditWidget(this,false,false);
+ this->p_binary_widget->setContentsMargins(0,0,0,0);
+ this->p_binary_widget_layout->setContentsMargins(0,0,0,0);
+ this->p_binary_widget_layout->addWidget(this->p_binary_widget_hex_edit);
+}
+
+void DlgAddKey::DestroyValueWidgets() {
+ //delete this->p_line_widget_layout_rb_ansi;
+ //delete this->p_line_widget_layout_rb_unicode;
+ delete this->p_line_widget_line_edit;
+ delete this->p_line_widget_layout;
+ delete this->p_line_widget;
+
+ delete this->p_text_widget_text_edit;
+ delete this->p_text_widget_layout;
+ delete this->p_text_widget;
+
+ delete this->p_number_widget_rb_hex;
+ delete this->p_number_widget_rb_dec;
+ delete this->p_number_widget_line_edit;
+ delete this->p_number_widget_layout;
+ delete this->p_number_widget;
+
+ delete this->p_binary_widget_hex_edit;
+ delete this->p_binary_widget_layout;
+ delete this->p_binary_widget;
+}
+
+void DlgAddKey::SetValueWidgetData(QByteArray &key_value,
+ QString &key_value_type)
+{
+ if(key_value_type=="REG_SZ" || key_value_type=="REG_EXPAND_SZ") {
+ this->p_line_widget_line_edit->setText(
+ RegistryHive::KeyValueToString(key_value,
+ RegistryHive::StringToKeyValueType(
+ key_value_type)));
+ } else if(key_value_type=="REG_MULTI_SZ") {
+ QStringList strings=
+ RegistryHive::KeyValueToStringList(key_value,&(this->ansi_encoded));
+ this->p_text_widget_text_edit->setPlainText(strings.join("\n"));
+ } else if(key_value_type=="REG_DWORD") {
+ this->p_number_widget_line_edit->setText(
+ RegistryHive::KeyValueToString(key_value,"uint32"));
+ } else if(key_value_type=="REG_DWORD_BIG_ENDIAN") {
+ this->p_number_widget_line_edit->setText(
+ RegistryHive::KeyValueToString(key_value,"uint32",0,0,false));
+ } else if(key_value_type=="REG_QWORD") {
+ this->p_number_widget_line_edit->setText(
+ RegistryHive::KeyValueToString(key_value,"uint64",0,0,false));
+ } else if(key_value_type=="REG_BINARY" ||
+ key_value_type=="REG_LINK" ||
+ key_value_type=="REG_RESOURCE_LIST" ||
+ key_value_type=="REG_FULL_RESOURCE_DESC" ||
+ key_value_type=="REG_RESOURCE_REQ_LIST")
+ {
+ this->p_binary_widget_hex_edit->SetData(key_value);
+ }
+}
+
+QByteArray DlgAddKey::GetValueWidgetData() {
+ QString key_value_type=this->KeyType();
+
+ if(key_value_type=="REG_SZ" || key_value_type=="REG_EXPAND_SZ") {
+ // TODO: Wouldn't it be wise to let the user choose the encoding?
+ // Get data
+ QString data=this->p_line_widget_line_edit->text();
+ // Convert data to UTF16LE buffer
+ quint16 *p_buf=NULL;
+ int buf_len=this->ToUtf16LeBuf(&p_buf,data.utf16(),data.size());
+ if(p_buf==NULL || buf_len==0) {
+ // TODO: Inform user there was an error???
+ return QByteArray("\x00\x00",2);
+ }
+ // Construct ByteArray, free buffer and return
+ QByteArray ret=QByteArray((char*)p_buf,buf_len);
+ free(p_buf);
+ return ret;
+ } else if(key_value_type=="REG_MULTI_SZ") {
+ // TODO: Let the user choose the encoding / endianness
+ // TODO: Do we need to check for \r\n on Windows??
+ return RegistryHive::StringListToKeyValue(
+ this->p_text_widget_text_edit->
+ toPlainText().split("\n",
+ QString::SkipEmptyParts),
+ true,
+ this->ansi_encoded);
+ } else if(key_value_type=="REG_DWORD" ||
+ key_value_type=="REG_DWORD_BIG_ENDIAN")
+ {
+ quint32 val;
+ if(this->p_number_widget_rb_dec->isChecked()) {
+ val=this->p_number_widget_line_edit->text().toUInt();
+ } else {
+ val=this->p_number_widget_line_edit->text().toUInt(0,16);
+ }
+ if(key_value_type=="REG_DWORD") val=qToLittleEndian(val);
+ else val=qToBigEndian(val);
+ return QByteArray((char*)&val,4);
+ } else if(key_value_type=="REG_QWORD") {
+ quint64 val;
+ if(this->p_number_widget_rb_dec->isChecked()) {
+ val=this->p_number_widget_line_edit->text().toULongLong();
+ } else {
+ val=this->p_number_widget_line_edit->text().toULongLong(0,16);
+ }
+ val=qToLittleEndian(val);
+ return QByteArray((char*)&val,8);
+ } else if(key_value_type=="REG_BINARY" ||
+ key_value_type=="REG_LINK" ||
+ key_value_type=="REG_RESOURCE_LIST" ||
+ key_value_type=="REG_FULL_RESOURCE_DESC" ||
+ key_value_type=="REG_RESOURCE_REQ_LIST")
+ {
+ return this->p_binary_widget_hex_edit->GetData();
+ }
+ return QByteArray();
+}
+
+int DlgAddKey::ToUtf16LeBuf(quint16 **pp_buf,
+ const quint16 *p_data,
+ int ascii_len)
+{
+ // Calculate utf16 buffer size
+ // TODO: This fails if there are chars that need more than 16bit!!
+ int buf_len=(ascii_len*2)+2;
+
+ // Alloc buffer and set to 0x00h
+ *pp_buf=(quint16*)malloc(buf_len);
+ if(*pp_buf==NULL) return 0;
+ memset(*pp_buf,0,buf_len);
+ if(ascii_len==0) {
+ // Empty string, we're done (buffer contains \0\0)
+ return buf_len;
+ }
+ // Fill buffer with UTF16 string (ignoring \0\0 at the end)
+ memcpy(*pp_buf,p_data,buf_len-2);
+ // Make sure endianness is LE
+ for(int i=0;i<ascii_len;i++) {
+ (*pp_buf)[i]=qToLittleEndian((*pp_buf)[i]);
+ }
+
+ return buf_len;
+}
diff --git a/tags/fred-0.2.0/dlgaddkey.h b/tags/fred-0.2.0/dlgaddkey.h
new file mode 100644
index 0000000..a15428c
--- /dev/null
+++ b/tags/fred-0.2.0/dlgaddkey.h
@@ -0,0 +1,87 @@
+/*******************************************************************************
+* fred Copyright (c) 2011-2020 by Gillen Daniel <gillen.dan@pinguin.lu> *
+* *
+* Forensic Registry EDitor (fred) is a cross-platform M$ registry hive editor *
+* with special feautures useful during forensic analysis. *
+* *
+* This program is free software: you can redistribute it and/or modify it *
+* under the terms of the GNU General Public License as published by the Free *
+* Software Foundation, either version 3 of the License, or (at your option) *
+* any later version. *
+* *
+* This program is distributed in the hope that it will be useful, but WITHOUT *
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or *
+* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for *
+* more details. *
+* *
+* You should have received a copy of the GNU General Public License along with *
+* this program. If not, see <http://www.gnu.org/licenses/>. *
+*******************************************************************************/
+
+#ifndef DLGADDKEY_H
+#define DLGADDKEY_H
+
+#include <QDialog>
+#include <QWidget>
+#include <QHBoxLayout>
+#include <QLineEdit>
+#include <QPlainTextEdit>
+#include <QRadioButton>
+
+#include "hexeditwidget.h"
+
+namespace Ui {
+ class DlgAddKey;
+}
+
+class DlgAddKey : public QDialog {
+ Q_OBJECT
+
+ public:
+ explicit DlgAddKey(QWidget *p_parent=0,
+ QString key_name=QString(),
+ QString key_value_type=QString(),
+ QByteArray key_value=QByteArray());
+ ~DlgAddKey();
+
+ QString KeyName();
+ QString KeyType();
+ QByteArray KeyValue();
+
+ private slots:
+ void on_BtnCancel_clicked();
+ void on_BtnOk_clicked();
+ void on_CmbKeyType_currentIndexChanged(const QString &arg1);
+ void SlotNumberWidgetRbDecClicked(bool checked);
+ void SlotNumberWidgetRbHexClicked(bool checked);
+
+ private:
+ Ui::DlgAddKey *ui;
+ QWidget *p_current_widget;
+ QWidget *p_line_widget;
+ QHBoxLayout *p_line_widget_layout;
+ //QRadioButton *p_line_widget_layout_rb_ansi;
+ //QRadioButton *p_line_widget_layout_rb_unicode;
+ QLineEdit *p_line_widget_line_edit;
+ QWidget *p_text_widget;
+ QHBoxLayout *p_text_widget_layout;
+ QPlainTextEdit *p_text_widget_text_edit;
+ QWidget *p_number_widget;
+ QHBoxLayout *p_number_widget_layout;
+ QLineEdit *p_number_widget_line_edit;
+ QRadioButton *p_number_widget_rb_dec;
+ QRadioButton *p_number_widget_rb_hex;
+ QWidget *p_binary_widget;
+ QHBoxLayout *p_binary_widget_layout;
+ HexEditWidget *p_binary_widget_hex_edit;
+ bool ansi_encoded;
+
+ void CreateValueWidgets();
+ void DestroyValueWidgets();
+ void SetValueWidgetData(QByteArray &key_value, QString &key_value_type);
+ QByteArray GetValueWidgetData();
+ int ToUtf16LeBuf(quint16 **pp_buf, const quint16 *p_data, int ascii_len);
+ void SetNumberWidgetLineEditInputMask();
+};
+
+#endif // DLGADDKEY_H
diff --git a/tags/fred-0.2.0/dlgaddkey.ui b/tags/fred-0.2.0/dlgaddkey.ui
new file mode 100644
index 0000000..14431b8
--- /dev/null
+++ b/tags/fred-0.2.0/dlgaddkey.ui
@@ -0,0 +1,98 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>DlgAddKey</class>
+ <widget class="QDialog" name="DlgAddKey">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>400</width>
+ <height>154</height>
+ </rect>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Minimum">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="windowTitle">
+ <string>Dialog</string>
+ </property>
+ <property name="sizeGripEnabled">
+ <bool>true</bool>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <property name="sizeConstraint">
+ <enum>QLayout::SetMinAndMaxSize</enum>
+ </property>
+ <item>
+ <layout class="QGridLayout" name="gridLayout">
+ <property name="sizeConstraint">
+ <enum>QLayout::SetDefaultConstraint</enum>
+ </property>
+ <item row="0" column="0">
+ <widget class="QLabel" name="LblKeyName">
+ <property name="text">
+ <string>Key name:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="LblKeyType">
+ <property name="text">
+ <string>Key type:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="0">
+ <widget class="QLabel" name="LblKeyValue">
+ <property name="text">
+ <string>Key value:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QLineEdit" name="EdtKeyName"/>
+ </item>
+ <item row="1" column="1">
+ <widget class="QComboBox" name="CmbKeyType"/>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <widget class="QPushButton" name="BtnCancel">
+ <property name="text">
+ <string>&amp;Cancel</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QPushButton" name="BtnOk">
+ <property name="text">
+ <string>&amp;Ok</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/tags/fred-0.2.0/dlgpreferences.cpp b/tags/fred-0.2.0/dlgpreferences.cpp
new file mode 100644
index 0000000..6245ead
--- /dev/null
+++ b/tags/fred-0.2.0/dlgpreferences.cpp
@@ -0,0 +1,235 @@
+/*******************************************************************************
+* fred Copyright (c) 2011-2020 by Gillen Daniel <gillen.dan@pinguin.lu> *
+* *
+* Forensic Registry EDitor (fred) is a cross-platform M$ registry hive editor *
+* with special feautures useful during forensic analysis. *
+* *
+* This program is free software: you can redistribute it and/or modify it *
+* under the terms of the GNU General Public License as published by the Free *
+* Software Foundation, either version 3 of the License, or (at your option) *
+* any later version. *
+* *
+* This program is distributed in the hope that it will be useful, but WITHOUT *
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or *
+* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for *
+* more details. *
+* *
+* You should have received a copy of the GNU General Public License along with *
+* this program. If not, see <http://www.gnu.org/licenses/>. *
+*******************************************************************************/
+
+#include <QString>
+#include <QStringList>
+#include <QListIterator>
+#include <QModelIndexList>
+#include <QFileDialog>
+#include <QMessageBox>
+
+#include <QDebug>
+
+#include "dlgpreferences.h"
+#include "ui_dlgpreferences.h"
+
+/*******************************************************************************
+ * Public
+ ******************************************************************************/
+
+DlgPreferences::DlgPreferences(Settings *p_sets, QWidget *p_parent) :
+ QDialog(p_parent), ui(new Ui::DlgPreferences)
+{
+ ui->setupUi(this);
+ this->p_settings=p_sets;
+
+ // Load current values
+ this->LoadPreferences();
+}
+
+DlgPreferences::~DlgPreferences() {
+ delete ui;
+}
+
+/*******************************************************************************
+ * Private slots
+ ******************************************************************************/
+
+void DlgPreferences::on_BtnCancel_clicked() {
+ this->reject();
+}
+
+void DlgPreferences::on_ListReportLocations_clicked(const QModelIndex &index) {
+ if(!index.isValid()) {
+ // No valid row selected, disable some buttons
+ this->ui->BtnEditReportLoc->setEnabled(false);
+ this->ui->BtnRemoveReportLoc->setEnabled(false);
+ this->ui->BtnMoveReportLocUp->setEnabled(false);
+ this->ui->BtnMoveReportLocDown->setEnabled(false);
+ this->ui->BtnAddReportLoc->setFocus();
+ return;
+ }
+
+ if(this->ui->ListReportLocations->count()==1) {
+ // Only one item left, disable up/down buttons
+ this->ui->BtnEditReportLoc->setEnabled(true);
+ this->ui->BtnRemoveReportLoc->setEnabled(true);
+ this->ui->BtnMoveReportLocUp->setEnabled(false);
+ this->ui->BtnMoveReportLocDown->setEnabled(false);
+ return;
+ }
+
+ if(index.row()==0) {
+ // First row selected, disable up button
+ this->ui->BtnEditReportLoc->setEnabled(true);
+ this->ui->BtnRemoveReportLoc->setEnabled(true);
+ this->ui->BtnMoveReportLocUp->setEnabled(false);
+ this->ui->BtnMoveReportLocDown->setEnabled(true);
+ return;
+ }
+
+ if(index.row()==(this->ui->ListReportLocations->count()-1)) {
+ // Last row selected, disable down button
+ this->ui->BtnEditReportLoc->setEnabled(true);
+ this->ui->BtnRemoveReportLoc->setEnabled(true);
+ this->ui->BtnMoveReportLocUp->setEnabled(true);
+ this->ui->BtnMoveReportLocDown->setEnabled(false);
+ return;
+ }
+
+ // Any other valid row selected, enable up/down buttons
+ this->ui->BtnEditReportLoc->setEnabled(true);
+ this->ui->BtnRemoveReportLoc->setEnabled(true);
+ this->ui->BtnMoveReportLocUp->setEnabled(true);
+ this->ui->BtnMoveReportLocDown->setEnabled(true);
+}
+
+void DlgPreferences::on_BtnAddReportLoc_clicked() {
+ QString new_loc=QFileDialog::getExistingDirectory(this,
+ tr("Select new report "
+ "directory"));
+ if(!new_loc.isEmpty()) {
+ this->ui->ListReportLocations->addItem(new_loc);
+ }
+}
+
+void DlgPreferences::on_BtnEditReportLoc_clicked() {
+ QModelIndex cur_item=this->ui->ListReportLocations->currentIndex();
+ if(!cur_item.isValid()) return;
+
+ // Get selected item
+ QListWidgetItem *p_item=this->ui->ListReportLocations->item(cur_item.row());
+
+ // Let user select new directory
+ QString new_loc=QFileDialog::getExistingDirectory(this,
+ tr("Edit report directory"),
+ p_item->text());
+ if(!new_loc.isEmpty()) {
+ p_item->setText(new_loc);
+ }
+}
+
+void DlgPreferences::on_BtnRemoveReportLoc_clicked() {
+ QModelIndex cur_item=this->ui->ListReportLocations->currentIndex();
+ if(!cur_item.isValid()) return;
+
+ QListWidgetItem *p_item=
+ this->ui->ListReportLocations->takeItem(cur_item.row());
+ delete p_item;
+ // Update buttons
+ this->on_ListReportLocations_clicked(
+ this->ui->ListReportLocations->currentIndex());
+}
+
+void DlgPreferences::on_BtnMoveReportLocUp_clicked() {
+ QModelIndex cur_item=this->ui->ListReportLocations->currentIndex();
+ if(!cur_item.isValid() || cur_item.row()==0) return;
+
+ // Move selected item up
+ QListWidgetItem *p_item=
+ this->ui->ListReportLocations->takeItem(cur_item.row());
+ this->ui->ListReportLocations->insertItem(cur_item.row()-1,p_item);
+
+ // Reselect moved item and update buttons
+ this->ui->ListReportLocations->setCurrentItem(p_item);
+ this->on_ListReportLocations_clicked(
+ this->ui->ListReportLocations->currentIndex());
+}
+
+void DlgPreferences::on_BtnMoveReportLocDown_clicked() {
+ QModelIndex cur_item=this->ui->ListReportLocations->currentIndex();
+ if(!cur_item.isValid() ||
+ cur_item.row()==(this->ui->ListReportLocations->count()-1))
+ {
+ return;
+ }
+
+ // Move selected item up
+ QListWidgetItem *p_item=
+ this->ui->ListReportLocations->takeItem(cur_item.row());
+ this->ui->ListReportLocations->insertItem(cur_item.row()+1,p_item);
+
+ // Reselect moved item and update buttons
+ this->ui->ListReportLocations->setCurrentItem(p_item);
+ this->on_ListReportLocations_clicked(
+ this->ui->ListReportLocations->currentIndex());
+}
+
+
+void DlgPreferences::on_BtnReset_clicked() {
+ if(QMessageBox::warning(this,
+ tr("Reset default settings"),
+ tr("Are you sure to reset all settings to their defaults?"),
+ QMessageBox::No,
+ QMessageBox::Yes)==QMessageBox::Yes)
+ {
+ this->p_settings->Reset();
+ this->LoadPreferences();
+ }
+}
+
+void DlgPreferences::on_BtnOk_clicked() {
+ this->SavePreferences();
+ this->accept();
+}
+
+/*******************************************************************************
+ * Private
+ ******************************************************************************/
+
+void DlgPreferences::LoadPreferences() {
+ // Load general preferences
+ this->ui->SpinBoxRecentFiles->setValue(
+ this->p_settings->GetRecentFilesDepth());
+ this->ui->ChkBoxSavePositions->setChecked(
+ this->p_settings->GetWindowGeometryStatus());
+ this->ui->ChkBoxOpenReadOnly->setChecked(
+ this->p_settings->GetOpenHivesReadOnly());
+
+ // Populate report location list
+ this->ui->ListReportLocations->clear();
+ QStringList report_dirs=this->p_settings->GetReportTemplateDirs();
+ QListIterator<QString> it_report_dirs(report_dirs);
+ if(!report_dirs.isEmpty()) {
+ while(it_report_dirs.hasNext()) {
+ this->ui->ListReportLocations->addItem(it_report_dirs.next());
+ }
+ this->ui->ListReportLocations->setCurrentRow(0);
+ this->ui->BtnEditReportLoc->setEnabled(true);
+ this->ui->BtnRemoveReportLoc->setEnabled(true);
+ this->ui->BtnMoveReportLocDown->setEnabled(true);
+ }
+}
+
+void DlgPreferences::SavePreferences() {
+ // Save general preferences
+ this->p_settings->SetRecentFilesDepth(this->ui->SpinBoxRecentFiles->value());
+ this->p_settings->SetWindowGeometryStatus(
+ this->ui->ChkBoxSavePositions->isChecked());
+ this->p_settings->SetOpenHivesReadOnly(
+ this->ui->ChkBoxOpenReadOnly->isChecked());
+
+ // Save report location list
+ QStringList report_dirs;
+ for(int i=0;i<this->ui->ListReportLocations->count();i++) {
+ report_dirs.append(this->ui->ListReportLocations->item(i)->text());
+ }
+ this->p_settings->SetReportTemplateDirs(report_dirs);
+}
diff --git a/tags/fred-0.2.0/dlgpreferences.h b/tags/fred-0.2.0/dlgpreferences.h
new file mode 100644
index 0000000..b7f7f9e
--- /dev/null
+++ b/tags/fred-0.2.0/dlgpreferences.h
@@ -0,0 +1,60 @@
+/*******************************************************************************
+* fred Copyright (c) 2011-2020 by Gillen Daniel <gillen.dan@pinguin.lu> *
+* *
+* Forensic Registry EDitor (fred) is a cross-platform M$ registry hive editor *
+* with special feautures useful during forensic analysis. *
+* *
+* This program is free software: you can redistribute it and/or modify it *
+* under the terms of the GNU General Public License as published by the Free *
+* Software Foundation, either version 3 of the License, or (at your option) *
+* any later version. *
+* *
+* This program is distributed in the hope that it will be useful, but WITHOUT *
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or *
+* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for *
+* more details. *
+* *
+* You should have received a copy of the GNU General Public License along with *
+* this program. If not, see <http://www.gnu.org/licenses/>. *
+*******************************************************************************/
+
+#ifndef DLGPREFERENCES_H
+#define DLGPREFERENCES_H
+
+#include <QDialog>
+#include <QModelIndex>
+
+#include "settings.h"
+
+namespace Ui {
+ class DlgPreferences;
+}
+
+class DlgPreferences : public QDialog {
+ Q_OBJECT
+
+ public:
+ explicit DlgPreferences(Settings *p_sets, QWidget *p_parent=0);
+ ~DlgPreferences();
+
+ private slots:
+ void on_BtnCancel_clicked();
+ void on_ListReportLocations_clicked(const QModelIndex &index);
+ void on_BtnAddReportLoc_clicked();
+ void on_BtnEditReportLoc_clicked();
+ void on_BtnRemoveReportLoc_clicked();
+ void on_BtnMoveReportLocUp_clicked();
+ void on_BtnMoveReportLocDown_clicked();
+ void on_BtnReset_clicked();
+
+ void on_BtnOk_clicked();
+
+ private:
+ Ui::DlgPreferences *ui;
+ Settings *p_settings;
+
+ void LoadPreferences();
+ void SavePreferences();
+};
+
+#endif // DLGPREFERENCES_H
diff --git a/tags/fred-0.2.0/dlgpreferences.ui b/tags/fred-0.2.0/dlgpreferences.ui
new file mode 100644
index 0000000..09b834b
--- /dev/null
+++ b/tags/fred-0.2.0/dlgpreferences.ui
@@ -0,0 +1,256 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>DlgPreferences</class>
+ <widget class="QDialog" name="DlgPreferences">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>615</width>
+ <height>404</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Preferences</string>
+ </property>
+ <property name="windowIcon">
+ <iconset resource="fred.qrc">
+ <normaloff>:/icons/resources/fred.png</normaloff>:/icons/resources/fred.png</iconset>
+ </property>
+ <property name="sizeGripEnabled">
+ <bool>true</bool>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <widget class="QTabWidget" name="tabWidget">
+ <property name="currentIndex">
+ <number>0</number>
+ </property>
+ <widget class="QWidget" name="TabGeneral">
+ <attribute name="title">
+ <string>General</string>
+ </attribute>
+ <layout class="QGridLayout" name="gridLayout">
+ <item row="0" column="1">
+ <widget class="QSpinBox" name="SpinBoxRecentFiles"/>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="LblSavePositions">
+ <property name="text">
+ <string>Save position and size of main window and dialogs:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QCheckBox" name="ChkBoxSavePositions">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ <property name="checkable">
+ <bool>true</bool>
+ </property>
+ <property name="autoExclusive">
+ <bool>false</bool>
+ </property>
+ <property name="tristate">
+ <bool>false</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="0">
+ <widget class="QLabel" name="LblRecentFiles">
+ <property name="text">
+ <string>Number of recent files to remember:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="0">
+ <spacer name="verticalSpacer">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item row="2" column="0">
+ <widget class="QLabel" name="LblOpenReadOnly">
+ <property name="text">
+ <string>Always open files read-only:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1">
+ <widget class="QCheckBox" name="ChkBoxOpenReadOnly">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QWidget" name="TabReports">
+ <attribute name="title">
+ <string>Reports</string>
+ </attribute>
+ <layout class="QVBoxLayout" name="verticalLayout_3">
+ <item>
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-weight:600;&quot;&gt;Warning:&lt;/span&gt;&lt;/p&gt;&lt;p&gt;The following list gives you the possibility to add/remove report locations and to change their precedence. Reports are searched and added from top to bottom, thus reports found in later directories replace reports found earlier if they have same name, category and hive! In addition, you may also remove the two default system and user locations which might result in no reports being found at all if you don't have added your own locations.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+ </property>
+ <property name="wordWrap">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_2">
+ <item>
+ <widget class="QListWidget" name="ListReportLocations"/>
+ </item>
+ <item>
+ <layout class="QVBoxLayout" name="verticalLayout_2">
+ <item>
+ <widget class="QPushButton" name="BtnAddReportLoc">
+ <property name="text">
+ <string>Add</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="BtnEditReportLoc">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>Edit</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="BtnRemoveReportLoc">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>Remove</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="BtnMoveReportLocUp">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>Move up</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="BtnMoveReportLocDown">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>Move down</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="verticalSpacer_2">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <widget class="QPushButton" name="BtnCancel">
+ <property name="text">
+ <string>&amp;Cancel</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="BtnReset">
+ <property name="text">
+ <string>Reset to defaults</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QPushButton" name="BtnOk">
+ <property name="text">
+ <string>&amp;Ok</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <tabstops>
+ <tabstop>BtnOk</tabstop>
+ <tabstop>BtnCancel</tabstop>
+ <tabstop>BtnReset</tabstop>
+ <tabstop>tabWidget</tabstop>
+ <tabstop>SpinBoxRecentFiles</tabstop>
+ <tabstop>ChkBoxSavePositions</tabstop>
+ <tabstop>ListReportLocations</tabstop>
+ <tabstop>BtnAddReportLoc</tabstop>
+ <tabstop>BtnEditReportLoc</tabstop>
+ <tabstop>BtnRemoveReportLoc</tabstop>
+ <tabstop>BtnMoveReportLocUp</tabstop>
+ <tabstop>BtnMoveReportLocDown</tabstop>
+ </tabstops>
+ <resources>
+ <include location="fred.qrc"/>
+ </resources>
+ <connections/>
+</ui>
diff --git a/tags/fred-0.2.0/dlgreportchooser.cpp b/tags/fred-0.2.0/dlgreportchooser.cpp
new file mode 100644
index 0000000..8a95151
--- /dev/null
+++ b/tags/fred-0.2.0/dlgreportchooser.cpp
@@ -0,0 +1,159 @@
+/*******************************************************************************
+* fred Copyright (c) 2011-2020 by Gillen Daniel <gillen.dan@pinguin.lu> *
+* *
+* Forensic Registry EDitor (fred) is a cross-platform M$ registry hive editor *
+* with special feautures useful during forensic analysis. *
+* *
+* This program is free software: you can redistribute it and/or modify it *
+* under the terms of the GNU General Public License as published by the Free *
+* Software Foundation, either version 3 of the License, or (at your option) *
+* any later version. *
+* *
+* This program is distributed in the hope that it will be useful, but WITHOUT *
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or *
+* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for *
+* more details. *
+* *
+* You should have received a copy of the GNU General Public License along with *
+* this program. If not, see <http://www.gnu.org/licenses/>. *
+*******************************************************************************/
+
+#include <QString>
+#include <QStringList>
+#include <QListIterator>
+
+#include <QDebug>
+
+#include "dlgreportchooser.h"
+#include "ui_dlgreportchooser.h"
+
+DlgReportChooser::DlgReportChooser(Reports *p_reps,
+ QString hive_type_string,
+ Settings *p_sets,
+ QWidget *p_parent)
+ : QDialog(p_parent), ui(new Ui::DlgReportChooser)
+{
+ QStringList tree_cats;
+ QString cur_tree_cat;
+ QTreeWidgetItem *p_tree_cat_widget;
+ QTreeWidgetItem *p_tree_cat_rep_widget;
+ QList<ReportTemplate*> tree_cat_reports;
+ ReportTemplate* p_report;
+
+ // Init private vars
+ this->ui->setupUi(this);
+ this->p_reports=p_reps;
+ this->p_settings=p_sets;
+ this->hive_type=hive_type_string;
+ this->tree_category_items.clear();
+ this->selected_reports.clear();
+
+ // Restore dialog geometry if possible
+ QByteArray geometry=this->p_settings->GetWindowGeometry("DlgReportChooser");
+ if(!geometry.isEmpty()) this->restoreGeometry(geometry);
+
+ // Populate tree with reports
+ tree_cats=this->p_reports->GetAvailableReportCategories();
+ QListIterator<QString> tree_cat_it(tree_cats);
+ while(tree_cat_it.hasNext()) {
+ cur_tree_cat=tree_cat_it.next();
+ p_tree_cat_widget=new QTreeWidgetItem(this->ui->TrReports);
+ p_tree_cat_widget->setText(0,cur_tree_cat);
+ p_tree_cat_widget->setFlags(Qt::ItemIsEnabled|
+ Qt::ItemIsUserCheckable|
+ Qt::ItemIsTristate);
+ p_tree_cat_widget->setCheckState(0,Qt::Unchecked);
+ tree_cat_reports=this->p_reports->GetAvailableReports(cur_tree_cat);
+ QListIterator<ReportTemplate*> tree_cat_rep_it(tree_cat_reports);
+ while(tree_cat_rep_it.hasNext()) {
+ p_report=tree_cat_rep_it.next();
+
+ p_tree_cat_rep_widget=new QTreeWidgetItem(p_tree_cat_widget);
+ // Save pointer to ReportTemplate alongside
+ p_tree_cat_rep_widget->setData(0,
+ Qt::UserRole,
+ QVariant().fromValue(p_report));
+ p_tree_cat_rep_widget->setText(0,p_report->Name());
+ p_tree_cat_rep_widget->setFlags(Qt::ItemIsEnabled|
+ Qt::ItemIsSelectable|
+ Qt::ItemIsUserCheckable);
+ if(this->hive_type!="UNKNOWN" && this->hive_type==p_report->Hive()) {
+ p_tree_cat_rep_widget->setCheckState(0,Qt::Checked);
+ } else {
+ p_tree_cat_rep_widget->setCheckState(0,Qt::Unchecked);
+ }
+ }
+ this->tree_category_items.append(p_tree_cat_widget);
+ }
+
+ // Finally, expand all categories
+ this->ui->TrReports->expandAll();
+}
+
+DlgReportChooser::~DlgReportChooser() {
+ // Save dialog geometry
+ this->p_settings->SetWindowGeometry("DlgReportChooser",this->saveGeometry());
+ delete this->ui;
+}
+
+QList<ReportTemplate*> DlgReportChooser::GetSelectedReports()
+{
+ return this->selected_reports;
+}
+
+void DlgReportChooser::changeEvent(QEvent *p_event) {
+ QDialog::changeEvent(p_event);
+ switch (p_event->type()) {
+ case QEvent::LanguageChange:
+ this->ui->retranslateUi(this);
+ break;
+ default:
+ break;
+ }
+}
+
+void DlgReportChooser::on_BtnCancel_clicked() {
+ this->reject();
+}
+
+void DlgReportChooser::on_TrReports_currentItemChanged(
+ QTreeWidgetItem *p_current, QTreeWidgetItem *p_previous)
+{
+ Q_UNUSED(p_previous)
+
+ // If item has no parent, clear labels and return
+ if(p_current->parent()==NULL) {
+ this->ui->LblHive->clear();
+ this->ui->LblAuthor->clear();
+ this->ui->LblDesc->clear();
+ return;
+ }
+
+ // Update labels
+ this->ui->LblHive->setText(
+ p_current->data(0,Qt::UserRole).value<ReportTemplate*>()->Hive());
+ this->ui->LblAuthor->setText(
+ p_current->data(0,Qt::UserRole).value<ReportTemplate*>()->Author());
+ this->ui->LblDesc->setText(
+ p_current->data(0,Qt::UserRole).value<ReportTemplate*>()->Description());
+}
+
+void DlgReportChooser::on_BtnGenerate_clicked() {
+ QTreeWidgetItem *p_cat;
+ int i;
+
+ // Add selected reports to selected_reports
+ QListIterator<QTreeWidgetItem*> cat_it(this->tree_category_items);
+ while(cat_it.hasNext()) {
+ p_cat=cat_it.next();
+ for(i=0;i<p_cat->childCount();i++) {
+ if(p_cat->child(i)->checkState(0)==Qt::Checked) {
+ // Get saved pointer to ReportTemplate and append it to selected_reps
+ this->selected_reports.append(p_cat->
+ child(i)->data(0,Qt::UserRole).value<ReportTemplate*>());
+ }
+ }
+ }
+
+ this->accept();
+}
diff --git a/tags/fred-0.2.0/dlgreportchooser.h b/tags/fred-0.2.0/dlgreportchooser.h
new file mode 100644
index 0000000..a8b996b
--- /dev/null
+++ b/tags/fred-0.2.0/dlgreportchooser.h
@@ -0,0 +1,65 @@
+/*******************************************************************************
+* fred Copyright (c) 2011-2020 by Gillen Daniel <gillen.dan@pinguin.lu> *
+* *
+* Forensic Registry EDitor (fred) is a cross-platform M$ registry hive editor *
+* with special feautures useful during forensic analysis. *
+* *
+* This program is free software: you can redistribute it and/or modify it *
+* under the terms of the GNU General Public License as published by the Free *
+* Software Foundation, either version 3 of the License, or (at your option) *
+* any later version. *
+* *
+* This program is distributed in the hope that it will be useful, but WITHOUT *
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or *
+* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for *
+* more details. *
+* *
+* You should have received a copy of the GNU General Public License along with *
+* this program. If not, see <http://www.gnu.org/licenses/>. *
+*******************************************************************************/
+
+#ifndef DLGREPORTCHOOSER_H
+#define DLGREPORTCHOOSER_H
+
+#include <QDialog>
+#include <QList>
+#include <QTreeWidgetItem>
+
+#include "reports.h"
+#include "settings.h"
+
+namespace Ui {
+ class DlgReportChooser;
+}
+
+class DlgReportChooser : public QDialog {
+ Q_OBJECT
+
+ public:
+ explicit DlgReportChooser(Reports *p_reps,
+ QString hive_type_string,
+ Settings *p_sets,
+ QWidget *p_parent=0);
+ ~DlgReportChooser();
+
+ QList<ReportTemplate*> GetSelectedReports();
+
+ protected:
+ void changeEvent(QEvent *p_event);
+
+ private slots:
+ void on_BtnCancel_clicked();
+ void on_TrReports_currentItemChanged(QTreeWidgetItem *p_current,
+ QTreeWidgetItem *p_previous);
+ void on_BtnGenerate_clicked();
+
+ private:
+ Ui::DlgReportChooser *ui;
+ Reports *p_reports;
+ Settings *p_settings;
+ QString hive_type;
+ QList<QTreeWidgetItem*> tree_category_items;
+ QList<ReportTemplate*> selected_reports;
+};
+
+#endif // DLGREPORTCHOOSER_H
diff --git a/tags/fred-0.2.0/dlgreportchooser.ui b/tags/fred-0.2.0/dlgreportchooser.ui
new file mode 100644
index 0000000..2d96fc2
--- /dev/null
+++ b/tags/fred-0.2.0/dlgreportchooser.ui
@@ -0,0 +1,237 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>DlgReportChooser</class>
+ <widget class="QDialog" name="DlgReportChooser">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>599</width>
+ <height>300</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Generate report</string>
+ </property>
+ <property name="windowIcon">
+ <iconset resource="fred.qrc">
+ <normaloff>:/icons/resources/fred.png</normaloff>:/icons/resources/fred.png</iconset>
+ </property>
+ <property name="sizeGripEnabled">
+ <bool>true</bool>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <widget class="QGroupBox" name="groupBox">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="title">
+ <string>Available reports</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_3">
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>9</number>
+ </property>
+ <property name="rightMargin">
+ <number>9</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QTreeWidget" name="TrReports">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="MinimumExpanding" vsizetype="Expanding">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="headerHidden">
+ <bool>true</bool>
+ </property>
+ <column>
+ <property name="text">
+ <string notr="true">1</string>
+ </property>
+ </column>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="groupBox_2">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Preferred">
+ <horstretch>3</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>300</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="title">
+ <string>Report details</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_4">
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>9</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QLabel" name="LblHiveCaption">
+ <property name="font">
+ <font>
+ <underline>true</underline>
+ </font>
+ </property>
+ <property name="mouseTracking">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>Hive:</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="LblHive">
+ <property name="text">
+ <string/>
+ </property>
+ <property name="indent">
+ <number>10</number>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="LblAuthorCaption">
+ <property name="font">
+ <font>
+ <weight>50</weight>
+ <bold>false</bold>
+ <underline>true</underline>
+ </font>
+ </property>
+ <property name="text">
+ <string>Author:</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="LblAuthor">
+ <property name="text">
+ <string/>
+ </property>
+ <property name="indent">
+ <number>10</number>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="LblDescCaption">
+ <property name="font">
+ <font>
+ <weight>50</weight>
+ <bold>false</bold>
+ <underline>true</underline>
+ </font>
+ </property>
+ <property name="text">
+ <string>Description:</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="LblDesc">
+ <property name="text">
+ <string/>
+ </property>
+ <property name="wordWrap">
+ <bool>true</bool>
+ </property>
+ <property name="indent">
+ <number>10</number>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="verticalSpacer">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_2">
+ <item>
+ <widget class="QPushButton" name="BtnCancel">
+ <property name="text">
+ <string>&amp;Cancel</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QPushButton" name="BtnGenerate">
+ <property name="text">
+ <string>&amp;Generate</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <tabstops>
+ <tabstop>BtnGenerate</tabstop>
+ <tabstop>BtnCancel</tabstop>
+ <tabstop>TrReports</tabstop>
+ </tabstops>
+ <resources>
+ <include location="fred.qrc"/>
+ </resources>
+ <connections/>
+</ui>
diff --git a/tags/fred-0.2.0/dlgreportviewer.cpp b/tags/fred-0.2.0/dlgreportviewer.cpp
new file mode 100644
index 0000000..0deb7f1
--- /dev/null
+++ b/tags/fred-0.2.0/dlgreportviewer.cpp
@@ -0,0 +1,116 @@
+/*******************************************************************************
+* fred Copyright (c) 2011-2020 by Gillen Daniel <gillen.dan@pinguin.lu> *
+* *
+* Forensic Registry EDitor (fred) is a cross-platform M$ registry hive editor *
+* with special feautures useful during forensic analysis. *
+* *
+* This program is free software: you can redistribute it and/or modify it *
+* under the terms of the GNU General Public License as published by the Free *
+* Software Foundation, either version 3 of the License, or (at your option) *
+* any later version. *
+* *
+* This program is distributed in the hope that it will be useful, but WITHOUT *
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or *
+* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for *
+* more details. *
+* *
+* You should have received a copy of the GNU General Public License along with *
+* this program. If not, see <http://www.gnu.org/licenses/>. *
+*******************************************************************************/
+
+#include <QPrinter>
+#include <QPrintDialog>
+#include <QFileDialog>
+#include <QTextDocument>
+#include <QTextDocumentWriter>
+
+#include "dlgreportviewer.h"
+#include "ui_dlgreportviewer.h"
+
+DlgReportViewer::DlgReportViewer(QString &report_data,
+ Settings *p_sets,
+ QWidget *p_parent)
+ : QMainWindow(p_parent,Qt::Dialog | Qt::Popup), ui(new Ui::DlgReportViewer)
+{
+ // Init local vars
+ ui->setupUi(this);
+ this->p_local_event_loop=NULL;
+ this->orig_report_data=report_data;
+ this->p_settings=p_sets;
+
+ // Try to restore dialog geometry
+ QByteArray geometry=this->p_settings->GetWindowGeometry("DlgReportViewer");
+ if(!geometry.isEmpty()) this->restoreGeometry(geometry);
+
+ // Set report content
+ this->ui->WebView->setHtml(report_data);
+
+ // Set dialog title based on report content title
+ QString report_title=this->ui->WebView->title();
+ this->setWindowTitle("Report Viewer");
+}
+
+DlgReportViewer::~DlgReportViewer() {
+ // Save dialog geometry
+ this->p_settings->SetWindowGeometry("DlgReportViewer",this->saveGeometry());
+ delete ui;
+ if(this->p_local_event_loop!=NULL) this->p_local_event_loop->exit();
+}
+
+void DlgReportViewer::changeEvent(QEvent *p_event) {
+ QMainWindow::changeEvent(p_event);
+ switch(p_event->type()) {
+ case QEvent::LanguageChange:
+ ui->retranslateUi(this);
+ break;
+ default:
+ break;
+ }
+}
+
+void DlgReportViewer::closeEvent(QCloseEvent *p_event) {
+ // Make sure we exit the local event loop on exit
+ if(this->p_local_event_loop!=NULL) {
+ this->p_local_event_loop->exit();
+ this->p_local_event_loop=NULL;
+ }
+ p_event->accept();
+}
+
+void DlgReportViewer::exec() {
+ // Create local event loop
+ this->p_local_event_loop=new QEventLoop(this);
+ // Show window and enter loop
+ this->show();
+ this->p_local_event_loop->exec();
+}
+
+void DlgReportViewer::on_action_Print_triggered() {
+ // Print report
+ QPrinter printer;
+ QPrintDialog *p_dlg_print=new QPrintDialog(&printer);
+ if(p_dlg_print->exec()==QDialog::Accepted) {
+ this->ui->WebView->page()->print(&printer, [=](bool){});
+ }
+ delete p_dlg_print;
+}
+
+void DlgReportViewer::on_action_Close_triggered() {
+ this->close();
+}
+
+void DlgReportViewer::on_action_Save_triggered() {
+ QString filename=QFileDialog::getSaveFileName(this,
+ tr("Save report as"),
+ "",
+ "ODF file (*.odf)");
+ if(filename!="") {
+ QTextDocument *p_doc=new QTextDocument(this);
+ p_doc->setHtml(this->orig_report_data);
+ QTextDocumentWriter *p_doc_writer=new QTextDocumentWriter(filename);
+ p_doc_writer->setFormat(QByteArray("ODF"));
+ p_doc_writer->write(p_doc);
+ delete p_doc_writer;
+ delete p_doc;
+ }
+}
diff --git a/tags/fred-0.2.0/dlgreportviewer.h b/tags/fred-0.2.0/dlgreportviewer.h
new file mode 100644
index 0000000..163306a
--- /dev/null
+++ b/tags/fred-0.2.0/dlgreportviewer.h
@@ -0,0 +1,62 @@
+/*******************************************************************************
+* fred Copyright (c) 2011-2020 by Gillen Daniel <gillen.dan@pinguin.lu> *
+* *
+* Forensic Registry EDitor (fred) is a cross-platform M$ registry hive editor *
+* with special feautures useful during forensic analysis. *
+* *
+* This program is free software: you can redistribute it and/or modify it *
+* under the terms of the GNU General Public License as published by the Free *
+* Software Foundation, either version 3 of the License, or (at your option) *
+* any later version. *
+* *
+* This program is distributed in the hope that it will be useful, but WITHOUT *
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or *
+* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for *
+* more details. *
+* *
+* You should have received a copy of the GNU General Public License along with *
+* this program. If not, see <http://www.gnu.org/licenses/>. *
+*******************************************************************************/
+
+#ifndef DLGREPORTVIEWER_H
+#define DLGREPORTVIEWER_H
+
+#include <QMainWindow>
+#include <QEventLoop>
+#include <QCloseEvent>
+
+#include "settings.h"
+
+namespace Ui {
+ class DlgReportViewer;
+}
+
+class DlgReportViewer : public QMainWindow {
+ Q_OBJECT
+
+ public:
+ explicit DlgReportViewer(QString &report_data,
+ Settings *p_sets,
+ QWidget *p_parent=0);
+ ~DlgReportViewer();
+
+ void exec();
+
+ protected:
+ void changeEvent(QEvent *p_event);
+ void closeEvent(QCloseEvent *p_event);
+
+ private slots:
+ void on_action_Print_triggered();
+ void on_action_Close_triggered();
+
+ void on_action_Save_triggered();
+
+ private:
+ Ui::DlgReportViewer *ui;
+ QEventLoop *p_local_event_loop;
+ QString orig_report_data;
+ Settings *p_settings;
+};
+
+#endif // DLGREPORTVIEWER_H
diff --git a/tags/fred-0.2.0/dlgreportviewer.ui b/tags/fred-0.2.0/dlgreportviewer.ui
new file mode 100644
index 0000000..5fecdb7
--- /dev/null
+++ b/tags/fred-0.2.0/dlgreportviewer.ui
@@ -0,0 +1,83 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>DlgReportViewer</class>
+ <widget class="QMainWindow" name="DlgReportViewer">
+ <property name="windowModality">
+ <enum>Qt::NonModal</enum>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>605</width>
+ <height>497</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string/>
+ </property>
+ <property name="windowIcon">
+ <iconset resource="fred.qrc">
+ <normaloff>:/icons/resources/fred.png</normaloff>:/icons/resources/fred.png</iconset>
+ </property>
+ <widget class="QWidget" name="centralwidget">
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <widget class="QWebEngineView" name="WebView" native="true">
+ <property name="url" stdset="0">
+ <url>
+ <string>about:blank</string>
+ </url>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QMenuBar" name="menubar">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>605</width>
+ <height>29</height>
+ </rect>
+ </property>
+ <widget class="QMenu" name="menu_File">
+ <property name="title">
+ <string>&amp;File</string>
+ </property>
+ <addaction name="action_Save"/>
+ <addaction name="action_Print"/>
+ <addaction name="separator"/>
+ <addaction name="action_Close"/>
+ </widget>
+ <addaction name="menu_File"/>
+ </widget>
+ <action name="action_Print">
+ <property name="text">
+ <string>&amp;Print</string>
+ </property>
+ </action>
+ <action name="action_Close">
+ <property name="text">
+ <string>&amp;Close</string>
+ </property>
+ </action>
+ <action name="action_Save">
+ <property name="text">
+ <string>&amp;Save</string>
+ </property>
+ </action>
+ </widget>
+ <customwidgets>
+ <customwidget>
+ <class>QWebEngineView</class>
+ <extends>QWidget</extends>
+ <header>QtWebEngineWidgets/QWebEngineView</header>
+ </customwidget>
+ </customwidgets>
+ <resources>
+ <include location="fred.qrc"/>
+ </resources>
+ <connections/>
+</ui>
diff --git a/tags/fred-0.2.0/dlgsearch.cpp b/tags/fred-0.2.0/dlgsearch.cpp
new file mode 100644
index 0000000..52afdeb
--- /dev/null
+++ b/tags/fred-0.2.0/dlgsearch.cpp
@@ -0,0 +1,136 @@
+/*******************************************************************************
+* fred Copyright (c) 2011-2020 by Gillen Daniel <gillen.dan@pinguin.lu> *
+* *
+* Forensic Registry EDitor (fred) is a cross-platform M$ registry hive editor *
+* with special feautures useful during forensic analysis. *
+* *
+* This program is free software: you can redistribute it and/or modify it *
+* under the terms of the GNU General Public License as published by the Free *
+* Software Foundation, either version 3 of the License, or (at your option) *
+* any later version. *
+* *
+* This program is distributed in the hope that it will be useful, but WITHOUT *
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or *
+* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for *
+* more details. *
+* *
+* You should have received a copy of the GNU General Public License along with *
+* this program. If not, see <http://www.gnu.org/licenses/>. *
+*******************************************************************************/
+
+#include <QMessageBox>
+
+#include "dlgsearch.h"
+#include "ui_dlgsearch.h"
+
+
+DlgSearch::DlgSearch(QWidget *parent) : QDialog(parent), ui(new Ui::DlgSearch)
+{
+ ui->setupUi(this);
+}
+
+DlgSearch::~DlgSearch() {
+ delete ui;
+}
+
+QList<QByteArray> DlgSearch::Keywords() {
+ return this->keywords;
+}
+
+bool DlgSearch::SearchNodeNames() {
+ return this->search_nodes;
+}
+
+bool DlgSearch::SearchKeyNames() {
+ return this->search_keys;
+}
+
+bool DlgSearch::SearchKeyValues() {
+ return this->search_values;
+}
+
+void DlgSearch::changeEvent(QEvent *e) {
+ QDialog::changeEvent(e);
+ switch (e->type()) {
+ case QEvent::LanguageChange:
+ ui->retranslateUi(this);
+ break;
+ default:
+ break;
+ }
+}
+
+void DlgSearch::keyPressEvent(QKeyEvent *p_event) {
+ if(p_event->key()==Qt::Key_Return || p_event->key()==Qt::Key_Enter) {
+ this->on_BtnSearch_clicked();
+ } else {
+ QDialog::keyPressEvent(p_event);
+ }
+}
+
+void DlgSearch::on_BtnCancel_clicked() {
+ this->reject();
+}
+
+void DlgSearch::on_BtnSearch_clicked() {
+ if(this->ui->EdtValue->text()=="" ||
+ (!this->ui->CbAscii->isChecked() &&
+ !this->ui->CbUtf16->isChecked() &&
+ !this->ui->CbHex->isChecked()))
+ {
+ // No value type specified
+ QMessageBox::critical(this,
+ tr("Error"),
+ tr("Please specify a search value and type!"));
+ return;
+ }
+
+ if(!this->ui->CbNodeNames->isChecked() &&
+ !this->ui->CbKeyNames->isChecked() &&
+ !this->ui->CbKeyValues->isChecked())
+ {
+ // No target specified
+ QMessageBox::critical(this,
+ tr("Error"),
+ tr("Please specify a search target!"));
+ return;
+ }
+
+ // Save settings
+ QString keyword=this->ui->EdtValue->text();
+ this->keywords.clear();
+ if(this->ui->CbAscii->isChecked()) this->keywords.append(QByteArray(keyword.toLatin1()));
+ if(this->ui->CbUtf16->isChecked()) {
+ // TODO: .size()*2 will definetly fail sometimes!!!!
+ this->keywords.append(QByteArray((char*)(keyword.utf16()),keyword.size()*2));
+ }
+ if(this->ui->CbHex->isChecked()) {
+ // TODO: Convert to hex
+ }
+
+ this->search_nodes=this->ui->CbNodeNames->isChecked();
+ this->search_keys=this->ui->CbKeyNames->isChecked();
+ this->search_values=this->ui->CbKeyValues->isChecked();
+
+ this->accept();
+}
+
+void DlgSearch::on_CbAscii_toggled(bool checked) {
+ // It is not possible to search for text and hex
+ if(checked && this->ui->CbHex->isChecked())
+ this->ui->CbHex->setChecked(false);
+}
+
+void DlgSearch::on_CbUtf16_toggled(bool checked) {
+ // It is not possible to search for text and hex
+ if(checked && this->ui->CbHex->isChecked())
+ this->ui->CbHex->setChecked(false);
+}
+
+void DlgSearch::on_CbHex_toggled(bool checked) {
+ // It is not possible to search for text and hex
+ if(checked) {
+ this->ui->CbAscii->setChecked(false);
+ this->ui->CbUtf16->setChecked(false);
+ }
+}
diff --git a/tags/fred-0.2.0/dlgsearch.h b/tags/fred-0.2.0/dlgsearch.h
new file mode 100644
index 0000000..c51efa2
--- /dev/null
+++ b/tags/fred-0.2.0/dlgsearch.h
@@ -0,0 +1,64 @@
+/*******************************************************************************
+* fred Copyright (c) 2011-2020 by Gillen Daniel <gillen.dan@pinguin.lu> *
+* *
+* Forensic Registry EDitor (fred) is a cross-platform M$ registry hive editor *
+* with special feautures useful during forensic analysis. *
+* *
+* This program is free software: you can redistribute it and/or modify it *
+* under the terms of the GNU General Public License as published by the Free *
+* Software Foundation, either version 3 of the License, or (at your option) *
+* any later version. *
+* *
+* This program is distributed in the hope that it will be useful, but WITHOUT *
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or *
+* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for *
+* more details. *
+* *
+* You should have received a copy of the GNU General Public License along with *
+* this program. If not, see <http://www.gnu.org/licenses/>. *
+*******************************************************************************/
+
+#ifndef DLGSEARCH_H
+#define DLGSEARCH_H
+
+#include <QDialog>
+#include <QList>
+#include <QByteArray>
+#include <QKeyEvent>
+
+namespace Ui {
+ class DlgSearch;
+}
+
+class DlgSearch : public QDialog {
+ Q_OBJECT
+
+ public:
+ explicit DlgSearch(QWidget *parent = 0);
+ ~DlgSearch();
+
+ QList<QByteArray> Keywords();
+ bool SearchNodeNames();
+ bool SearchKeyNames();
+ bool SearchKeyValues();
+
+ protected:
+ void changeEvent(QEvent *e);
+ void keyPressEvent(QKeyEvent *p_event);
+
+ private slots:
+ void on_BtnCancel_clicked();
+ void on_BtnSearch_clicked();
+ void on_CbAscii_toggled(bool checked);
+ void on_CbUtf16_toggled(bool checked);
+ void on_CbHex_toggled(bool checked);
+
+ private:
+ Ui::DlgSearch *ui;
+ QList<QByteArray> keywords;
+ bool search_nodes;
+ bool search_keys;
+ bool search_values;
+};
+
+#endif // DLGSEARCH_H
diff --git a/tags/fred-0.2.0/dlgsearch.ui b/tags/fred-0.2.0/dlgsearch.ui
new file mode 100644
index 0000000..a3e27f4
--- /dev/null
+++ b/tags/fred-0.2.0/dlgsearch.ui
@@ -0,0 +1,152 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>DlgSearch</class>
+ <widget class="QDialog" name="DlgSearch">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>400</width>
+ <height>216</height>
+ </rect>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Minimum" vsizetype="Minimum">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="windowTitle">
+ <string>Find</string>
+ </property>
+ <property name="windowIcon">
+ <iconset resource="fred.qrc">
+ <normaloff>:/icons/resources/fred.png</normaloff>:/icons/resources/fred.png</iconset>
+ </property>
+ <property name="sizeGripEnabled">
+ <bool>true</bool>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <widget class="QGroupBox" name="groupBox">
+ <property name="title">
+ <string>Search value</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_2">
+ <item>
+ <widget class="QLineEdit" name="EdtValue"/>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <widget class="QCheckBox" name="CbAscii">
+ <property name="text">
+ <string>ASCII</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="CbUtf16">
+ <property name="text">
+ <string>UTF16</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="CbHex">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>Hexadecimal</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="groupBox_2">
+ <property name="title">
+ <string>Search in</string>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout_2">
+ <item>
+ <widget class="QCheckBox" name="CbNodeNames">
+ <property name="text">
+ <string>Node names</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="CbKeyNames">
+ <property name="text">
+ <string>Key names</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="CbKeyValues">
+ <property name="text">
+ <string>Key values</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_3">
+ <item>
+ <widget class="QPushButton" name="BtnCancel">
+ <property name="text">
+ <string>&amp;Cancel</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QPushButton" name="BtnSearch">
+ <property name="text">
+ <string>&amp;Search</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <resources>
+ <include location="fred.qrc"/>
+ </resources>
+ <connections/>
+</ui>
diff --git a/tags/fred-0.2.0/fred.pro b/tags/fred-0.2.0/fred.pro
new file mode 100644
index 0000000..8d3bd2d
--- /dev/null
+++ b/tags/fred-0.2.0/fred.pro
@@ -0,0 +1,134 @@
+#*******************************************************************************
+# fred Copyright (c) 2011-2020 by Gillen Daniel <gillen.dan@pinguin.lu> *
+# *
+# Forensic Registry EDitor (fred) is a cross-platform M$ registry hive editor *
+# with special feautures useful during forensic analysis. *
+# *
+# This program is free software: you can redistribute it and/or modify it *
+# under the terms of the GNU General Public License as published by the Free *
+# Software Foundation, either version 3 of the License, or (at your option) *
+# any later version. *
+# *
+# This program is distributed in the hope that it will be useful, but WITHOUT *
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or *
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for *
+# more details. *
+# *
+# You should have received a copy of the GNU General Public License along with *
+# this program. If not, see <http://www.gnu.org/licenses/>. *
+#******************************************************************************/
+
+# Generate compileinfo.h
+system(bash compileinfo.sh > compileinfo.h)
+#compileinfo.target = compileinfo.h
+#compileinfo.commands = $$PWD/compileinfo.sh > compileinfo.h
+#QMAKE_EXTRA_TARGETS += compileinfo
+#PRE_TARGETDEPS += compileinfo.h
+
+# Check command line args
+!isEmpty(HIVEX_STATIC) {
+ DEFINES += "HIVEX_STATIC"
+}
+
+# Configure fred
+QMAKE_CXXFLAGS += -Wall
+
+QT += core \
+ widgets \
+ printsupport \
+ script \
+ webenginewidgets
+
+CONFIG += console
+
+TARGET = fred
+
+TEMPLATE = app
+
+SOURCES += main.cpp\
+ mainwindow.cpp \
+ registrynode.cpp \
+ registrynodetreemodel.cpp \
+ registrykey.cpp \
+ registrykeytablemodel.cpp \
+ dlgabout.cpp \
+ qhexedit/qhexedit_p.cpp \
+ qhexedit/qhexedit.cpp \
+ reporttemplate.cpp \
+ registryhive.cpp \
+ qtscript_types/bytearray.cpp \
+ qtscript_types/bytearrayprototype.cpp \
+ qtscript_types/bytearrayiterator.cpp \
+ dlgreportviewer.cpp \
+ registrykeytable.cpp \
+ registrynodetree.cpp \
+ dlgsearch.cpp \
+ threadsearch.cpp \
+ searchresultwidget.cpp \
+ tabwidget.cpp \
+ argparser.cpp \
+ datainterpretertable.cpp \
+ datainterpreterwidget.cpp \
+ hexeditwidget.cpp \
+ settings.cpp \
+ searchresulttabledelegate.cpp \
+ registrynodetreemodelproxy.cpp \
+ reports.cpp \
+ reportengine.cpp \
+ dlgreportchooser.cpp \
+ dlgpreferences.cpp \
+ dlgaddkey.cpp
+
+HEADERS += mainwindow.h \
+ registrynode.h \
+ registrynodetreemodel.h \
+ registrykey.h \
+ registrykeytablemodel.h \
+ dlgabout.h \
+ qhexedit/qhexedit_p.h \
+ qhexedit/qhexedit.h \
+ reporttemplate.h \
+ registryhive.h \
+ qtscript_types/bytearray.h \
+ qtscript_types/bytearrayprototype.h \
+ qtscript_types/bytearrayiterator.h \
+ dlgreportviewer.h \
+ registrykeytable.h \
+ registrynodetree.h \
+ dlgsearch.h \
+ threadsearch.h \
+ searchresultwidget.h \
+ tabwidget.h \
+ argparser.h \
+ datainterpretertable.h \
+ datainterpreterwidget.h \
+ hexeditwidget.h \
+ settings.h \
+ searchresulttabledelegate.h \
+ registrynodetreemodelproxy.h \
+ reports.h \
+ reportengine.h \
+ dlgreportchooser.h \
+ dlgpreferences.h \
+ dlgaddkey.h
+
+FORMS += mainwindow.ui \
+ dlgabout.ui \
+ dlgreportviewer.ui \
+ dlgsearch.ui \
+ dlgreportchooser.ui \
+ dlgpreferences.ui \
+ dlgaddkey.ui
+
+!isEmpty(HIVEX_STATIC) {
+ LIBS += $$PWD/hivex/lib/.libs/libhivex.a
+} else {
+ LIBS += -lhivex
+}
+
+win32:LIBS += -liconv
+mac:LIBS += -liconv
+
+RESOURCES += fred.qrc
+RC_FILE = fred.rc
+ICON = resources/fred.icns
diff --git a/tags/fred-0.2.0/fred.qrc b/tags/fred-0.2.0/fred.qrc
new file mode 100644
index 0000000..d6d985e
--- /dev/null
+++ b/tags/fred-0.2.0/fred.qrc
@@ -0,0 +1,6 @@
+<RCC>
+ <qresource prefix="/icons">
+ <file>resources/fred.png</file>
+ <file alias="close_button">resources/close_button.jpg</file>
+ </qresource>
+</RCC>
diff --git a/tags/fred-0.2.0/fred.rc b/tags/fred-0.2.0/fred.rc
new file mode 100644
index 0000000..2365184
--- /dev/null
+++ b/tags/fred-0.2.0/fred.rc
@@ -0,0 +1 @@
+IDI_ICON1 ICON DISCARDABLE "resources/fred.ico"
diff --git a/tags/fred-0.2.0/fred_license_template.txt b/tags/fred-0.2.0/fred_license_template.txt
new file mode 100644
index 0000000..b8ab59a
--- /dev/null
+++ b/tags/fred-0.2.0/fred_license_template.txt
@@ -0,0 +1,19 @@
+/*******************************************************************************
+* fred Copyright (c) 2011-2020 by Gillen Daniel <gillen.dan@pinguin.lu> *
+* *
+* Forensic Registry EDitor (fred) is a cross-platform M$ registry hive editor *
+* with special feautures useful during forensic analysis. *
+* *
+* This program is free software: you can redistribute it and/or modify it *
+* under the terms of the GNU General Public License as published by the Free *
+* Software Foundation, either version 3 of the License, or (at your option) *
+* any later version. *
+* *
+* This program is distributed in the hope that it will be useful, but WITHOUT *
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or *
+* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for *
+* more details. *
+* *
+* You should have received a copy of the GNU General Public License along with *
+* this program. If not, see <http://www.gnu.org/licenses/>. *
+*******************************************************************************/
diff --git a/tags/fred-0.2.0/hexeditwidget.cpp b/tags/fred-0.2.0/hexeditwidget.cpp
new file mode 100644
index 0000000..c90399f
--- /dev/null
+++ b/tags/fred-0.2.0/hexeditwidget.cpp
@@ -0,0 +1,148 @@
+/*******************************************************************************
+* fred Copyright (c) 2011-2020 by Gillen Daniel <gillen.dan@pinguin.lu> *
+* *
+* Forensic Registry EDitor (fred) is a cross-platform M$ registry hive editor *
+* with special feautures useful during forensic analysis. *
+* *
+* This program is free software: you can redistribute it and/or modify it *
+* under the terms of the GNU General Public License as published by the Free *
+* Software Foundation, either version 3 of the License, or (at your option) *
+* any later version. *
+* *
+* This program is distributed in the hope that it will be useful, but WITHOUT *
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or *
+* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for *
+* more details. *
+* *
+* You should have received a copy of the GNU General Public License along with *
+* this program. If not, see <http://www.gnu.org/licenses/>. *
+*******************************************************************************/
+
+#include <QFont>
+#include <QSizePolicy>
+
+#include "hexeditwidget.h"
+
+HexEditWidget::HexEditWidget(QWidget *p_parent,
+ bool with_data_interpreter,
+ bool is_read_only) : QWidget(p_parent)
+{
+ // Init private vars
+ this->has_data_interpreter=with_data_interpreter;
+ this->read_only=is_read_only;
+ this->data=QByteArray();
+
+ // Set widget layout. Setting it's parent to "this" will also call
+ // this->SetLayout.
+ this->p_widget_layout=new QVBoxLayout(this);
+
+ // Create sub-widgets
+ if(this->has_data_interpreter) {
+ // Widget should include a data interpreter
+ this->p_widget_splitter=new QSplitter(this);
+ this->p_hex_edit_layout_widget=new QWidget(this->p_widget_splitter);
+ this->p_hex_edit_layout=new QVBoxLayout(this->p_hex_edit_layout_widget);
+ this->p_hex_edit=new QHexEdit(this->p_hex_edit_layout_widget);
+ this->p_hex_edit_status_bar=new QLabel(this);
+ this->p_data_interpreter_widget=new DataInterpreterWidget(this);
+
+ // Add hex edit and hex edit status bar to their layout
+ this->p_hex_edit_layout->addWidget(this->p_hex_edit);
+ this->p_hex_edit_layout->addWidget(this->p_hex_edit_status_bar);
+
+ // Add sub-widgets to splitter and splitter to our layout
+ this->p_widget_splitter->addWidget(this->p_hex_edit_layout_widget);
+ this->p_widget_splitter->addWidget(this->p_data_interpreter_widget);
+ this->p_widget_layout->addWidget(this->p_widget_splitter);
+
+ // Configure sub-widgets
+ this->p_widget_splitter->setOrientation(Qt::Horizontal);
+ this->p_hex_edit_layout_widget->setContentsMargins(0,0,0,0);
+ this->p_hex_edit_layout->setContentsMargins(0,0,0,0);
+
+ // Set size policies of sub-widgets
+ QSizePolicy hex_edit_layout_widget_policy=
+ this->p_hex_edit_layout_widget->sizePolicy();
+ hex_edit_layout_widget_policy.setVerticalStretch(2);
+ hex_edit_layout_widget_policy.setHorizontalStretch(200);
+ this->p_hex_edit_layout_widget->setSizePolicy(hex_edit_layout_widget_policy);
+
+ QSizePolicy data_interpreter_widget_policy=
+ this->p_data_interpreter_widget->sizePolicy();
+ data_interpreter_widget_policy.setVerticalStretch(2);
+ data_interpreter_widget_policy.setHorizontalStretch(0);
+ this->p_data_interpreter_widget->
+ setSizePolicy(data_interpreter_widget_policy);
+ } else {
+ // Widget shouldn't include a data interpreter
+ this->p_hex_edit=new QHexEdit(this);
+ this->p_hex_edit_status_bar=new QLabel(this);
+ this->p_widget_layout->addWidget(this->p_hex_edit);
+ this->p_widget_layout->addWidget(this->p_hex_edit_status_bar);
+ }
+
+ // Configure widget and sub-widgets
+ this->setContentsMargins(0,0,0,0);
+ this->p_widget_layout->setContentsMargins(0,0,0,0);
+ this->p_hex_edit->setContentsMargins(0,0,0,0);
+ // 5 pixel bottom margin makes hex edit and data interpreter lignup correctly
+ this->p_hex_edit_status_bar->setContentsMargins(0,0,0,5);
+ this->p_hex_edit->setReadOnly(this->read_only);
+ // If we're not read only, it should also be possible to add data
+ this->p_hex_edit->setOverwriteMode(this->read_only);
+
+ // Make sure hex edit font is monospaced.
+ QFont mono_font("Monospace");
+ mono_font.setStyleHint(QFont::TypeWriter);
+ this->p_hex_edit->setFont(mono_font);
+
+ // Connect signals
+ this->connect(this->p_hex_edit,
+ SIGNAL(currentAddressChanged(int)),
+ this,
+ SLOT(SlotHexEditOffsetChanged(int)));
+}
+
+HexEditWidget::~HexEditWidget() {
+ delete this->p_hex_edit_status_bar;
+ delete this->p_hex_edit;
+ if(this->has_data_interpreter) {
+ delete this->p_data_interpreter_widget;
+ delete this->p_hex_edit_layout;
+ delete this->p_hex_edit_layout_widget;
+ delete this->p_widget_splitter;
+ }
+ delete this->p_widget_layout;
+}
+
+void HexEditWidget::SetData(QByteArray const &new_data) {
+ this->data=new_data;
+
+ this->p_hex_edit->setData(this->data);
+ if(data.size()!=0) {
+ // Data set, update status bar and init data interpreter
+ this->SlotHexEditOffsetChanged(0);
+ } else {
+ // No data set, clear status bar and data interpreter
+ this->p_hex_edit_status_bar->setText("");
+ this->p_data_interpreter_widget->SetData(QByteArray());
+ }
+}
+
+QByteArray HexEditWidget::GetData() {
+ return this->p_hex_edit->data();
+}
+
+void HexEditWidget::SlotHexEditOffsetChanged(int offset) {
+ // Update hex edit status bar
+ this->p_hex_edit_status_bar->setText(tr("Byte offset: 0x%1 (%2)")
+ .arg((quint16)offset,
+ 4,
+ 16,
+ QChar('0'))
+ .arg(offset));
+ // Update data interpreter
+ if(this->has_data_interpreter) {
+ this->p_data_interpreter_widget->SetData(this->data.mid(offset,8));
+ }
+}
diff --git a/tags/fred-0.2.0/hexeditwidget.h b/tags/fred-0.2.0/hexeditwidget.h
new file mode 100644
index 0000000..1cd3d6b
--- /dev/null
+++ b/tags/fred-0.2.0/hexeditwidget.h
@@ -0,0 +1,68 @@
+/*******************************************************************************
+* fred Copyright (c) 2011-2020 by Gillen Daniel <gillen.dan@pinguin.lu> *
+* *
+* Forensic Registry EDitor (fred) is a cross-platform M$ registry hive editor *
+* with special feautures useful during forensic analysis. *
+* *
+* This program is free software: you can redistribute it and/or modify it *
+* under the terms of the GNU General Public License as published by the Free *
+* Software Foundation, either version 3 of the License, or (at your option) *
+* any later version. *
+* *
+* This program is distributed in the hope that it will be useful, but WITHOUT *
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or *
+* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for *
+* more details. *
+* *
+* You should have received a copy of the GNU General Public License along with *
+* this program. If not, see <http://www.gnu.org/licenses/>. *
+*******************************************************************************/
+
+#ifndef HEXEDITWIDGET_H
+#define HEXEDITWIDGET_H
+
+#include <QWidget>
+#include <QSplitter>
+#include <QVBoxLayout>
+#include <QLabel>
+#include <QByteArray>
+
+#include "qhexedit/qhexedit.h"
+#include "datainterpreterwidget.h"
+
+class HexEditWidget : public QWidget {
+ Q_OBJECT
+
+ public:
+ explicit HexEditWidget(QWidget *p_parent=0,
+ bool with_data_interpreter=true,
+ bool is_read_only=true);
+ ~HexEditWidget();
+
+ void SetData(QByteArray const &data);
+ QByteArray GetData();
+
+ signals:
+
+ public slots:
+
+ private:
+ // Widget layout
+ QVBoxLayout *p_widget_layout;
+ QSplitter *p_widget_splitter;
+ // Sub-widgets
+ QWidget *p_hex_edit_layout_widget;
+ QVBoxLayout *p_hex_edit_layout;
+ QHexEdit *p_hex_edit;
+ QLabel *p_hex_edit_status_bar;
+ DataInterpreterWidget *p_data_interpreter_widget;
+ // Vars
+ bool has_data_interpreter;
+ bool read_only;
+ QByteArray data;
+
+ private slots:
+ void SlotHexEditOffsetChanged(int offset);
+};
+
+#endif // HEXEDITWIDGET_H
diff --git a/tags/fred-0.2.0/hivex_patches/byte_conversions.patch b/tags/fred-0.2.0/hivex_patches/byte_conversions.patch
new file mode 100644
index 0000000..467a35d
--- /dev/null
+++ b/tags/fred-0.2.0/hivex_patches/byte_conversions.patch
@@ -0,0 +1,54 @@
+diff --git a/lib/byte_conversions.h b/lib/byte_conversions.h
+index aa4ffe6..2e4cafe 100644
+--- a/lib/byte_conversions.h
++++ b/lib/byte_conversions.h
+@@ -22,16 +22,16 @@
+
+ #if __BYTE_ORDER == __LITTLE_ENDIAN
+ #ifndef be32toh
+-#define be32toh(x) __bswap_32 (x)
++#define be32toh(x) bswap_32 (x)
+ #endif
+ #ifndef htobe32
+-#define htobe32(x) __bswap_32 (x)
++#define htobe32(x) bswap_32 (x)
+ #endif
+ #ifndef be64toh
+-#define be64toh(x) __bswap_64 (x)
++#define be64toh(x) bswap_64 (x)
+ #endif
+ #ifndef htobe64
+-#define htobe64(x) __bswap_64 (x)
++#define htobe64(x) bswap_64 (x)
+ #endif
+ #ifndef le16toh
+ #define le16toh(x) (x)
+@@ -65,22 +65,22 @@
+ #define htobe64(x) (x)
+ #endif
+ #ifndef le16toh
+-#define le16toh(x) __bswap_16 (x)
++#define le16toh(x) bswap_16 (x)
+ #endif
+ #ifndef htole16
+-#define htole16(x) __bswap_16 (x)
++#define htole16(x) bswap_16 (x)
+ #endif
+ #ifndef le32toh
+-#define le32toh(x) __bswap_32 (x)
++#define le32toh(x) bswap_32 (x)
+ #endif
+ #ifndef htole32
+-#define htole32(x) __bswap_32 (x)
++#define htole32(x) bswap_32 (x)
+ #endif
+ #ifndef le64toh
+-#define le64toh(x) __bswap_64 (x)
++#define le64toh(x) bswap_64 (x)
+ #endif
+ #ifndef htole64
+-#define htole64(x) __bswap_64 (x)
++#define htole64(x) bswap_64 (x)
+ #endif
+ #endif /* __BYTE_ORDER == __BIG_ENDIAN */
+
diff --git a/tags/fred-0.2.0/hivex_patches/config.patch b/tags/fred-0.2.0/hivex_patches/config.patch
new file mode 100644
index 0000000..2a9495b
--- /dev/null
+++ b/tags/fred-0.2.0/hivex_patches/config.patch
@@ -0,0 +1,104 @@
+--- configure.ac.orig 2011-08-15 22:29:28.309745342 +0300
++++ configure.ac 2011-08-15 22:34:54.324549151 +0300
+@@ -170,11 +170,18 @@
+ AC_SUBST([LIBXML2_CFLAGS])
+ AC_SUBST([LIBXML2_LIBS])
+
++
++dnl ////////////////////////////////////////////////////////////////////////////
+ dnl Check for OCaml (optional, for OCaml bindings).
++
++AC_ARG_ENABLE([ocaml],
++ AS_HELP_STRING([--with-ocaml],[build Ocaml binding]))
++
++
+ AC_PROG_OCAML
+ AC_PROG_FINDLIB
+ AM_CONDITIONAL([HAVE_OCAML],
+- [test "x$OCAMLC" != "xno" && test "x$OCAMLFIND" != "xno"])
++ [test "x$OCAMLC" != "xno" -a "x$OCAMLFIND" != "xno" -a "x$enable_ocaml" = "xyes"])
+ AM_CONDITIONAL([HAVE_OCAMLOPT],
+ [test "x$OCAMLOPT" != "xno" && test "x$OCAMLFIND" != "xno"])
+
+@@ -207,6 +214,8 @@
+ rm -f conftest conftest.* conftest_ml.*
+ fi
+
++dnl ///////////////////////////////////////////////////////////////////////////////////////
++
+ dnl Check for Perl (optional, for Perl bindings).
+ dnl XXX This isn't quite right, we should check for Perl devel library.
+ AC_CHECK_PROG([PERL],[perl],[perl],[no])
+@@ -214,21 +223,35 @@
+ dnl Check for Perl modules that must be present to compile and
+ dnl test the Perl bindings.
+ missing_perl_modules=no
+-for pm in Test::More ExtUtils::MakeMaker IO::Stringy; do
+- AC_MSG_CHECKING([for $pm])
+- if ! perl -M$pm -e1 >/dev/null 2>&1; then
+- AC_MSG_RESULT([no])
+- missing_perl_modules=yes
+- else
+- AC_MSG_RESULT([yes])
+- fi
+-done
+-if test "x$missing_perl_modules" = "xyes"; then
+- AC_MSG_WARN([some Perl modules required to compile or test the Perl bindings are missing])
+-fi
++
++AC_ARG_ENABLE([perl],
++ AS_HELP_STRING([--with-perl],[build Perl binding]))
++
++
++PERL=
++AS_IF([test "x$enable_perl" != "xno" ],[
++ AC_CHECK_PROG([PERL],[perl],[yes],[no])
++
++ for pm in Test::More ExtUtils::MakeMaker IO::Stringy; do
++ AC_MSG_CHECKING([for $pm])
++ if ! perl -M$pm -e1 >/dev/null 2>&1; then
++ AC_MSG_RESULT([no])
++ missing_perl_modules=yes
++ else
++ AC_MSG_RESULT([yes])
++ fi
++ done
++
++ AS_IF([test "x$missing_perl_modules" = "xyes"],
++ [AC_MSG_FAILURE([some Perl modules required to compile or test the Perl bindings are missing])],
++ )
++])
++
+
+ AM_CONDITIONAL([HAVE_PERL],
+- [test "x$PERL" != "xno" && test "x$missing_perl_modules" != "xyes"])
++ [test "x$PERL" != "xno" -a "x$missing_perl_modules" != "xyes" -a "x$enable_perl" = "xyes"])
++
++dnl //////////////////////////////////////////////////////////////////////////////////////////////////
+
+ dnl Check for Python (optional, for Python bindings).
+ AC_CHECK_PROG([PYTHON],[python],[python],[no])
+@@ -266,15 +289,21 @@
+ AC_SUBST(PYTHON_INCLUDEDIR)
+ AC_SUBST(PYTHON_SITE_PACKAGES)
+
++AC_ARG_ENABLE([python],
++ AS_HELP_STRING([--with-python],[build Python binding]))
++
+ AM_CONDITIONAL([HAVE_PYTHON],
+- [test "x$PYTHON_INCLUDEDIR" != "x" && test "x$PYTHON_SITE_PACKAGES" != "x"])
++ [test "x$PYTHON_INCLUDEDIR" != "x" -a "x$PYTHON_SITE_PACKAGES" != "x" -a "x$enable_python" = "xyes"])
+
+ dnl Check for Ruby and rake (optional, for Ruby bindings).
+ AC_CHECK_LIB([ruby],[ruby_init],[HAVE_LIBRUBY=1],[HAVE_LIBRUBY=0])
+ AC_CHECK_PROG([RAKE],[rake],[rake],[no])
+
++AC_ARG_ENABLE([ruby],
++ AS_HELP_STRING([--with-ruby],[build Ruby binding]))
++
+ AM_CONDITIONAL([HAVE_RUBY],
+- [test "x$RAKE" != "xno" && test -n "$HAVE_LIBRUBY"])
++ [test "x$RAKE" != "xno" && test -n "$HAVE_LIBRUBY" -a "x$enable_ruby" = "xyes"])
+
+ dnl dnl Check for Java.
+ dnl AC_ARG_WITH(java_home,
diff --git a/tags/fred-0.2.0/hivex_patches/gnulib.patch b/tags/fred-0.2.0/hivex_patches/gnulib.patch
new file mode 100644
index 0000000..caa4464
--- /dev/null
+++ b/tags/fred-0.2.0/hivex_patches/gnulib.patch
@@ -0,0 +1,29 @@
+--- a/lib/msvc-inval.c
++++ b/lib/msvc-inval.c
+@@ -28,7 +28,7 @@
+
+ # if MSVC_INVALID_PARAMETER_HANDLING == DEFAULT_HANDLING
+
+-static void cdecl
++static void __cdecl
+ gl_msvc_invalid_parameter_handler (const wchar_t *expression,
+ const wchar_t *function,
+ const wchar_t *file,
+@@ -45,7 +45,7 @@ gl_msvc_invalid_parameter_handler (const wchar_t *expression,
+
+ # if defined _MSC_VER
+
+-static void cdecl
++static void __cdecl
+ gl_msvc_invalid_parameter_handler (const wchar_t *expression,
+ const wchar_t *function,
+ const wchar_t *file,
+@@ -94,7 +94,7 @@ gl_msvc_inval_current (void)
+ }
+ }
+
+-static void cdecl
++static void __cdecl
+ gl_msvc_invalid_parameter_handler (const wchar_t *expression,
+ const wchar_t *function,
+ const wchar_t *file,
diff --git a/tags/fred-0.2.0/hivex_patches/hivex_mmap.patch b/tags/fred-0.2.0/hivex_patches/hivex_mmap.patch
new file mode 100644
index 0000000..69965a2
--- /dev/null
+++ b/tags/fred-0.2.0/hivex_patches/hivex_mmap.patch
@@ -0,0 +1,93 @@
+diff --git a/lib/hivex.c b/lib/hivex.c
+index 4b9fcf0..374e435 100644
+--- a/lib/hivex.c
++++ b/lib/hivex.c
+@@ -30,7 +30,11 @@
+ #include <unistd.h>
+ #include <errno.h>
+ #include <iconv.h>
+-#include <sys/mman.h>
++#ifndef __MINGW32__
++ #include <sys/mman.h>
++#else
++ #include <windows.h>
++#endif
+ #include <sys/stat.h>
+ #include <assert.h>
+
+@@ -63,6 +67,10 @@ static size_t utf16_string_len_in_bytes_max (const char *str, size_t len);
+ struct hive_h {
+ char *filename;
+ int fd;
++#ifdef __MINGW32__
++ HANDLE winmap;
++#endif
++
+ size_t size;
+ int msglvl;
+ int writable;
+@@ -312,9 +320,21 @@ hivex_open (const char *filename, int flags)
+ h->size = statbuf.st_size;
+
+ if (!h->writable) {
++#ifndef __MINGW32__
+ h->addr = mmap (NULL, h->size, PROT_READ, MAP_SHARED, h->fd, 0);
+ if (h->addr == MAP_FAILED)
+ goto error;
++#else
++ // Mingw / Gnulib does not support mmap, we have to use native win32api
++ // Create file mapping
++ h->winmap = CreateFileMapping ((HANDLE)_get_osfhandle(h->fd), NULL, PAGE_READONLY, 0, 0, NULL);
++ if (h->winmap == NULL)
++ goto error;
++ // Create map view
++ h->addr = MapViewOfFile (h->winmap, FILE_MAP_READ, 0, 0, h->size);
++ if (h->addr == NULL)
++ goto error;
++#endif
+
+ if (h->msglvl >= 2)
+ fprintf (stderr, "hivex_open: mapped file at %p\n", h->addr);
+@@ -532,11 +552,23 @@ hivex_open (const char *filename, int flags)
+ int err = errno;
+ if (h) {
+ free (h->bitmap);
++#ifndef __MINGW32__
+ if (h->addr && h->size && h->addr != MAP_FAILED) {
+- if (!h->writable)
++#else
++ if (h->addr && h->size && h->addr != NULL) {
++#endif
++ if (!h->writable) {
++#ifndef __MINGW32__
+ munmap (h->addr, h->size);
+- else
++#else
++ UnmapViewOfFile (h->addr);
++#endif
++ } else
+ free (h->addr);
++#ifdef __MINGW32__
++ if (!h->writable && h->winmap != NULL)
++ CloseHandle (h->winmap);
++#endif
+ }
+ if (h->fd >= 0)
+ close (h->fd);
+@@ -556,9 +588,14 @@ hivex_close (hive_h *h)
+ fprintf (stderr, "hivex_close\n");
+
+ free (h->bitmap);
+- if (!h->writable)
++ if (!h->writable) {
++#ifndef __MINGW32__
+ munmap (h->addr, h->size);
+- else
++#else
++ UnmapViewOfFile (h->addr);
++ CloseHandle (h->winmap);
++#endif
++ } else
+ free (h->addr);
+ if (h->fd >= 0)
+ r = close (h->fd);
diff --git a/tags/fred-0.2.0/hivex_patches/hivex_o_binary.patch b/tags/fred-0.2.0/hivex_patches/hivex_o_binary.patch
new file mode 100644
index 0000000..6286312
--- /dev/null
+++ b/tags/fred-0.2.0/hivex_patches/hivex_o_binary.patch
@@ -0,0 +1,38 @@
+From 726feff722dbaee93064ffc603d9979c26399928 Mon Sep 17 00:00:00 2001
+From: Gillen Daniel <gillen.daniel@gmail.com>
+Date: Thu, 27 Jun 2013 23:08:15 +0200
+Subject: [PATCH] hivex: Add O_BINARY flag to open calls for platforms where
+ this isn't the default (such as Win32)
+
+---
+ lib/hivex.c | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/lib/hivex.c b/lib/hivex.c
+index 040b1e7..86e5959 100644
+--- a/lib/hivex.c
++++ b/lib/hivex.c
+@@ -265,9 +265,9 @@ hivex_open (const char *filename, int flags)
+ goto error;
+
+ #ifdef O_CLOEXEC
+- h->fd = open (filename, O_RDONLY | O_CLOEXEC);
++ h->fd = open (filename, O_RDONLY | O_CLOEXEC | O_BINARY);
+ #else
+- h->fd = open (filename, O_RDONLY);
++ h->fd = open (filename, O_RDONLY | O_BINARY);
+ #endif
+ if (h->fd == -1)
+ goto error;
+@@ -2261,7 +2261,7 @@ hivex_commit (hive_h *h, const char *filename, int flags)
+ }
+
+ filename = filename ? : h->filename;
+- int fd = open (filename, O_WRONLY|O_CREAT|O_TRUNC|O_NOCTTY, 0666);
++ int fd = open (filename, O_WRONLY|O_CREAT|O_TRUNC|O_NOCTTY|O_BINARY, 0666);
+ if (fd == -1)
+ return -1;
+
+--
+1.7.10.4
+
diff --git a/tags/fred-0.2.0/macros.h b/tags/fred-0.2.0/macros.h
new file mode 100644
index 0000000..89daaa1
--- /dev/null
+++ b/tags/fred-0.2.0/macros.h
@@ -0,0 +1,293 @@
+/*******************************************************************************
+* Copyright (c) 2011 by Gillen Daniel <gillen.dan@pinguin.lu> *
+* *
+* This file contains macros with some very often used code pieces. It should *
+* primarily make my everyday life easier and improve code portability. *
+* *
+* This program is free software: you can redistribute it and/or modify it *
+* under the terms of the GNU General Public License as published by the Free *
+* Software Foundation, either version 3 of the License, or (at your option) *
+* any later version. *
+* *
+* This program is distributed in the hope that it will be useful, but WITHOUT *
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or *
+* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for *
+* more details. *
+* *
+* You should have received a copy of the GNU General Public License along with *
+* this program. If not, see <http://www.gnu.org/licenses/>. *
+*******************************************************************************/
+
+// Available macro groups:
+//
+// MACROS_FILE, MACROS_STRING, MACROS_WSTRING, MACROS_ENDIANNESS, MACROS_MUTEX,
+// MACROS_MEMORY, MACROS_LOGGING
+//
+// Define one or more of these before including this file to make them available
+
+#ifndef MACROS_H
+#define MACROS_H
+
+/*
+ * Macros for file access
+ *
+ * Will also include MACROS_LOGGING
+ */
+#ifdef MACROS_FILE
+ #include <stdio.h>
+
+ // These macros rely partly on logging macros, so those are needed too
+ #define MACROS_LOGGING
+
+ #undef FOPEN
+ #ifndef __APPLE__
+ #define FOPEN (FILE*)fopen64
+ #else
+ // Apple always uses fopen
+ #define FOPEN (FILE*)fopen
+ #endif // __APPLE__
+ #undef FCLOSE
+ #define FCLOSE(var,err_ret) { \
+ if(fclose(var)!=0) { \
+ LOG_ERROR("Couldn't close file!") \
+ err_ret; \
+ } \
+ }
+ #undef FSEEK
+ #define FSEEK(hfile,off,whence,err_ret) { \
+ if(fseeko(hfile,off,whence)!=0) { \
+ LOG_ERROR("Couldn't seek to offset %u!",off); \
+ err_ret; \
+ } \
+ }
+ #undef FTELL
+ #define FTELL(hfile,var,err_ret) { \
+ if((var=ftello(hfile))==-1) { \
+ LOG_ERROR("Unable to get file position!"); \
+ err_ret; \
+ } \
+ }
+ #undef FTELLSIZE
+ #define FTELLSIZE(hfile,var,err_ret) { \
+ FSEEK(hfile,0,SEEK_END,err_ret); \
+ FTELL(hfile,var,err_ret); \
+ rewind(hfile); \
+ }
+#endif
+
+/*
+ * Macros for string functions
+ *
+ * Will also include MACROS_MEMORY and MACROS_LOGGING
+ */
+#ifdef MACROS_STRING
+ #include <string.h>
+
+ // These macros rely partly on memory macros, so those are needed too
+ #define MACROS_MEMORY
+
+ #undef STRSET
+ #define STRSET(dst,src,err_ret) { \
+ MALLOC(dst,char*,(strlen(src)+1)*sizeof(char),err_ret) \
+ strcpy(dst,src); \
+ }
+ #undef STRNSET
+ #define STRNSET(dst,src,size,err_ret) { \
+ MALLOC(dst,char*,((size)+1)*sizeof(char),err_ret) \
+ strncpy(dst,src,size); \
+ (dst)[size]='\0'; \
+ }
+ #undef STRAPP
+ #define STRAPP(var1,var2,err_ret) { \
+ REALLOC(var1,char*,(strlen(var1)+strlen(var2)+1)*sizeof(char),err_ret) \
+ strcpy((var1)+strlen(var1),var2); \
+ }
+ #undef STRNAPP
+ #define STRNAPP(var1,var2,size,err_ret) { \
+ REALLOC(var1,char*,(strlen(var1)+(size)+1)*sizeof(char),err_ret) \
+ (var1)[strlen(var1)+(size)]='\0'; \
+ strncpy((var1)+strlen(var1),var2,size); \
+ }
+#endif
+
+/*
+ * Macros for wide string functions
+ *
+ * Will also include MACROS_MEMORY and MACROS_LOGGING
+ */
+#ifdef MACROS_WSTRING
+ #include <string.h>
+
+ // These macros rely partly on memory macros, so those are needed too
+ #define MACROS_MEMORY
+
+ #undef WSTRSET
+ #define WSTRSET(dst,src,err_ret) { \
+ MALLOC(dst,wchar_t*,(wcslen(src)+1)*sizeof(wchar_t),err_ret) \
+ wcscpy(dst,src); \
+ }
+ #undef WSTRNSET
+ #define WSTRNSET(dst,src,size,err_ret) { \
+ MALLOC(dst,wchar_t*,((size)+1)*sizeof(wchar_t),err_ret) \
+ wcsncpy(dst,src,size); \
+ (dst)[size]=L'\0'; \
+ }
+#endif
+
+/*
+ * Macros for endianness conversion
+ */
+#ifdef MACROS_ENDIANNESS
+ #include <inttypes.h>
+ #include <endian.h>
+
+ #undef LE16TOH
+ #define LE16TOH(var) le16toh(var)
+ #undef BE16TOH
+ #define BE16TOH(var) be16toh(var)
+ #undef LE32TOH
+ #define LE32TOH(var) le32toh(var)
+ #undef BE32TOH
+ #define BE32TOH(var) be32toh(var)
+ #undef LE64TOH
+ #define LE64TOH(var) le64toh(var)
+ #undef BE64TOH
+ #define BE64TOH(var) be64toh(var)
+ #undef HTOLE16
+ #define HTOLE16(var) htole16(var)
+ #undef HTOBE16
+ #define HTOBE16(var) htobe16(var)
+ #undef HTOLE32
+ #define HTOLE32(var) htole32(var)
+ #undef HTOBE32
+ #define HTOBE32(var) htobe32(var)
+ #undef HTOLE64
+ #define HTOLE64(var) htole64(var)
+ #undef HTOBE64
+ #define HTOBE64(var) htobe64(var)
+ #undef UTF16LETOH
+ #define UTF16LETOH(buf,buf_len) { \
+ for(int buf_off=0;buf_off<((buf_len)-1);buf_off+=2) { \
+ *((uint16_t*)((buf)+buf_off))=LE16TOH(*((uint16_t*)((buf)+buf_off))); \
+ } \
+ }
+ #undef UTF16BETOH
+ #define UTF16BETOH(buf,buf_len) { \
+ for(int buf_off=0;buf_off<((buf_len)-1);buf_off+=2) { \
+ *((uint16_t*)((buf)+buf_off))=BE16TOH(*((uint16_t*)((buf)+buf_off))); \
+ } \
+ }
+ #undef HTOUTF16LE
+ #define HTOUTF16LE(buf,buf_len) { \
+ for(int buf_off=0;buf_off<((buf_len)-1);buf_off+=2) { \
+ *((uint16_t*)((buf)+buf_off))=HTOLE16(*((uint16_t*)((buf)+buf_off))); \
+ } \
+ }
+ #undef HTOUTF16BE
+ #define HTOUTF16BE(buf,buf_len) { \
+ for(int buf_off=0;buf_off<((buf_len)-1);buf_off+=2) { \
+ *((uint16_t*)((buf)+buf_off))=HTOBE16(*((uint16_t*)((buf)+buf_off))); \
+ } \
+ }
+#endif
+
+/*
+ * Macros for mutex access
+ */
+#ifdef MACROS_MUTEX
+ #include <pthread.h>
+
+ #undef MUTEX_INIT
+ #define MUTEX_INIT(var) { \
+ pthread_mutex_init(&(var),NULL); \
+ }
+ #undef MUTEX_DESTROY
+ #define MUTEX_DESTROY(var) { \
+ pthread_mutex_destroy(&(var)); \
+ }
+ #undef MUTEX_LOCK
+ #define MUTEX_LOCK(var) { \
+ pthread_mutex_lock(&(var)); \
+ }
+ #undef MUTEX_UNLOCK
+ #define MUTEX_UNLOCK(var) { \
+ pthread_mutex_unlock(&(var)); \
+ }
+#endif
+
+/*
+ * Macros for memory management
+ *
+ * Will also include MACROS_LOGGING!
+ */
+#ifdef MACROS_MEMORY
+ #include <stdlib.h>
+
+ // These macros rely partly on logging macros, so those are needed too
+ #define MACROS_LOGGING
+
+ #undef MALLOC
+ #define MALLOC(var,var_type,size,err_ret) { \
+ (var)=(var_type)malloc(size); \
+ if((var)==NULL) { \
+ LOG_ERROR("Couldn't allocate memmory!\n"); \
+ err_ret; \
+ } \
+ }
+ #undef REALLOC
+ #define REALLOC(var,var_type,size,err_ret) { \
+ (var)=(var_type)realloc((var),size); \
+ if((var)==NULL) { \
+ LOG_ERROR("Couldn't allocate memmory!\n"); \
+ err_ret; \
+ } \
+ }
+ #undef FREE
+ #define FREE(var) free(var)
+#endif
+
+/*
+ * Macros to ease debugging and error reporting
+ *
+ * These require the following function to be implemented somewhere:
+ *
+ * #include <stdio.h>
+ * #include <stdarg.h>
+ *
+ * static void LogMessage(char *p_message_type,
+ * char *p_calling_function,
+ * int line,
+ * char *p_message,
+ * ...)
+ * {
+ * va_list VaList;
+ * // Print message "header"
+ * printf("%s: %s@%u : ",
+ * p_message_type,
+ * p_calling_function,
+ * line);
+ * // Print message with variable parameters
+ * va_start(VaList,p_message);
+ * vprintf(p_message,VaList);
+ * va_end(VaList);
+ * printf("\n");
+ * }
+ */
+#ifdef MACROS_LOGGING
+ #undef LOG_ERROR
+ #define LOG_ERROR(...) \
+ LogMessage("ERROR",(char*)__FUNCTION__,__LINE__,__VA_ARGS__);
+ #undef LOG_DEBUG
+ #define LOG_DEBUG(...) { \
+ LogMessage("DEBUG",(char*)__FUNCTION__,__LINE__,__VA_ARGS__); \
+ }
+#endif
+
+#endif // MACROS_H
+
+/*
+ ----- Change history -----
+ 20130611: * Added ability to only include specific macro groups.
+ 20110428: * Initial release.
+*/
+
diff --git a/tags/fred-0.2.0/main.cpp b/tags/fred-0.2.0/main.cpp
new file mode 100644
index 0000000..c99602d
--- /dev/null
+++ b/tags/fred-0.2.0/main.cpp
@@ -0,0 +1,158 @@
+/*******************************************************************************
+* fred Copyright (c) 2011-2020 by Gillen Daniel <gillen.dan@pinguin.lu> *
+* *
+* Forensic Registry EDitor (fred) is a cross-platform M$ registry hive editor *
+* with special feautures useful during forensic analysis. *
+* *
+* This program is free software: you can redistribute it and/or modify it *
+* under the terms of the GNU General Public License as published by the Free *
+* Software Foundation, either version 3 of the License, or (at your option) *
+* any later version. *
+* *
+* This program is distributed in the hope that it will be useful, but WITHOUT *
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or *
+* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for *
+* more details. *
+* *
+* You should have received a copy of the GNU General Public License along with *
+* this program. If not, see <http://www.gnu.org/licenses/>. *
+*******************************************************************************/
+
+#include <QApplication>
+#include <QStringList>
+
+#include <stdio.h>
+
+#include "mainwindow.h"
+#include "argparser.h"
+#include "compileinfo.h"
+#include "reportengine.h"
+#include "registryhive.h"
+
+// Forward declarations
+void PrintUsage();
+void DumpReport(QString report_template, QString hive_file);
+
+// Main entry point
+int main(int argc, char *argv[]) {
+ // Disable output buffering
+ setbuf(stdout,NULL);
+
+ // Init QApplication
+ QApplication a(argc, argv);
+
+#define PRINT_HEADER { \
+ printf("%s v%s %s\n\n",APP_NAME,APP_VERSION,APP_COPYRIGHT); \
+}
+#define PRINT_HEADER_AND_USAGE { \
+ PRINT_HEADER; \
+ PrintUsage(); \
+}
+#define PRINT_VERSION printf("%s\n",APP_VERSION);
+#define PRINT_UNKNOWN_ARG_ERROR(s) { \
+ PRINT_HEADER; \
+ printf("ERROR: Unknown command line argument '%s'!\n\n",s); \
+ PrintUsage(); \
+}
+
+ // Parse command line args
+ ArgParser args(a.arguments());
+ if(!args.ParseArgs()) {
+ PRINT_HEADER;
+ printf("ERROR: %s\n\n",args.GetErrorMsg().toLatin1().constData());
+ PrintUsage();
+ exit(1);
+ }
+
+ // Check command line args for correctness
+ if(args.IsSet("dump-report")) {
+ if(args.GetArgVal("dump-report")=="") {
+ PRINT_HEADER;
+ printf("ERROR: --dump-report specified without a report file!\n\n");
+ PrintUsage();
+ exit(1);
+ }
+ if(!args.IsSet("hive-file")) {
+ PRINT_HEADER;
+ printf("ERROR: --dump-report specified without a hive file!\n\n");
+ PrintUsage();
+ exit(1);
+ }
+ }
+ if(args.IsSet("fullscreen") && args.IsSet("maximized")) {
+ PRINT_HEADER;
+ printf("ERROR: --fullscreen and --maximized cannot be specified both!\n\n");
+ PrintUsage();
+ exit(1);
+ }
+
+ // React on some command line args early
+ if(args.IsSet("?") || args.IsSet("h") || args.IsSet("help")) {
+ PRINT_HEADER_AND_USAGE;
+ exit(0);
+ }
+ if(args.IsSet("v") || args.IsSet("version")) {
+ PRINT_VERSION;
+ exit(0);
+ }
+ if(args.IsSet("dump-report")) {
+ // Dump report to stdout
+ DumpReport(args.GetArgVal("dump-report"),args.GetArgVal("hive-file"));
+ exit(0);
+ }
+
+#undef PRINT_UNKNOWN_ARG_ERROR
+#undef PRINT_VERSION
+#undef PRINT_HEADER_AND_USAGE
+#undef PRINT_HEADER
+
+ // Create and show main window
+ MainWindow w(&args);
+ w.show();
+
+ return a.exec();
+}
+
+void PrintUsage() {
+ printf("Usage:\n");
+ printf(" %s [opts] [hive]\n\n",
+ qApp->arguments().at(0).toLatin1().constData());
+ printf("Options:\n");
+ printf(" opts:\n");
+ printf(" --dump-report=FILE : Dump the specified report to stdout.\n");
+ printf(" --fullscreen : Display main window in fullscreen mode.\n");
+ printf(" -h, -?, --help : Display this help message.\n");
+ printf(" --maximized : Display main window in maximized mode.\n");
+ printf(" -v, --version : Display version info.\n");
+ printf(" hive:\n");
+ printf(" Open / Use the specified hive file.\n");
+
+ printf("\n");
+}
+
+void DumpReport(QString report_template, QString hive_file) {
+ RegistryHive *p_hive=new RegistryHive();
+ ReportEngine *p_report_engine=new ReportEngine(NULL);
+
+ // Open hive
+ if(!p_hive->Open(hive_file,true)) {
+ printf("ERROR: Unable to open hive file '%s'!\n",
+ hive_file.toLatin1().constData());
+ exit(1);
+ }
+
+ // Generate report
+ QString result="";
+ p_report_engine->GenerateReport(p_hive,
+ report_template,
+ result,
+ true);
+
+ // Close hive and free DataReporter and RegistryHive
+ p_hive->Close();
+ delete p_report_engine;
+ delete p_hive;
+
+ // Print result to stdout
+ printf("%s",result.toLatin1().constData());
+}
diff --git a/tags/fred-0.2.0/mainwindow.cpp b/tags/fred-0.2.0/mainwindow.cpp
new file mode 100644
index 0000000..c6f0808
--- /dev/null
+++ b/tags/fred-0.2.0/mainwindow.cpp
@@ -0,0 +1,1106 @@
+/*******************************************************************************
+* fred Copyright (c) 2011-2020 by Gillen Daniel <gillen.dan@pinguin.lu> *
+* *
+* Forensic Registry EDitor (fred) is a cross-platform M$ registry hive editor *
+* with special feautures useful during forensic analysis. *
+* *
+* This program is free software: you can redistribute it and/or modify it *
+* under the terms of the GNU General Public License as published by the Free *
+* Software Foundation, either version 3 of the License, or (at your option) *
+* any later version. *
+* *
+* This program is distributed in the hope that it will be useful, but WITHOUT *
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or *
+* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for *
+* more details. *
+* *
+* You should have received a copy of the GNU General Public License along with *
+* this program. If not, see <http://www.gnu.org/licenses/>. *
+*******************************************************************************/
+
+#include <QFileDialog>
+#include <QMessageBox>
+#include <QStringList>
+#include <QDesktopWidget>
+#include <QDir>
+#include <QSplitter>
+#include <QListIterator>
+#include <QInputDialog>
+
+#include <QDebug>
+
+#include "mainwindow.h"
+#include "ui_mainwindow.h"
+#include "dlgabout.h"
+#include "dlgreportchooser.h"
+#include "dlgreportviewer.h"
+#include "dlgsearch.h"
+#include "dlgpreferences.h"
+#include "dlgaddkey.h"
+
+#include "compileinfo.h"
+
+/*******************************************************************************
+ * Public
+ ******************************************************************************/
+
+/*
+ * Constructor
+ */
+MainWindow::MainWindow(ArgParser *p_arg_parser) :
+ QMainWindow(0), ui(new Ui::MainWindow)
+{
+ ui->setupUi(this);
+
+ // Initialize private vars
+ this->p_args=p_arg_parser;
+ this->p_hive=new RegistryHive(this);
+ this->is_hive_open=false;
+ this->p_reg_node_tree_model=NULL;
+ this->p_reg_node_tree_model_proxy=NULL;
+ this->p_reg_key_table_model=NULL;
+ this->p_search_thread=NULL;
+ this->search_result_widgets.clear();
+
+ // Init and load settings
+ this->p_settings=new Settings(this);
+ this->is_hive_writable=!this->p_settings->GetOpenHivesReadOnly();
+
+ // Set main window size
+ QByteArray geometry=this->p_settings->GetWindowGeometry("MainWindow");
+ if(!geometry.isEmpty()) {
+ // Restore saved geometry
+ this->restoreGeometry(geometry);
+ } else {
+ // No saved geometry, calculate and set default
+ int cur_screen=QApplication::desktop()->screenNumber(this);
+ int window_width=
+ QApplication::desktop()->availableGeometry(cur_screen).width()*0.5;
+ int window_height=
+ QApplication::desktop()->availableGeometry(cur_screen).height()*0.5;
+ int window_x=
+ (QApplication::desktop()->availableGeometry(cur_screen).width()/2)-
+ (window_width/2);
+ int window_y=
+ (QApplication::desktop()->availableGeometry(cur_screen).height()/2)-
+ (window_height/2);
+ this->setGeometry(window_x,
+ window_y,
+ window_width,
+ window_height);
+ }
+
+ // Create widgets
+ this->p_horizontal_splitter=new QSplitter();
+ this->p_horizontal_splitter->setOrientation(Qt::Horizontal);
+
+ this->p_node_tree=new RegistryNodeTree(this->p_horizontal_splitter);
+
+ this->p_vertical_splitter=new QSplitter(this->p_horizontal_splitter);
+ this->p_vertical_splitter->setOrientation(Qt::Vertical);
+
+ this->p_key_table=new RegistryKeyTable(this->p_vertical_splitter);
+
+ this->p_tab_widget=new TabWidget(this->p_vertical_splitter);
+
+ this->p_hex_edit_widget=new HexEditWidget();
+ this->p_hex_edit_widget->setEnabled(false);
+
+ // Add hexedit page to tab_widget
+ this->p_tab_widget->addTab(this->p_hex_edit_widget,tr("Hex viewer"));
+
+ // Add widgets to their splitters
+ this->p_vertical_splitter->addWidget(this->p_key_table);
+ this->p_vertical_splitter->addWidget(this->p_tab_widget);
+
+ this->p_horizontal_splitter->addWidget(this->p_node_tree);
+ this->p_horizontal_splitter->addWidget(this->p_vertical_splitter);
+
+ // Set stretch factors
+ QSizePolicy node_tree_policy=this->p_node_tree->sizePolicy();
+ node_tree_policy.setHorizontalStretch(1);
+ node_tree_policy.setVerticalStretch(100);
+ this->p_node_tree->setSizePolicy(node_tree_policy);
+
+ QSizePolicy vertical_splitter_policy=this->p_vertical_splitter->sizePolicy();
+ vertical_splitter_policy.setHorizontalStretch(4);
+ vertical_splitter_policy.setVerticalStretch(100);
+ this->p_vertical_splitter->setSizePolicy(vertical_splitter_policy);
+
+ QSizePolicy key_table_policy=this->p_key_table->sizePolicy();
+ key_table_policy.setVerticalStretch(5);
+ key_table_policy.setHorizontalStretch(100);
+ this->p_key_table->setSizePolicy(key_table_policy);
+
+ QSizePolicy tab_widget_policy=this->p_tab_widget->sizePolicy();
+ tab_widget_policy.setVerticalStretch(2);
+ tab_widget_policy.setHorizontalStretch(200);
+ this->p_tab_widget->setSizePolicy(tab_widget_policy);
+
+ // Connect signals
+ this->connect(this->p_node_tree,
+ SIGNAL(clicked(QModelIndex)),
+ this,
+ SLOT(SlotNodeTreeClicked(QModelIndex)));
+ this->connect(this->p_node_tree,
+ SIGNAL(activated(QModelIndex)),
+ this,
+ SLOT(SlotNodeTreeClicked(QModelIndex)));
+ this->connect(this->p_node_tree,
+ SIGNAL(CurrentItemChanged(QModelIndex)),
+ this,
+ SLOT(SlotNodeTreeClicked(QModelIndex)));
+ this->connect(this->p_key_table,
+ SIGNAL(clicked(QModelIndex)),
+ this,
+ SLOT(SlotKeyTableClicked(QModelIndex)));
+ this->connect(this->p_key_table,
+ SIGNAL(doubleClicked(QModelIndex)),
+ this,
+ SLOT(SlotKeyTableDoubleClicked(QModelIndex)));
+ this->connect(this->p_key_table,
+ SIGNAL(CurrentItemChanged(QModelIndex)),
+ this,
+ SLOT(SlotKeyTableClicked(QModelIndex)));
+ this->connect(this->p_tab_widget,
+ SIGNAL(tabCloseRequested(int)),
+ this,
+ SLOT(SlotTabCloseButtonClicked(int)));
+ this->connect(this->p_node_tree,
+ SIGNAL(SignalAddNode(QModelIndex)),
+ this,
+ SLOT(SlotAddNode(QModelIndex)));
+ this->connect(this->p_node_tree,
+ SIGNAL(SignalDeleteNode(QModelIndex)),
+ this,
+ SLOT(SlotDeleteNode(QModelIndex)));
+ this->connect(this->p_key_table,
+ SIGNAL(SignalAddKey()),
+ this,
+ SLOT(SlotAddKey()));
+ this->connect(this->p_key_table,
+ SIGNAL(SignalEditKey(QModelIndex)),
+ this,
+ SLOT(SlotEditKey(QModelIndex)));
+ this->connect(this->p_key_table,
+ SIGNAL(SignalDeleteKey(QModelIndex)),
+ this,
+ SLOT(SlotDeleteKey(QModelIndex)));
+
+ // Add central widget
+ this->setCentralWidget(this->p_horizontal_splitter);
+ this->centralWidget()->setContentsMargins(4,4,4,0);
+
+ // Set window title
+ this->UpdateWindowTitle();
+
+ // Create and update recently opened menu
+ this->p_recently_opened_menu=new QMenu(this);
+ this->ui->ActionRecentlyOpened->setMenu(this->p_recently_opened_menu);
+ this->UpdateRecentlyOpenedMenu();
+
+ // Update EnableWriteSupport menu according to defaults
+ this->UpdateEnableWriteSupportMenu();
+
+ // Load report templates
+ this->p_reports=new Reports(this->p_settings);
+
+ // Finally, react on some command line arguments
+ if(this->p_args->IsSet("maximized")) {
+ this->setWindowState(Qt::WindowMaximized);
+ }
+ if(this->p_args->IsSet("fullscreen")) {
+ this->setWindowState(Qt::WindowFullScreen);
+ }
+ if(this->p_args->IsSet("hive-file")) {
+ // Resolve path
+ this->OpenHive(QDir(this->p_args->GetArgVal("hive-file")).canonicalPath());
+ }
+}
+
+/*
+ * Destructor
+ */
+MainWindow::~MainWindow() {
+ if(this->is_hive_open) {
+ this->p_hive->Close();
+ }
+
+ // Delete created objects
+ delete this->p_reports;
+ this->ClearRecentlyOpenedMenu();
+ delete this->p_recently_opened_menu;
+ delete this->p_hex_edit_widget;
+ delete this->p_tab_widget;
+ delete this->p_key_table;
+ delete this->p_vertical_splitter;
+ delete this->p_node_tree;
+ delete this->p_horizontal_splitter;
+ delete this->p_settings;
+ delete this->p_hive;
+ delete ui;
+}
+
+/*******************************************************************************
+ * Protected
+ ******************************************************************************/
+
+/*
+ * closeEvent
+ */
+void MainWindow::closeEvent(QCloseEvent *p_event) {
+ Q_UNUSED(p_event)
+
+ // Make sure the user can save any changes
+ // TODO: If saving fails, let the user cancel closing
+ this->SaveHiveChanges();
+
+ // Save window position and size on exit
+ this->p_settings->SetWindowGeometry("MainWindow",this->saveGeometry());
+ QMainWindow::closeEvent(p_event);
+}
+
+/*******************************************************************************
+ * Private slots
+ ******************************************************************************/
+
+/*
+ * on_ActionOpenHive_triggered
+ */
+void MainWindow::on_ActionOpenHive_triggered() {
+ QString hive_file="";
+
+ hive_file=QFileDialog::getOpenFileName(this,
+ tr("Open registry hive"),
+ this->p_settings->GetLastOpenLocation(),
+ tr("All files (*)"));
+ if(hive_file=="") return;
+
+ this->OpenHive(hive_file);
+}
+
+/*
+ * on_ActionSave_triggered
+ */
+void MainWindow::on_ActionSave_triggered() {
+ if(!(this->is_hive_open && this->is_hive_writable)) {
+ this->ui->ActionSave->setEnabled(false);
+ return;
+ }
+ this->SaveHiveChanges(true);
+ if(!this->p_hive->HasChangesToCommit()) {
+ this->ui->ActionSave->setEnabled(false);
+ }
+}
+
+/*
+ * on_ActionCloseHive_triggered
+ */
+void MainWindow::on_ActionCloseHive_triggered() {
+ // Make sure the user can save any changes
+ // TODO: If saving fails, let the user cancel closing
+ this->SaveHiveChanges();
+
+ if(this->is_hive_open) {
+ // Remove search results
+ while(this->p_tab_widget->count()>1) {
+ this->p_tab_widget->removeTab(this->p_tab_widget->count()-1);
+ delete this->search_result_widgets.at(this->p_tab_widget->count()-1);
+ this->search_result_widgets.removeLast();
+ }
+
+ // Delete models
+ if(this->p_reg_node_tree_model!=NULL) {
+ this->p_node_tree->setModel(NULL);
+ delete this->p_reg_node_tree_model_proxy;
+ delete this->p_reg_node_tree_model;
+ this->p_reg_node_tree_model_proxy=NULL;
+ this->p_reg_node_tree_model=NULL;
+ }
+ if(this->p_reg_key_table_model!=NULL) {
+ this->p_key_table->setModel(NULL);
+ delete this->p_reg_key_table_model;
+ this->p_reg_key_table_model=NULL;
+ }
+
+ // Remove any data from hex edit and data interpreter
+ this->p_hex_edit_widget->SetData(QByteArray());
+ this->p_hex_edit_widget->setEnabled(false);
+
+ // Close hive
+ this->p_hive->Close();
+
+ this->is_hive_open=false;
+ this->is_hive_writable=!this->p_settings->GetOpenHivesReadOnly();
+ this->UpdateWindowTitle();
+ this->UpdateMenuStates();
+ this->UpdateEnableWriteSupportMenu();
+ }
+}
+
+/*
+ * on_ActionQuit_triggered
+ */
+void MainWindow::on_ActionQuit_triggered() {
+ qApp->exit();
+}
+
+/*
+ * on_ActionFind_triggered
+ */
+void MainWindow::on_ActionFind_triggered() {
+ DlgSearch dlg_search(this);
+ if(dlg_search.exec()==QDialog::Accepted) {
+ // Create search thread and connect needed signals/slots
+ this->p_search_thread=new ThreadSearch(this);
+
+ // Add new search widget to tabwidget and to internal widget list
+ SearchResultWidget *p_search_widget=
+ new SearchResultWidget(this->p_tab_widget);
+ p_search_widget->setEnabled(false);
+ this->search_result_widgets.append(p_search_widget);
+
+ this->connect(p_search_widget,
+ SIGNAL(doubleClicked(QModelIndex)),
+ this,
+ SLOT(SlotSearchResultWidgetDoubleClicked(QModelIndex)));
+
+ this->p_tab_widget->addTab(p_search_widget,tr("Search results"),true);
+ this->p_tab_widget->setCurrentIndex(this->p_tab_widget->count()-1);
+
+ // Connect search thread to result widget
+ this->connect(this->p_search_thread,
+ SIGNAL(SignalFoundMatch(ThreadSearch::eMatchType,
+ QString,QString,QString)),
+ p_search_widget,
+ SLOT(SlotFoundMatch(ThreadSearch::eMatchType,
+ QString,QString,QString)));
+ this->connect(this->p_search_thread,
+ SIGNAL(finished()),
+ this,
+ SLOT(SlotSearchFinished()));
+ this->connect(this->p_search_thread,
+ SIGNAL(finished()),
+ p_search_widget,
+ SLOT(SlotSearchFinished()));
+
+ // Start searching
+ this->ui->ActionFind->setEnabled(false);
+ p_search_thread->Search(this->p_hive->Filename(),
+ dlg_search.Keywords(),
+ dlg_search.SearchNodeNames(),
+ dlg_search.SearchKeyNames(),
+ dlg_search.SearchKeyValues());
+ }
+}
+
+/*
+ * on_ActionEnableWriteSupport_triggered
+ */
+void MainWindow::on_ActionEnableWriteSupport_triggered() {
+ // There might be unsaved changes, give the user the chance to save them
+ if(!this->SaveHiveChanges()) return;
+
+ // Reopen hive
+ // Reopen has read_only as parameter. Thus we need to pass
+ // !this->is_hive_writable which is the case when passing
+ // this->is_hive_writable as long as we do it before actually changing our
+ // internal state.
+ if(!this->p_hive->Reopen(this->is_hive_writable)) {
+ QMessageBox::critical(this,
+ tr("Error"),
+ tr("Unable to switch write-support: %1")
+ .arg(this->p_hive->GetErrorMsg()));
+ return;
+ }
+
+ // Switch internal state
+ this->is_hive_writable=!this->is_hive_writable;
+ this->UpdateEnableWriteSupportMenu();
+ this->p_node_tree->SetWritable(this->is_hive_writable);
+ this->p_key_table->SetWritable(this->is_hive_writable);
+ this->UpdateWindowTitle(this->p_hive->Filename());
+}
+
+/*
+ * on_ActionPreferences_triggered
+ */
+void MainWindow::on_ActionPreferences_triggered() {
+ DlgPreferences dlg_preferences(this->p_settings,this);
+ dlg_preferences.exec();
+ // Update vars, objects and GUI elements which might be affected by the new
+ // settings
+ this->UpdateRecentlyOpenedMenu();
+ this->is_hive_writable=!this->p_settings->GetOpenHivesReadOnly();
+ this->UpdateEnableWriteSupportMenu();
+ this->p_reports->LoadReportTemplates();
+}
+
+/*
+ * on_ActionGenerateReport_triggered
+ */
+void MainWindow::on_ActionGenerateReport_triggered() {
+ DlgReportChooser dlg_repchooser(this->p_reports,
+ this->p_hive->HiveTypeToString(
+ this->p_hive->HiveType()),
+ this->p_settings,
+ this);
+ if(dlg_repchooser.exec()==QDialog::Accepted) {
+ QList<ReportTemplate*> selected_reports;
+
+ // Get selected report
+ selected_reports=dlg_repchooser.GetSelectedReports();
+ if(selected_reports.isEmpty()) return;
+
+ // Generate report(s)
+ QString report_result="";
+ if(this->p_reports->GenerateReport(this->p_hive,
+ selected_reports,
+ report_result,
+ false))
+ {
+ // Report generation was successfull, show reports
+ DlgReportViewer *p_dlg_report_view=new DlgReportViewer(report_result,
+ this->p_settings,
+ this);
+ p_dlg_report_view->exec();
+ delete p_dlg_report_view;
+ } else {
+ // TODO: Inform user
+ qDebug()<<"ERROR: "<<report_result;
+ }
+ }
+}
+
+/*
+ * on_ActionReloadReportTemplates_triggered
+ */
+void MainWindow::on_ActionReloadReportTemplates_triggered() {
+ this->p_reports->LoadReportTemplates();
+}
+
+/*
+ * on_ActionAboutQt_triggered
+ */
+void MainWindow::on_ActionAboutQt_triggered() {
+ QMessageBox::aboutQt(this,tr("About Qt"));
+}
+
+/*
+ * on_ActionAboutFred_triggered
+ */
+void MainWindow::on_ActionAboutFred_triggered() {
+ DlgAbout dlg_about(this);
+ dlg_about.exec();
+}
+
+/*
+ * SlotNodeTreeClicked
+ */
+void MainWindow::SlotNodeTreeClicked(QModelIndex index) {
+ QString node_path;
+
+ if(!index.isValid()) return;
+
+ // Map proxy index to tree model index
+ index=this->p_reg_node_tree_model_proxy->mapToSource(index);
+
+ // Built node path
+ node_path=this->p_reg_node_tree_model->GetNodePath(index);
+
+ // Create table model and attach it to the table view
+ if(this->p_reg_key_table_model!=NULL) {
+ // If a previous model was set, delete it and clear hexedit etc...
+ this->p_key_table->setModel(NULL);
+ delete this->p_reg_key_table_model;
+ this->p_hex_edit_widget->SetData(QByteArray());
+ }
+ this->p_reg_key_table_model=new RegistryKeyTableModel(this->p_hive,node_path);
+ this->p_key_table->setModel(this->p_reg_key_table_model,
+ this->is_hive_writable);
+ // Set focus back to nodetree to be able to navigate with keyboard
+ this->p_node_tree->setFocus();
+}
+
+/*
+ * SlotKeyTableClicked
+ */
+void MainWindow::SlotKeyTableClicked(QModelIndex index) {
+ if(!index.isValid()) return;
+
+ this->selected_key_value=
+ this->p_reg_key_table_model->data(this->p_reg_key_table_model->
+ index(index.row(),2),
+ RegistryKeyTableModel::
+ AdditionalRoles_GetRawData)
+ .toByteArray();
+ this->p_hex_edit_widget->SetData(this->selected_key_value);
+ // Set focus back to nodetree to be able to navigate with keyboard
+ this->p_key_table->setFocus();
+}
+
+/*
+ * SlotKeyTableDoubleClicked
+ */
+void MainWindow::SlotKeyTableDoubleClicked(QModelIndex index) {
+ if(!index.isValid()) return;
+ if(!this->is_hive_open) return;
+
+ if(this->is_hive_writable) this->SlotEditKey(index);
+}
+
+/*
+ * SlotSearchFinished
+ */
+void MainWindow::SlotSearchFinished() {
+ delete this->p_search_thread;
+ this->p_search_thread=NULL;
+ this->ui->ActionFind->setEnabled(true);
+ // Enable result widget
+ this->search_result_widgets.last()->setEnabled(true);
+}
+
+/*
+ * SlotSearchResultWidgetDoubleClicked
+ */
+void MainWindow::SlotSearchResultWidgetDoubleClicked(QModelIndex index) {
+ SearchResultWidget *p_sender;
+ QString path;
+ QString match_type;
+ QString value;
+ QString key="";
+ int i;
+
+ if(!index.isValid()) return;
+
+ // Get pointer to sender
+ p_sender=(SearchResultWidget*)QObject::sender();
+
+ // Get path and matchtype
+ path=p_sender->item(index.row(),0)->text();
+ match_type=p_sender->item(index.row(),1)->text();
+ value=p_sender->item(index.row(),2)->text();
+
+ if(match_type==tr("Node name")) {
+ // Node name is not part of path. Add it
+ if(path=="\\") path.append(value);
+ else path.append("\\").append(value);
+ } else if(match_type==tr("Key name")) {
+ // Key name is stored in value
+ key=value;
+ } else if(match_type==tr("Key value")) {
+ // Key name is part of path. Save and remove it
+ QStringList nodes=path.split("\\",QString::SkipEmptyParts);
+ key=nodes.at(nodes.count()-1);
+ // Remove \<key name> from path
+ path.chop(key.length()+1);
+ }
+
+ // Expand treeview to correct node
+ QList<QModelIndex> indexes=
+ this->p_reg_node_tree_model->GetIndexListOf(path);
+ for(i=0;i<indexes.count();i++) {
+ indexes.replace(i,this->p_reg_node_tree_model_proxy->
+ mapFromSource(indexes.at(i)));
+ this->p_node_tree->expand(indexes.at(i));
+ }
+ if(indexes.count()>0) {
+ // Scroll to last expanded node, select it and update widgets
+ this->p_node_tree->scrollTo(indexes.at(indexes.count()-1),
+ QAbstractItemView::PositionAtCenter);
+ this->p_node_tree->selectionModel()->clear();
+ this->p_node_tree->selectionModel()->
+ select(indexes.at(indexes.count()-1),
+ QItemSelectionModel::ClearAndSelect |
+ QItemSelectionModel::Rows |
+ QItemSelectionModel::Current);
+ this->SlotNodeTreeClicked(indexes.at(indexes.count()-1));
+ }
+
+ // Select correct key if search matched on keay name / value
+ if(key!="") {
+ int row=this->p_reg_key_table_model->GetKeyRow(key);
+ this->p_key_table->clearSelection();
+ this->p_key_table->scrollTo(this->p_reg_key_table_model->index(row,0),
+ QAbstractItemView::PositionAtCenter);
+ this->p_key_table->selectRow(row);
+ this->SlotKeyTableClicked(this->p_reg_key_table_model->index(row,0));
+ }
+}
+
+/*
+ * SlotTabCloseButtonClicked
+ */
+void MainWindow::SlotTabCloseButtonClicked(int index) {
+ // Delete tab widget and remove tab
+ this->p_tab_widget->removeTab(index);
+ delete this->search_result_widgets.at(index-1);
+ this->search_result_widgets.removeAt(index-1);
+}
+
+/*
+ * SlotRecentlyOpenedFileClicked
+ */
+void MainWindow::SlotRecentlyOpenedFileClicked(bool checked) {
+ Q_UNUSED(checked)
+
+ QAction *p_sender=(QAction*)QObject::sender();
+ this->OpenHive(p_sender->text());
+}
+
+/*
+ * SlotAddNode
+ */
+void MainWindow::SlotAddNode(QModelIndex index) {
+ QString node_path;
+ int new_node_id;
+
+ if(!index.isValid()) return;
+
+ // Map proxy index to tree model index and get node path
+ index=this->p_reg_node_tree_model_proxy->mapToSource(index);
+ node_path=this->p_reg_node_tree_model->GetNodePath(index);
+
+ // Query user for a node name
+ bool ok=false;
+ QString node_name=QInputDialog::getText(this,
+ tr("Add node"),
+ tr("Please specify a name for the new node"),
+ QLineEdit::Normal,
+ QString(),
+ &ok);
+ if(ok) {
+ if((new_node_id=this->p_hive->AddNode(node_path,node_name))==0) {
+ QMessageBox::critical(this,
+ tr("Error"),
+ tr("Unable to create node '%1\\%2': %3!")
+ .arg(node_path,
+ node_name,
+ this->p_hive->GetErrorMsg()));
+ } else {
+ // Add node to model. We have to pass node_name as Ascii as utf8 names are
+ // not supported inside hives!
+ QModelIndex new_node_index=
+ this->p_reg_node_tree_model->AddNode(this->p_hive,
+ index,
+ new_node_id,
+ node_name.toLatin1());
+ // Now that node has been added, expand parent and select new node
+ this->p_node_tree->expand(
+ this->p_reg_node_tree_model_proxy->mapFromSource(index));
+ new_node_index=
+ this->p_reg_node_tree_model_proxy->mapFromSource(new_node_index);
+ this->p_node_tree->scrollTo(new_node_index,
+ QAbstractItemView::PositionAtCenter);
+ this->p_node_tree->selectionModel()->clear();
+ this->p_node_tree->selectionModel()->
+ select(new_node_index,
+ QItemSelectionModel::ClearAndSelect |
+ QItemSelectionModel::Rows |
+ QItemSelectionModel::Current);
+ // Finally update key table and enable Save menu
+ this->SlotNodeTreeClicked(new_node_index);
+ this->ui->ActionSave->setEnabled(true);
+ }
+ }
+}
+
+/*
+ * SlotDeleteNode
+ */
+void MainWindow::SlotDeleteNode(QModelIndex index) {
+ QString node_path;
+
+ if(!index.isValid()) return;
+
+ // Map proxy index to tree model index and get node path
+ index=this->p_reg_node_tree_model_proxy->mapToSource(index);
+ node_path=this->p_reg_node_tree_model->GetNodePath(index);
+
+ if(QMessageBox::warning(this,
+ tr("Delete node"),
+ tr("Are you sure you want to remove the node '%1' and all of its child nodes?").arg(node_path),
+ QMessageBox::Yes,
+ QMessageBox::No)==QMessageBox::Yes)
+ {
+ // Remove node from hive
+ if(!this->p_hive->DeleteNode(node_path)) {
+ QMessageBox::critical(this,
+ tr("Error"),
+ tr("Unable to delete node '%1': %2!")
+ .arg(node_path,this->p_hive->GetErrorMsg()));
+ return;
+ }
+
+ // Remove node from tree model and select nearest node
+ QModelIndex next_node_index=this->p_reg_node_tree_model->RemoveNode(index);
+ if(next_node_index.isValid()) {
+ next_node_index=
+ this->p_reg_node_tree_model_proxy->mapFromSource(next_node_index);
+ this->p_node_tree->selectionModel()->clear();
+ this->p_node_tree->selectionModel()->
+ select(next_node_index,
+ QItemSelectionModel::ClearAndSelect |
+ QItemSelectionModel::Rows |
+ QItemSelectionModel::Current);
+ }
+ // And finally update key table and enable Save menu
+ this->SlotNodeTreeClicked(next_node_index);
+ this->ui->ActionSave->setEnabled(true);
+ }
+}
+
+/*
+ * SlotAddKey
+ */
+void MainWindow::SlotAddKey() {
+ DlgAddKey dlg_add_key(this);
+ if(dlg_add_key.exec()==QDialog::Accepted) {
+ // Get selected parent node
+ QModelIndex parent_node=this->p_node_tree->currentIndex();
+ parent_node=this->p_reg_node_tree_model_proxy->mapToSource(parent_node);
+ QString parent_node_path=this->p_reg_node_tree_model->GetNodePath(parent_node);
+
+ // Add key
+ int new_key=this->p_hive->AddKey(parent_node_path,
+ dlg_add_key.KeyName(),
+ dlg_add_key.KeyType(),
+ dlg_add_key.KeyValue());
+ if(new_key==0) {
+ QMessageBox::critical(this,
+ tr("Error"),
+ tr("Unable to add key: %1")
+ .arg(this->p_hive->GetErrorMsg()));
+ return;
+ }
+
+ // Add new key to the key table model
+ QModelIndex new_key_index=
+ this->p_reg_key_table_model->AddKey(this->p_hive,new_key);
+ if(new_key_index.isValid()) {
+ this->p_key_table->clearSelection();
+ this->p_key_table->scrollTo(new_key_index,
+ QAbstractItemView::PositionAtCenter);
+ this->p_key_table->selectRow(new_key_index.row());
+ }
+ // Update key table and enable save menu
+ this->SlotKeyTableClicked(new_key_index);
+ this->ui->ActionSave->setEnabled(true);
+ }
+}
+
+/*
+ * SlotEditKey
+ */
+void MainWindow::SlotEditKey(QModelIndex index) {
+ if(!index.isValid()) return;
+
+ // Get current values
+ QString key_name=
+ this->p_reg_key_table_model->data(this->p_reg_key_table_model->
+ index(index.row(),
+ RegistryKeyTableModel::
+ ColumnContent_KeyName),
+ Qt::DisplayRole).toString();
+ QString key_value_type=
+ this->p_reg_key_table_model->data(this->p_reg_key_table_model->
+ index(index.row(),
+ RegistryKeyTableModel::
+ ColumnContent_KeyType),
+ Qt::DisplayRole).toString();
+ QByteArray key_value=
+ this->p_reg_key_table_model->data(this->p_reg_key_table_model->
+ index(index.row(),
+ RegistryKeyTableModel::
+ ColumnContent_KeyValue),
+ RegistryKeyTableModel::
+ AdditionalRoles_GetRawData).toByteArray();
+
+ // Exec update dialog
+ DlgAddKey dlg_update_key(this,key_name,key_value_type,key_value);
+ if(dlg_update_key.exec()==QDialog::Accepted) {
+ // Get selected parent node
+ QModelIndex parent_node=this->p_node_tree->currentIndex();
+ parent_node=this->p_reg_node_tree_model_proxy->mapToSource(parent_node);
+ QString parent_node_path=this->p_reg_node_tree_model->GetNodePath(parent_node);
+
+ // Update key
+ int new_key=this->p_hive->UpdateKey(parent_node_path,
+ dlg_update_key.KeyName(),
+ dlg_update_key.KeyType(),
+ dlg_update_key.KeyValue());
+ if(new_key==0) {
+ QMessageBox::critical(this,
+ tr("Error"),
+ tr("Unable to update key: %1")
+ .arg(this->p_hive->GetErrorMsg()));
+ return;
+ }
+
+ // Update key in key table model
+ QModelIndex new_key_index=
+ this->p_reg_key_table_model->UpdateKey(this->p_hive,new_key);
+ this->p_key_table->clearSelection();
+ if(new_key_index.isValid()) {
+ this->p_key_table->scrollTo(new_key_index,
+ QAbstractItemView::PositionAtCenter);
+ this->p_key_table->selectRow(new_key_index.row());
+ // TODO: Update geometry in case data has been added and is now expanding
+ // behind the right border
+ // Update HexEditWidget
+ }
+ // Update key table and enable Save menu
+ this->SlotKeyTableClicked(new_key_index);
+ this->ui->ActionSave->setEnabled(true);
+ }
+}
+
+/*
+ * SlotDeleteKey
+ */
+void MainWindow::SlotDeleteKey(QModelIndex index) {
+ if(!index.isValid()) return;
+
+ // Get selected key name
+ QString key_name=
+ this->p_reg_key_table_model->data(this->p_reg_key_table_model->
+ index(index.row(),
+ RegistryKeyTableModel::
+ ColumnContent_KeyName),
+ Qt::DisplayRole).toString();
+
+ // Get selected parent node
+ QModelIndex parent_node=this->p_node_tree->currentIndex();
+ parent_node=this->p_reg_node_tree_model_proxy->mapToSource(parent_node);
+ QString parent_node_path=this->p_reg_node_tree_model->GetNodePath(parent_node);
+
+ if(QMessageBox::warning(this,
+ tr("Delete key"),
+ tr("Are you sure you want to remove the key '%1\\%2'?")
+ .arg(parent_node_path,key_name),
+ QMessageBox::Yes,
+ QMessageBox::No)==QMessageBox::Yes)
+ {
+ // Remove key from hive
+ if(!this->p_hive->DeleteKey(parent_node_path,key_name)) {
+ QMessageBox::critical(this,
+ tr("Error"),
+ tr("Unable to delete key '%1\\%2': %3")
+ .arg(parent_node_path,
+ key_name,
+ this->p_hive->GetErrorMsg()));
+ return;
+ }
+ // Remove key from table model and update selection
+ QModelIndex new_key_index=this->p_reg_key_table_model->RemoveKey(index);
+ this->p_key_table->clearSelection();
+ if(new_key_index.isValid()) {
+ this->p_key_table->scrollTo(new_key_index,
+ QAbstractItemView::PositionAtCenter);
+ this->p_key_table->selectRow(new_key_index.row());
+ }
+ // Enable Save menu
+ this->ui->ActionSave->setEnabled(true);
+ }
+}
+
+/*******************************************************************************
+ * Private
+ ******************************************************************************/
+
+/*
+ * OpenHive
+ */
+void MainWindow::OpenHive(QString hive_file) {
+ // Make sure hive_file has native directory separators
+ hive_file=QDir::toNativeSeparators(hive_file);
+
+ // Update last open location
+ this->p_settings->SetLastOpenLocation(
+ hive_file.left(hive_file.lastIndexOf(QDir::separator())));
+
+ // If another hive is currently open, close it
+ if(this->is_hive_open) this->on_ActionCloseHive_triggered();
+
+ // Try to open hive
+ if(!this->p_hive->Open(hive_file,!this->is_hive_writable)) {
+ QMessageBox::critical(this,
+ tr("Error opening hive file"),
+ tr("Unable to open file '%1'").arg(hive_file));
+ return;
+ }
+
+ // Create tree model & proxy
+ this->p_reg_node_tree_model=new RegistryNodeTreeModel(this->p_hive);
+ this->p_reg_node_tree_model_proxy=new RegistryNodeTreeModelProxy(this);
+ //this->p_reg_node_tree_model_proxy->setDynamicSortFilter(true);
+ this->p_reg_node_tree_model_proxy->
+ setSourceModel(this->p_reg_node_tree_model);
+ this->p_node_tree->setModel(this->p_reg_node_tree_model_proxy,
+ this->is_hive_writable);
+
+ this->is_hive_open=true;
+
+ // Enable data interpreter
+ this->p_hex_edit_widget->setEnabled(true);
+
+ // Update window title
+ this->UpdateWindowTitle(hive_file);
+
+ // Update menu states
+ this->UpdateMenuStates();
+
+ // Add file to recent list and update recently opened menu
+ this->p_settings->AddRecentFile(hive_file);
+ this->UpdateRecentlyOpenedMenu();
+}
+
+/*
+ * UpdateWindowTitle
+ */
+void MainWindow::UpdateWindowTitle(QString filename) {
+ if(filename=="") {
+ this->setWindowTitle(QString("%1 v%2").arg(APP_TITLE,APP_VERSION));
+ } else {
+ this->setWindowTitle(QString("%1 v%2 - %3").arg(APP_TITLE,
+ APP_VERSION,
+ filename.toLocal8Bit()
+ .constData()));
+ if(!this->is_hive_writable) {
+ this->setWindowTitle(this->windowTitle().append(QString(" (%1)")
+ .arg(tr("read-only"))));
+ }
+ }
+}
+
+/*
+ * UpdateMenuStates
+ */
+void MainWindow::UpdateMenuStates() {
+ if(this->is_hive_open) {
+ this->ui->ActionCloseHive->setEnabled(true);
+ this->ui->ActionFind->setEnabled(true);
+ this->ui->ActionEnableWriteSupport->setEnabled(true);
+ this->ui->ActionGenerateReport->setEnabled(true);
+ this->ui->ActionReloadReportTemplates->setEnabled(true);
+ this->UpdateEnableWriteSupportMenu();
+ } else {
+ this->ui->ActionSave->setEnabled(false);
+ this->ui->ActionCloseHive->setEnabled(false);
+ this->ui->ActionEnableWriteSupport->setEnabled(false);
+ this->ui->ActionFind->setEnabled(false);
+ this->ui->ActionEnableWriteSupport->setEnabled(false);
+ this->ui->ActionGenerateReport->setEnabled(false);
+ this->ui->ActionReloadReportTemplates->setEnabled(false);
+ }
+}
+
+/*
+ * ClearRecentlyOpenedMenu
+ */
+void MainWindow::ClearRecentlyOpenedMenu() {
+ QAction *p_action;
+
+ // Remove existing menu entries
+ QList<QAction*> menu_entries=this->p_recently_opened_menu->actions();
+ QListIterator<QAction*> it_me(menu_entries);
+ while(it_me.hasNext()) {
+ p_action=it_me.next();
+ this->p_recently_opened_menu->removeAction(p_action);
+ delete p_action;
+ }
+}
+
+/*
+ * UpdateRecentlyOpenedMenu
+ */
+void MainWindow::UpdateRecentlyOpenedMenu() {
+ QStringList recent_files=this->p_settings->GetRecentFiles();
+ QAction *p_action;
+
+ // Remove existing menu entries
+ this->ClearRecentlyOpenedMenu();
+
+ // If there are no recent files, disable submenu and return
+ if(recent_files.isEmpty()) {
+ this->ui->ActionRecentlyOpened->setEnabled(false);
+ return;
+ } else {
+ this->ui->ActionRecentlyOpened->setEnabled(true);
+ }
+
+ // Add recently opened files to menu
+ QListIterator<QString> it_rf(recent_files);
+ while(it_rf.hasNext()) {
+ // Create menu entry
+ p_action=new QAction(it_rf.next(),this->p_recently_opened_menu);
+ // Connect it to us
+ this->connect(p_action,
+ SIGNAL(triggered(bool)),
+ this,
+ SLOT(SlotRecentlyOpenedFileClicked(bool)));
+ // Add it to submenu
+ this->p_recently_opened_menu->addAction(p_action);
+ }
+}
+
+/*
+ * UpdateEnableWriteSupportMenu
+ */
+void MainWindow::UpdateEnableWriteSupportMenu() {
+ if(!this->is_hive_writable) {
+ this->ui->ActionEnableWriteSupport->setText(tr("Enable &write support"));
+ this->p_node_tree->SetWritable(false);
+ this->p_key_table->SetWritable(false);
+ } else {
+ this->ui->ActionEnableWriteSupport->setEnabled(false);
+ this->p_node_tree->SetWritable(true);
+ this->p_key_table->SetWritable(true);
+ }
+}
+
+/*
+ * SaveHiveChanges
+ */
+bool MainWindow::SaveHiveChanges(bool force) {
+ if(!this->is_hive_open) return true;
+ if(!this->is_hive_writable) return true;
+ if(!this->p_hive->HasChangesToCommit()) return true;
+
+ if(!force) {
+ // There are unsaved changes, ask user if we should commit them
+ switch(QMessageBox::information(this,
+ tr("Hive contains unsaved data"),
+ tr("Do you want to save them now?"),
+ QMessageBox::Yes,
+ QMessageBox::No,
+ QMessageBox::Cancel))
+ {
+ case QMessageBox::Yes: {
+ if(!this->p_hive->CommitChanges()) {
+ QMessageBox::critical(this,
+ tr("Saving changes"),
+ tr("Unable to save changes: %1")
+ .arg(this->p_hive->GetErrorMsg()));
+ return false;
+ }
+ break;
+ }
+ case QMessageBox::No: {
+ break;
+ }
+ default: {
+ return false;
+ }
+ }
+ } else {
+ if(!this->p_hive->CommitChanges()) {
+ QMessageBox::critical(this,
+ tr("Saving changes"),
+ tr("Unable to save changes: %1")
+ .arg(this->p_hive->GetErrorMsg()));
+ return false;
+ }
+ }
+ return true;
+}
diff --git a/tags/fred-0.2.0/mainwindow.h b/tags/fred-0.2.0/mainwindow.h
new file mode 100644
index 0000000..bf7b028
--- /dev/null
+++ b/tags/fred-0.2.0/mainwindow.h
@@ -0,0 +1,127 @@
+/*******************************************************************************
+* fred Copyright (c) 2011-2020 by Gillen Daniel <gillen.dan@pinguin.lu> *
+* *
+* Forensic Registry EDitor (fred) is a cross-platform M$ registry hive editor *
+* with special feautures useful during forensic analysis. *
+* *
+* This program is free software: you can redistribute it and/or modify it *
+* under the terms of the GNU General Public License as published by the Free *
+* Software Foundation, either version 3 of the License, or (at your option) *
+* any later version. *
+* *
+* This program is distributed in the hope that it will be useful, but WITHOUT *
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or *
+* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for *
+* more details. *
+* *
+* You should have received a copy of the GNU General Public License along with *
+* this program. If not, see <http://www.gnu.org/licenses/>. *
+*******************************************************************************/
+
+#ifndef MAINWINDOW_H
+#define MAINWINDOW_H
+
+#include <QMainWindow>
+#include <QWidget>
+#include <QLabel>
+#include <QTabWidget>
+#include <QVBoxLayout>
+#include <QSplitter>
+#include <QString>
+#include <QByteArray>
+
+//#include <hivex.h>
+
+#include "argparser.h"
+#include "registryhive.h"
+#include "registrynodetree.h"
+#include "registrynodetreemodel.h"
+#include "registrynodetreemodelproxy.h"
+#include "registrykeytable.h"
+#include "registrykeytablemodel.h"
+#include "hexeditwidget.h"
+#include "reports.h"
+#include "threadsearch.h"
+#include "searchresultwidget.h"
+#include "tabwidget.h"
+#include "settings.h"
+
+namespace Ui {
+ class MainWindow;
+}
+
+class MainWindow : public QMainWindow {
+ Q_OBJECT
+
+ public:
+ explicit MainWindow(ArgParser *p_arg_parser);
+ ~MainWindow();
+
+ protected:
+ void closeEvent(QCloseEvent *p_event);
+
+ private slots:
+ void on_ActionOpenHive_triggered();
+ void on_ActionCloseHive_triggered();
+ void on_ActionQuit_triggered();
+ void on_ActionEnableWriteSupport_triggered();
+ void on_ActionPreferences_triggered();
+ void on_ActionGenerateReport_triggered();
+ void on_ActionReloadReportTemplates_triggered();
+ void on_ActionAboutQt_triggered();
+ void on_ActionAboutFred_triggered();
+ void on_ActionFind_triggered();
+ void SlotNodeTreeClicked(QModelIndex index);
+ void SlotKeyTableClicked(QModelIndex index);
+ void SlotKeyTableDoubleClicked(QModelIndex index);
+ void SlotSearchFinished();
+ void SlotSearchResultWidgetDoubleClicked(QModelIndex index);
+ void SlotTabCloseButtonClicked(int index);
+ void SlotRecentlyOpenedFileClicked(bool checked);
+ void SlotAddNode(QModelIndex index);
+ void SlotDeleteNode(QModelIndex index);
+ void SlotAddKey();
+ void SlotEditKey(QModelIndex index);
+ void SlotDeleteKey(QModelIndex index);
+
+ void on_ActionSave_triggered();
+
+ private:
+ Ui::MainWindow *ui;
+ ArgParser *p_args;
+ RegistryHive *p_hive;
+ bool is_hive_open;
+ bool is_hive_writable;
+ QByteArray selected_key_value;
+ QList<SearchResultWidget*> search_result_widgets;
+ Settings *p_settings;
+
+ // Models
+ RegistryNodeTreeModel *p_reg_node_tree_model;
+ RegistryNodeTreeModelProxy *p_reg_node_tree_model_proxy;
+ RegistryKeyTableModel *p_reg_key_table_model;
+
+ // Widgets etc...
+ RegistryNodeTree *p_node_tree;
+ RegistryKeyTable *p_key_table;
+ TabWidget *p_tab_widget;
+ HexEditWidget *p_hex_edit_widget;
+ QSplitter *p_horizontal_splitter;
+ QSplitter *p_vertical_splitter;
+ Reports *p_reports;
+ QMenu *p_recently_opened_menu;
+
+ // Threads
+ ThreadSearch *p_search_thread;
+
+ // Functions
+ void OpenHive(QString hive_file);
+ void UpdateWindowTitle(QString filename="");
+ void UpdateMenuStates();
+ void ClearRecentlyOpenedMenu();
+ void UpdateRecentlyOpenedMenu();
+ void UpdateEnableWriteSupportMenu();
+ bool SaveHiveChanges(bool force=false);
+};
+
+#endif // MAINWINDOW_H
diff --git a/tags/fred-0.2.0/mainwindow.ui b/tags/fred-0.2.0/mainwindow.ui
new file mode 100644
index 0000000..6056ea3
--- /dev/null
+++ b/tags/fred-0.2.0/mainwindow.ui
@@ -0,0 +1,187 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>MainWindow</class>
+ <widget class="QMainWindow" name="MainWindow">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>508</width>
+ <height>317</height>
+ </rect>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>0</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="baseSize">
+ <size>
+ <width>0</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="windowTitle">
+ <string>MainWindow</string>
+ </property>
+ <property name="windowIcon">
+ <iconset resource="fred.qrc">
+ <normaloff>:/icons/resources/fred.png</normaloff>:/icons/resources/fred.png</iconset>
+ </property>
+ <widget class="QWidget" name="MainWidget"/>
+ <widget class="QMenuBar" name="menuBar">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>508</width>
+ <height>29</height>
+ </rect>
+ </property>
+ <widget class="QMenu" name="MenuFile">
+ <property name="title">
+ <string>&amp;File</string>
+ </property>
+ <addaction name="ActionOpenHive"/>
+ <addaction name="ActionRecentlyOpened"/>
+ <addaction name="ActionSave"/>
+ <addaction name="ActionCloseHive"/>
+ <addaction name="separator"/>
+ <addaction name="ActionQuit"/>
+ </widget>
+ <widget class="QMenu" name="MenuHelp">
+ <property name="title">
+ <string>&amp;Help</string>
+ </property>
+ <addaction name="ActionAboutQt"/>
+ <addaction name="ActionAboutFred"/>
+ </widget>
+ <widget class="QMenu" name="MenuReports">
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="title">
+ <string>&amp;Reports</string>
+ </property>
+ <addaction name="ActionGenerateReport"/>
+ <addaction name="ActionReloadReportTemplates"/>
+ </widget>
+ <widget class="QMenu" name="MenuEdit">
+ <property name="title">
+ <string>&amp;Edit</string>
+ </property>
+ <addaction name="ActionFind"/>
+ <addaction name="separator"/>
+ <addaction name="ActionEnableWriteSupport"/>
+ <addaction name="ActionPreferences"/>
+ </widget>
+ <addaction name="MenuFile"/>
+ <addaction name="MenuEdit"/>
+ <addaction name="MenuReports"/>
+ <addaction name="MenuHelp"/>
+ </widget>
+ <widget class="QStatusBar" name="StatusBar"/>
+ <action name="ActionOpenHive">
+ <property name="text">
+ <string>&amp;Open hive</string>
+ </property>
+ <property name="shortcut">
+ <string>Ctrl+O</string>
+ </property>
+ </action>
+ <action name="ActionCloseHive">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>Close hive</string>
+ </property>
+ </action>
+ <action name="ActionQuit">
+ <property name="text">
+ <string>&amp;Quit</string>
+ </property>
+ <property name="shortcut">
+ <string>Ctrl+Q</string>
+ </property>
+ </action>
+ <action name="ActionAboutQt">
+ <property name="text">
+ <string>About Qt</string>
+ </property>
+ </action>
+ <action name="ActionAboutFred">
+ <property name="text">
+ <string>About fred</string>
+ </property>
+ </action>
+ <action name="ActionFind">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>&amp;Find</string>
+ </property>
+ <property name="shortcut">
+ <string>Ctrl+F</string>
+ </property>
+ </action>
+ <action name="ActionPreferences">
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="text">
+ <string>&amp;Preferences</string>
+ </property>
+ </action>
+ <action name="ActionGenerateReport">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>Generate report</string>
+ </property>
+ </action>
+ <action name="ActionReloadReportTemplates">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>Reload report templates</string>
+ </property>
+ </action>
+ <action name="ActionRecentlyOpened">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>Recently opened</string>
+ </property>
+ </action>
+ <action name="ActionEnableWriteSupport">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>Enable &amp;write support</string>
+ </property>
+ </action>
+ <action name="ActionSave">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>&amp;Save</string>
+ </property>
+ <property name="shortcut">
+ <string>Ctrl+S</string>
+ </property>
+ </action>
+ </widget>
+ <layoutdefault spacing="6" margin="11"/>
+ <resources>
+ <include location="fred.qrc"/>
+ </resources>
+ <connections/>
+</ui>
diff --git a/tags/fred-0.2.0/manual/ECMAScript_additions_reference.odt b/tags/fred-0.2.0/manual/ECMAScript_additions_reference.odt
new file mode 100644
index 0000000..4c5fc9e
Binary files /dev/null and b/tags/fred-0.2.0/manual/ECMAScript_additions_reference.odt differ
diff --git a/tags/fred-0.2.0/old_src/datareporter.cpp b/tags/fred-0.2.0/old_src/datareporter.cpp
new file mode 100644
index 0000000..ad9fa3b
--- /dev/null
+++ b/tags/fred-0.2.0/old_src/datareporter.cpp
@@ -0,0 +1,201 @@
+/*******************************************************************************
+* fred Copyright (c) 2011-2020 by Gillen Daniel <gillen.dan@pinguin.lu> *
+* *
+* Forensic Registry EDitor (fred) is a cross-platform M$ registry hive editor *
+* with special feautures useful during forensic analysis. *
+* *
+* This program is free software: you can redistribute it and/or modify it *
+* under the terms of the GNU General Public License as published by the Free *
+* Software Foundation, either version 3 of the License, or (at your option) *
+* any later version. *
+* *
+* This program is distributed in the hope that it will be useful, but WITHOUT *
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or *
+* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for *
+* more details. *
+* *
+* You should have received a copy of the GNU General Public License along with *
+* this program. If not, see <http://www.gnu.org/licenses/>. *
+*******************************************************************************/
+
+#include "datareporter.h"
+
+#include <QDir>
+#include <QTextStream>
+#include <QtScript/QScriptEngine>
+#include <QMessageBox>
+
+DataReporter::DataReporter() {
+ this->report_templates.clear();
+ //this->p_report_engine=new DataReporterEngine();
+}
+
+DataReporter::~DataReporter() {
+ //delete this->p_report_engine;
+ qDeleteAll(this->report_templates);
+}
+
+void DataReporter::LoadReportTemplates(QString dir) {
+ QString report_template="";
+ int i=0;
+ int ii=0;
+ bool found=false;
+ QString report_category="";
+ QString report_name="";
+ ReportTemplate *p_report;
+
+ // Get all template files in report_templates directory
+ QDir report_dir(dir);
+ QStringList found_report_templates=report_dir.
+ entryList(QStringList()<<"*.qs");
+
+ for(i=0;i<found_report_templates.count();i++) {
+ // Build complete path to template file
+ report_template=report_dir.path();
+ report_template.append(QDir::separator());
+ report_template.append(found_report_templates.value(i));
+
+ // Extract report category and name from file name (<category>_<name>.qs)
+ report_category=found_report_templates.value(i).left(
+ found_report_templates.value(i).indexOf("_"));
+ report_name=found_report_templates.value(i).mid(
+ found_report_templates.value(i).indexOf("_")+1);
+ report_name=report_name.left(report_name.lastIndexOf("."));
+
+ // Check if a report with the same category/name was already added
+ found=false;
+ for(ii=0;ii<this->report_templates.count();ii++) {
+ if(this->report_templates.at(ii)->Category()==report_category &&
+ this->report_templates.at(ii)->Name()==report_name)
+ {
+ found=true;
+ break;
+ }
+ }
+
+ if(!found) {
+ // Add report to list
+ p_report=new ReportTemplate(report_template,
+ report_category,
+ report_name,
+ "","","");
+ this->report_templates.append(p_report);
+ } else {
+ // Update report entry
+ p_report=this->report_templates.at(ii);
+ p_report->SetFile(report_template);
+ }
+ }
+}
+
+QStringList DataReporter::GetAvailableReportCategories() {
+ QStringList ret;
+ QString cat;
+ int i=0;
+
+ ret.clear();
+ for(i=0;i<this->report_templates.count();i++) {
+ cat=this->report_templates.value(i)->Category();
+ if(!ret.contains(cat)) ret.append(cat);
+ }
+ ret.sort();
+
+ return ret;
+}
+
+QStringList DataReporter::GetAvailableReports(QString category) {
+ QStringList ret;
+ QString cat;
+ int i=0;
+
+ ret.clear();
+ for(i=0;i<this->report_templates.count();i++) {
+ cat=this->report_templates.value(i)->Category();
+ if(cat==category) ret.append(this->report_templates.value(i)->Name());
+ }
+ ret.sort();
+
+ return ret;
+}
+
+QString DataReporter::GenerateReport(RegistryHive *p_hive,
+ QString report_category,
+ QString report_name)
+{
+ int i=0;
+ ReportTemplate *p_report;
+
+ // Search report template
+ for(i=0;i<this->report_templates.count();i++) {
+ p_report=this->report_templates.value(i);
+ if(p_report->Category()!=report_category || p_report->Name()!=report_name) {
+ continue;
+ }
+ // Report template was found, now generate report and return result
+ return this->GenerateReport(p_hive,p_report->File());
+ }
+
+ // Report template couldn't be found
+ QMessageBox::critical(0,
+ "Report engine error",
+ QString("Unable to find report with name '%1' in category '%2'!")
+ .arg(report_name)
+ .arg(report_category));
+ return QString();
+}
+
+QString DataReporter::GenerateReport(RegistryHive *p_hive,
+ QString report_template,
+ bool console_mode)
+{
+ QString report_code;
+
+ // Init data reporter engine
+ DataReporterEngine engine(p_hive);
+ QScriptValue hive_value=engine.newQObject(p_hive);
+ engine.globalObject().setProperty("RegistryHive",hive_value);
+
+ // Open report template
+ QFile template_file(report_template);
+ if(!template_file.open(QIODevice::ReadOnly | QIODevice::Text)) {
+ if(!console_mode) {
+ QMessageBox::critical(0,
+ "Report engine error",
+ QString("Couldn't open report template file '%1'!")
+ .arg(report_template));
+ } else {
+ printf("ERROR: Couldn't open report template file '%s'!\n",
+ report_template.toAscii().constData());
+ }
+ return QString();
+ }
+
+ // Read template file
+ QTextStream in(&template_file);
+ while(!in.atEnd()) report_code.append(in.readLine()).append("\n");
+
+ // Close report template file
+ template_file.close();
+
+ // Execute report template script
+ QScriptValue report_result=engine.evaluate(report_code,report_template);
+ if (report_result.isError() || engine.hasUncaughtException()) {
+ if(!console_mode) {
+ QMessageBox::critical(0,
+ "Report engine error",
+ QString::fromLatin1("File: %0\n Line: %1\nError: %2")
+ .arg(report_template)
+ .arg(report_result.property("lineNumber")
+ .toInt32())
+ .arg(report_result.toString()));
+ } else {
+ printf("ERROR: %s:%u: %s\n",
+ report_template.toAscii().constData(),
+ report_result.property("lineNumber").toInt32(),
+ report_result.toString().toAscii().constData());
+ }
+ return QString();
+ }
+
+ return engine.report_content;
+}
diff --git a/tags/fred-0.2.0/old_src/datareporter.h b/tags/fred-0.2.0/old_src/datareporter.h
new file mode 100644
index 0000000..48096f8
--- /dev/null
+++ b/tags/fred-0.2.0/old_src/datareporter.h
@@ -0,0 +1,51 @@
+/*******************************************************************************
+* fred Copyright (c) 2011-2020 by Gillen Daniel <gillen.dan@pinguin.lu> *
+* *
+* Forensic Registry EDitor (fred) is a cross-platform M$ registry hive editor *
+* with special feautures useful during forensic analysis. *
+* *
+* This program is free software: you can redistribute it and/or modify it *
+* under the terms of the GNU General Public License as published by the Free *
+* Software Foundation, either version 3 of the License, or (at your option) *
+* any later version. *
+* *
+* This program is distributed in the hope that it will be useful, but WITHOUT *
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or *
+* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for *
+* more details. *
+* *
+* You should have received a copy of the GNU General Public License along with *
+* this program. If not, see <http://www.gnu.org/licenses/>. *
+*******************************************************************************/
+
+#ifndef DATAREPORTER_H
+#define DATAREPORTER_H
+
+#include <QList>
+
+#include "reporttemplate.h"
+#include "datareporterengine.h"
+#include "registryhive.h"
+
+class DataReporter {
+ public:
+ DataReporter();
+ ~DataReporter();
+
+ void LoadReportTemplates(QString dir);
+ QStringList GetAvailableReportCategories();
+ QStringList GetAvailableReports(QString category);
+
+ QString GenerateReport(RegistryHive *p_hive,
+ QString report_category,
+ QString report_name);
+ QString GenerateReport(RegistryHive *p_hive,
+ QString report_template,
+ bool console_mode=false);
+
+ private:
+ QList<ReportTemplate*> report_templates;
+ //DataReporterEngine *p_report_engine;
+};
+
+#endif // DATAREPORTER_H
diff --git a/tags/fred-0.2.0/old_src/datareporterengine.cpp b/tags/fred-0.2.0/old_src/datareporterengine.cpp
new file mode 100644
index 0000000..90c627a
--- /dev/null
+++ b/tags/fred-0.2.0/old_src/datareporterengine.cpp
@@ -0,0 +1,378 @@
+/*******************************************************************************
+* fred Copyright (c) 2011-2020 by Gillen Daniel <gillen.dan@pinguin.lu> *
+* *
+* Forensic Registry EDitor (fred) is a cross-platform M$ registry hive editor *
+* with special feautures useful during forensic analysis. *
+* *
+* This program is free software: you can redistribute it and/or modify it *
+* under the terms of the GNU General Public License as published by the Free *
+* Software Foundation, either version 3 of the License, or (at your option) *
+* any later version. *
+* *
+* This program is distributed in the hope that it will be useful, but WITHOUT *
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or *
+* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for *
+* more details. *
+* *
+* You should have received a copy of the GNU General Public License along with *
+* this program. If not, see <http://www.gnu.org/licenses/>. *
+*******************************************************************************/
+
+#include "datareporterengine.h"
+
+#include <QString>
+#include <QMap>
+#include <QMapIterator>
+#include <QStringList>
+#include <QDateTime>
+
+#include <stdio.h>
+
+DataReporterEngine::DataReporterEngine(RegistryHive *p_hive) : QScriptEngine() {
+ // Init vars
+ this->p_registry_hive=p_hive;
+ this->report_content="";
+
+ // Add our constants
+ this->globalObject().setProperty("ENGINE_API_VERSION",
+ this->api_version,
+ QScriptValue::ReadOnly|
+ QScriptValue::Undeletable);
+ this->globalObject().setProperty("HIVE_FILE",
+ this->p_registry_hive->Filename(),
+ QScriptValue::ReadOnly|
+ QScriptValue::Undeletable);
+
+ // Add our types to engine
+ qScriptRegisterMetaType<s_RegistryKeyValue>(this,
+ this->RegistryKeyValueToScript,
+ this->RegistryKeyValueFromScript);
+ this->p_type_byte_array=new ByteArray(this);
+ this->globalObject().setProperty("ByteArray",
+ this->p_type_byte_array->constructor());
+
+ // Add our functions
+ // print
+ QScriptValue func_print=this->newFunction(this->Print);
+ this->globalObject().setProperty("print",func_print);
+ // println
+ QScriptValue func_println=this->newFunction(this->PrintLn);
+ this->globalObject().setProperty("println",func_println);
+ // GetRegistryNodes
+ QScriptValue func_get_nodes=this->newFunction(this->GetRegistryNodes,1);
+ func_get_nodes.setData(this->newQObject(this->p_registry_hive));
+ this->globalObject().setProperty("GetRegistryNodes",func_get_nodes);
+ // GetRegistryKeys
+ QScriptValue func_get_keys=this->newFunction(this->GetRegistryKeys,1);
+ func_get_keys.setData(this->newQObject(this->p_registry_hive));
+ this->globalObject().setProperty("GetRegistryKeys",func_get_keys);
+ // GetRegistryKeyValue
+ QScriptValue func_get_key_value=this->newFunction(this->GetRegistryKeyValue,
+ 2);
+ func_get_key_value.setData(this->newQObject(this->p_registry_hive));
+ this->globalObject().setProperty("GetRegistryKeyValue",func_get_key_value);
+ // GetRegistryNodeModTime
+ QScriptValue func_get_node_modt=
+ this->newFunction(this->GetRegistryNodeModTime,1);
+ func_get_node_modt.setData(this->newQObject(this->p_registry_hive));
+ this->globalObject().setProperty("GetRegistryNodeModTime",func_get_node_modt);
+ // RegistryKeyValueToString
+ QScriptValue func_value_to_string=
+ this->newFunction(this->RegistryKeyValueToString,2);
+ this->globalObject().setProperty("RegistryKeyValueToString",
+ func_value_to_string);
+ // RegistryKeyValueToVariant
+ QScriptValue func_value_to_variant=
+ this->newFunction(this->RegistryKeyValueToVariant);
+ this->globalObject().setProperty("RegistryKeyValueToVariant",
+ func_value_to_variant);
+ // RegistryKeyTypeToString
+ QScriptValue func_type_to_string=
+ this->newFunction(this->RegistryKeyTypeToString,1);
+ this->globalObject().setProperty("RegistryKeyTypeToString",
+ func_type_to_string);
+}
+
+DataReporterEngine::~DataReporterEngine() {
+ delete this->p_type_byte_array;
+}
+
+QScriptValue DataReporterEngine::Print(QScriptContext *context,
+ QScriptEngine *engine)
+{
+ int i;
+ QString content;
+
+ // Append all arguments to content
+ for(i=0;i<context->argumentCount();++i) {
+ //if(i>0) content.append(" ");
+ content.append(context->argument(i).toString());
+ }
+
+ //QScriptValue calleeData=context->callee().data();
+ //DataReporterEngine *engine=
+ // qobject_cast<DataReporterEngine*>(calleeData.toQObject());
+ qobject_cast<DataReporterEngine*>(engine)->report_content.append(content);
+
+ return engine->undefinedValue();
+}
+
+QScriptValue DataReporterEngine::PrintLn(QScriptContext *context,
+ QScriptEngine *engine)
+{
+ int i;
+ QString content;
+
+ // Append all arguments to content
+ for(i=0;i<context->argumentCount();++i) {
+ //if(i>0) content.append(" ");
+ content.append(context->argument(i).toString());
+ }
+
+ qobject_cast<DataReporterEngine*>(engine)->
+ report_content.append(content).append("\n");
+
+ return engine->undefinedValue();
+}
+
+/*
+ * GetRegistryNodes
+ */
+QScriptValue DataReporterEngine::GetRegistryNodes(QScriptContext *context,
+ QScriptEngine *engine)
+{
+ QScriptValue calleeData;
+ RegistryHive *p_hive;
+ QMap<QString,int> nodes;
+ QScriptValue ret_nodes;
+ int ii=0;
+
+ // This function needs one argument, parent node path
+ if(context->argumentCount()!=1) return engine->undefinedValue();
+
+ // Get calle data (Pointer to RegistryHive class)
+ calleeData=context->callee().data();
+ p_hive=qobject_cast<RegistryHive*>(calleeData.toQObject());
+
+ // Get nodes
+ nodes=p_hive->GetNodes(context->argument(0).toString());
+ if(p_hive->Error()) {
+ // Clear error state
+ p_hive->GetErrorMsg();
+ return engine->undefinedValue();
+ }
+
+ // Build script array
+ ret_nodes=engine->newArray(nodes.count());
+ QMapIterator<QString,int> i(nodes);
+ while(i.hasNext()) {
+ i.next();
+ ret_nodes.setProperty(ii++,QScriptValue(i.key()));
+ }
+
+ return ret_nodes;
+}
+
+/*
+ * GetRegistryKeys
+ */
+QScriptValue DataReporterEngine::GetRegistryKeys(QScriptContext *context,
+ QScriptEngine *engine)
+{
+ QScriptValue calleeData;
+ RegistryHive *p_hive;
+ QMap<QString,int> keys;
+ QScriptValue ret_keys;
+ int ii=0;
+
+ // This function needs one argument, parent node path
+ if(context->argumentCount()!=1) return engine->undefinedValue();
+
+ // Get calle data (Pointer to RegistryHive class)
+ calleeData=context->callee().data();
+ p_hive=qobject_cast<RegistryHive*>(calleeData.toQObject());
+
+ // Get keys
+ keys=p_hive->GetKeys(context->argument(0).toString());
+ if(p_hive->Error()) {
+ // Clear error state
+ p_hive->GetErrorMsg();
+ return engine->undefinedValue();
+ }
+
+ //qDebug(QString("P: %1 A: %2").arg(context->argument(0).toString()).arg(keys.count()).toAscii().constData());
+
+ // Build script array
+ ret_keys=engine->newArray(keys.count());
+ QMapIterator<QString,int> i(keys);
+ while(i.hasNext()) {
+ i.next();
+ ret_keys.setProperty(ii++,QScriptValue(i.key()));
+ }
+
+ return ret_keys;
+}
+
+/*
+ * RegistryKeyValueToScript
+ */
+QScriptValue DataReporterEngine::RegistryKeyValueToScript(QScriptEngine *engine,
+ const
+ s_RegistryKeyValue
+ &s)
+{
+ QScriptValue obj=engine->newObject();
+ obj.setProperty("type",s.type);
+ obj.setProperty("length",s.length);
+ ByteArray *p_byte_array=new ByteArray(engine);
+ obj.setProperty("value",p_byte_array->newInstance(s.value));
+ return obj;
+}
+
+/*
+ * RegistryKeyValueFromScriptValue
+ */
+void DataReporterEngine::RegistryKeyValueFromScript(const QScriptValue &obj,
+ s_RegistryKeyValue &s)
+{
+ s.type=obj.property("type").toInt32();
+ s.length=obj.property("length").toInt32();
+ // TODO: Don't know if this works, but it probably does ;)
+ s.value=qvariant_cast<QByteArray>(obj.property("value").data().toVariant());
+}
+
+QScriptValue DataReporterEngine::GetRegistryKeyValue(QScriptContext *context,
+ QScriptEngine *engine)
+{
+ QScriptValue calleeData;
+ RegistryHive *p_hive;
+ QByteArray key_value;
+ int key_type=0;
+ size_t key_length=0;
+ s_RegistryKeyValue script_key_value;
+
+ // This function needs two arguments, key path and key name
+ if(context->argumentCount()!=2) return engine->undefinedValue();
+
+ // Get calle data (Pointer to RegistryHive class)
+ calleeData=context->callee().data();
+ p_hive=qobject_cast<RegistryHive*>(calleeData.toQObject());
+
+ // Get key value
+ key_value=p_hive->GetKeyValue(context->argument(0).toString(),
+ context->argument(1).toString(),
+ &key_type,
+ &key_length);
+ if(p_hive->Error()) {
+ // Get error message to clear error state
+ p_hive->GetErrorMsg();
+// printf("\nError: %s\n",p_hive->GetErrorMsg().toAscii().constData());
+ return engine->undefinedValue();
+ }
+
+ // Save key value to s_RegistryKeyValue struct
+ script_key_value.type=key_type;
+ script_key_value.length=key_length;
+ script_key_value.value=key_value;
+
+ return DataReporterEngine::RegistryKeyValueToScript(engine,script_key_value);
+}
+
+QScriptValue DataReporterEngine::RegistryKeyValueToString(
+ QScriptContext *context,
+ QScriptEngine *engine)
+{
+ QByteArray key_value;
+ QString ret="";
+
+ // This function needs two arguments, key value and value type
+ if(context->argumentCount()!=2) return engine->undefinedValue();
+
+ // Cast ByteArray argument to QByteArray and convert
+ key_value=qvariant_cast<QByteArray>(context->argument(0).data().toVariant());
+ ret=RegistryHive::KeyValueToString(key_value,
+ context->argument(1).toInt32());
+
+ return engine->newVariant(ret);
+}
+
+QScriptValue DataReporterEngine::RegistryKeyValueToVariant(
+ QScriptContext *context,
+ QScriptEngine *engine)
+{
+ int offset=0;
+ int length=-1;
+ bool little_endian=true;
+ QByteArray key_value;
+ QString format="";
+ QString ret="";
+
+ // This function needs at least two arguments, key value and variant type,
+ // and may have three optional arguments, offset, length and little_endian
+ if(context->argumentCount()<2 || context->argumentCount()>5) {
+ return engine->undefinedValue();
+ }
+ if(context->argumentCount()==3) {
+ offset=context->argument(2).toInt32();
+ }
+ if(context->argumentCount()==4) {
+ offset=context->argument(2).toInt32();
+ length=context->argument(3).toInt32();
+ }
+ if(context->argumentCount()==5) {
+ offset=context->argument(2).toInt32();
+ length=context->argument(3).toInt32();
+ little_endian=(context->argument(4).toInt32()==1);
+ }
+
+ // Cast ByteArray argument to QByteArray
+ key_value=qvariant_cast<QByteArray>(context->argument(0).data().toVariant());
+ format=context->argument(1).toString();
+
+ ret=RegistryHive::KeyValueToString(key_value,format,offset,length,little_endian);
+
+ return engine->newVariant(ret);
+}
+
+QScriptValue DataReporterEngine::RegistryKeyTypeToString(
+ QScriptContext *context,
+ QScriptEngine *engine)
+{
+ QString ret="";
+
+ // This function needs one argument, key type
+ if(context->argumentCount()!=1) return engine->undefinedValue();
+
+ ret=RegistryHive::KeyTypeToString(context->argument(0).toInt32());
+
+ return engine->newVariant(ret);
+}
+
+QScriptValue DataReporterEngine::GetRegistryNodeModTime(
+ QScriptContext *context,
+ QScriptEngine *engine)
+{
+ QScriptValue calleeData;
+ RegistryHive *p_hive;
+ int64_t mod_time=0;
+
+ // This function needs one argument, node path
+ if(context->argumentCount()!=1) return engine->undefinedValue();
+
+ // Get calle data (Pointer to RegistryHive class)
+ calleeData=context->callee().data();
+ p_hive=qobject_cast<RegistryHive*>(calleeData.toQObject());
+
+ mod_time=p_hive->GetNodeModTime(context->argument(0).toString());
+ if(p_hive->Error()) {
+ // Get error message to clear error state
+ p_hive->GetErrorMsg();
+ return engine->undefinedValue();
+ }
+
+ QDateTime date_time;
+ date_time.setTimeSpec(Qt::UTC);
+ date_time.setTime_t(RegistryHive::FiletimeToUnixtime(mod_time));
+
+ return engine->newVariant(date_time.toString("yyyy/MM/dd hh:mm:ss"));
+}
diff --git a/tags/fred-0.2.0/old_src/datareporterengine.h b/tags/fred-0.2.0/old_src/datareporterengine.h
new file mode 100644
index 0000000..a39b56e
--- /dev/null
+++ b/tags/fred-0.2.0/old_src/datareporterengine.h
@@ -0,0 +1,79 @@
+/*******************************************************************************
+* fred Copyright (c) 2011-2020 by Gillen Daniel <gillen.dan@pinguin.lu> *
+* *
+* Forensic Registry EDitor (fred) is a cross-platform M$ registry hive editor *
+* with special feautures useful during forensic analysis. *
+* *
+* This program is free software: you can redistribute it and/or modify it *
+* under the terms of the GNU General Public License as published by the Free *
+* Software Foundation, either version 3 of the License, or (at your option) *
+* any later version. *
+* *
+* This program is distributed in the hope that it will be useful, but WITHOUT *
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or *
+* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for *
+* more details. *
+* *
+* You should have received a copy of the GNU General Public License along with *
+* this program. If not, see <http://www.gnu.org/licenses/>. *
+*******************************************************************************/
+
+#ifndef DATAREPORTERENGINE_H
+#define DATAREPORTERENGINE_H
+
+#include <QObject>
+#include <QString>
+#include <QtScript/QScriptEngine>
+#include <QtScript/QScriptValue>
+#include <QtScript/QScriptContext>
+
+#include "registryhive.h"
+#include "qtscript_types/bytearray.h"
+
+#define FRED_DATAREPORTERENGINE_API_VERSION 2
+
+class DataReporterEngine : public QScriptEngine {
+ Q_OBJECT
+
+ public:
+ struct s_RegistryKeyValue {
+ int type;
+ int length;
+ QByteArray value;
+ };
+
+ RegistryHive *p_registry_hive;
+ QString report_content;
+
+ DataReporterEngine(RegistryHive *p_hive);
+ ~DataReporterEngine();
+
+ private:
+ static const int api_version=2;
+ ByteArray *p_type_byte_array;
+
+ static QScriptValue Print(QScriptContext *context, QScriptEngine *engine);
+ static QScriptValue PrintLn(QScriptContext *context, QScriptEngine *engine);
+ static QScriptValue GetRegistryNodes(QScriptContext *context,
+ QScriptEngine *engine);
+ static QScriptValue GetRegistryKeys(QScriptContext *context,
+ QScriptEngine *engine);
+ static QScriptValue RegistryKeyValueToScript(QScriptEngine *engine,
+ const s_RegistryKeyValue &s);
+ static void RegistryKeyValueFromScript(const QScriptValue &obj,
+ s_RegistryKeyValue &s);
+ static QScriptValue GetRegistryKeyValue(QScriptContext *context,
+ QScriptEngine *engine);
+ static QScriptValue RegistryKeyValueToString(QScriptContext *context,
+ QScriptEngine *engine);
+ static QScriptValue RegistryKeyValueToVariant(QScriptContext *context,
+ QScriptEngine *engine);
+ static QScriptValue RegistryKeyTypeToString(QScriptContext *context,
+ QScriptEngine *engine);
+ static QScriptValue GetRegistryNodeModTime(QScriptContext *context,
+ QScriptEngine *engine);
+};
+
+Q_DECLARE_METATYPE(DataReporterEngine::s_RegistryKeyValue)
+
+#endif // DATAREPORTERENGINE_H
diff --git a/tags/fred-0.2.0/qhexedit/qhexedit.cpp b/tags/fred-0.2.0/qhexedit/qhexedit.cpp
new file mode 100644
index 0000000..737efbb
--- /dev/null
+++ b/tags/fred-0.2.0/qhexedit/qhexedit.cpp
@@ -0,0 +1,135 @@
+/*******************************************************************************
+* qhexedit Copyright (c) 2011-2020 by Gillen Daniel <gillen.dan@pinguin.lu> *
+* *
+* Simple hex editor widget for Qt. *
+* *
+* Derived from code by Simon Winfried under a compatible license: *
+* Copyright (c) 2010 by Simon Winfried *
+* *
+* This program is free software: you can redistribute it and/or modify it *
+* under the terms of the GNU General Public License as published by the Free *
+* Software Foundation, either version 3 of the License, or (at your option) *
+* any later version. *
+* *
+* This program is distributed in the hope that it will be useful, but WITHOUT *
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or *
+* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for *
+* more details. *
+* *
+* You should have received a copy of the GNU General Public License along with *
+* this program. If not, see <http://www.gnu.org/licenses/>. *
+*******************************************************************************/
+
+#include <QScrollArea>
+#include "qhexedit.h"
+
+QHexEdit::QHexEdit(QWidget *parent) : QScrollArea(parent)
+{
+ qHexEdit_p = new QHexEditPrivate(this);
+ setWidget(qHexEdit_p);
+ setWidgetResizable(true);
+
+ connect(qHexEdit_p, SIGNAL(currentAddressChanged(int)), this, SIGNAL(currentAddressChanged(int)));
+ connect(qHexEdit_p, SIGNAL(currentSizeChanged(int)), this, SIGNAL(currentSizeChanged(int)));
+ connect(qHexEdit_p, SIGNAL(dataChanged()), this, SIGNAL(dataChanged()));
+ connect(qHexEdit_p, SIGNAL(overwriteModeChanged(bool)), this, SIGNAL(overwriteModeChanged(bool)));
+}
+
+void QHexEdit::insert(int i, const QByteArray & ba)
+{
+ qHexEdit_p->insert(i, ba);
+}
+
+void QHexEdit::insert(int i, char ch)
+{
+ qHexEdit_p->insert(i, ch);
+}
+
+void QHexEdit::remove(int pos, int len)
+{
+ qHexEdit_p->remove(pos, len);
+}
+
+void QHexEdit::setAddressArea(bool addressArea)
+{
+ qHexEdit_p->setAddressArea(addressArea);
+}
+
+void QHexEdit::setAddressWidth(int addressWidth)
+{
+ qHexEdit_p->setAddressWidth(addressWidth);
+}
+
+void QHexEdit::setAsciiArea(bool asciiArea)
+{
+ qHexEdit_p->setAsciiArea(asciiArea);
+}
+
+void QHexEdit::setHighlighting(bool mode)
+{
+ qHexEdit_p->setHighlighting(mode);
+}
+
+void QHexEdit::setAddressOffset(int offset)
+{
+ qHexEdit_p->setAddressOffset(offset);
+}
+
+int QHexEdit::addressOffset()
+{
+ return addressOffset();
+}
+
+void QHexEdit::setData(const QByteArray &data)
+{
+ qHexEdit_p->setData(data);
+}
+
+QByteArray QHexEdit::data()
+{
+ return qHexEdit_p->data();
+}
+
+void QHexEdit::setAddressAreaColor(const QColor &color)
+{
+ qHexEdit_p->setAddressAreaColor(color);
+}
+
+QColor QHexEdit::addressAreaColor()
+{
+ return qHexEdit_p->addressAreaColor();
+}
+
+void QHexEdit::setHighlightingColor(const QColor &color)
+{
+ qHexEdit_p->setHighlightingColor(color);
+}
+
+QColor QHexEdit::highlightingColor()
+{
+ return qHexEdit_p->highlightingColor();
+}
+
+void QHexEdit::setOverwriteMode(bool overwriteMode)
+{
+ qHexEdit_p->setOverwriteMode(overwriteMode);
+}
+
+bool QHexEdit::overwriteMode()
+{
+ return qHexEdit_p->overwriteMode();
+}
+
+void QHexEdit::setReadOnly(bool read_only) {
+ qHexEdit_p->setReadOnly(read_only);
+}
+
+bool QHexEdit::readOnly() {
+ return qHexEdit_p->readOnly();
+}
+
+void QHexEdit::setFont(const QFont &font)
+{
+ qHexEdit_p->setFont(font);
+}
+
diff --git a/tags/fred-0.2.0/qhexedit/qhexedit.h b/tags/fred-0.2.0/qhexedit/qhexedit.h
new file mode 100644
index 0000000..6b99df5
--- /dev/null
+++ b/tags/fred-0.2.0/qhexedit/qhexedit.h
@@ -0,0 +1,178 @@
+/*******************************************************************************
+* qhexedit Copyright (c) 2011-2020 by Gillen Daniel <gillen.dan@pinguin.lu> *
+* *
+* Simple hex editor widget for Qt. *
+* *
+* Derived from code by Simon Winfried under a compatible license: *
+* Copyright (c) 2010 by Simon Winfried *
+* *
+* This program is free software: you can redistribute it and/or modify it *
+* under the terms of the GNU General Public License as published by the Free *
+* Software Foundation, either version 3 of the License, or (at your option) *
+* any later version. *
+* *
+* This program is distributed in the hope that it will be useful, but WITHOUT *
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or *
+* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for *
+* more details. *
+* *
+* You should have received a copy of the GNU General Public License along with *
+* this program. If not, see <http://www.gnu.org/licenses/>. *
+*******************************************************************************/
+
+#ifndef QHEXEDIT_H
+#define QHEXEDIT_H
+
+#include "qhexedit_p.h"
+
+/** \mainpage
+QHexEdit is a binary editor widget for Qt.
+
+\version Version 0.4.6
+\image html hexedit.png
+*/
+
+
+class QHBoxLayout;
+
+/*! QHexEdit is a hex editor widget written in C++ for the Qt (Qt4) framework.
+It is a simple editor for binary data, just like QPlainTextEdit is for text data.
+There are sip configuration files included, so it is easy to create bindings
+for PyQt and you can use this widget also in python.
+
+QHexEdit takes the data of a QByteArray (setData()) and shows it. You can use the
+mouse or the keyboard to navigate inside the widget. If you hit the keys (0..9, a..f)
+you will change the data. Changed data is highlighted and can be accessed via data().
+
+Normaly QHexEdit works in the overwrite Mode. You can set overwriteMode(false) and
+insert data. In this case the size of data() increases. It is also possible to delete
+bytes under the cursor, here the size of data decreases.
+
+There are some limitations: The size of data has in general to be below 10 megabytes,
+otherwise the scroll sliders ard not shown and you can't scroll any more. Copy and
+paste functionality is perhaps a subject of a later release.
+*/
+ class QHexEdit : public QScrollArea
+{
+ Q_OBJECT
+ /*! Property data holds the content of QHexEdit. Call setData() to set the
+ content of QHexEdit, data() returns the actual content.
+ */
+ Q_PROPERTY(QByteArray data READ data WRITE setData)
+
+ /*! Property addressOffset is added to the Numbers of the Address Area.
+ A offset in the address area (left side) is sometimes usefull, whe you show
+ only a segment of a complete memory picture. With setAddressOffset() you set
+ this property - with addressOffset() you get the actual value.
+ */
+ Q_PROPERTY(int addressOffset READ addressOffset WRITE setAddressOffset)
+
+ /*! Property address area color sets (setAddressAreaColor()) the backgorund
+ color of address areas. You can also read the color (addressaAreaColor()).
+ */
+ Q_PROPERTY(QColor addressAreaColor READ addressAreaColor WRITE setAddressAreaColor)
+
+ /*! Property highlighting color sets (setHighlightingColor()) the backgorund
+ color of highlighted text areas. You can also read the color
+ (highlightingColor()).
+ */
+ Q_PROPERTY(QColor highlightingColor READ highlightingColor WRITE setHighlightingColor)
+
+ /*! Porperty overwrite mode sets (setOverwriteMode()) or gets (overwriteMode()) the mode
+ in which the editor works. In overwritem mode the user will overwrite existing data.
+ */
+ Q_PROPERTY(bool overwriteMode READ overwriteMode WRITE setOverwriteMode)
+
+ /*! Porperty read only sets (setReadOnly()) or gets (readOnly()) the
+ current editable mode.
+ */
+ Q_PROPERTY(bool readOnly READ readOnly WRITE setReadOnly)
+
+public:
+ /*! Creates an instance of QHexEdit.
+ \param parent Parent widget of QHexEdit.
+ */
+ QHexEdit(QWidget *parent = 0);
+
+ /*! Inserts a byte array.
+ \param i Index position, where to insert
+ \param ba byte array, which is to insert
+ */
+ void insert(int i, const QByteArray & ba);
+
+ /*! Inserts a char.
+ \param i Index position, where to insert
+ \param ch Char, which is to insert
+ */
+ void insert(int i, char ch);
+
+ /*! Removes len bytes from the content.
+ \param pos Index position, where to remove
+ \param len Amount of bytes to remove
+ */
+ void remove(int pos, int len=1);
+
+ /*! Set the font of the widget. Please use fixed width fonts like Mono or Courier.*/
+ void setFont(const QFont &);
+
+ /*! \cond docNever */
+ void setAddressOffset(int offset);
+ int addressOffset();
+ void setData(QByteArray const &data);
+ QByteArray data();
+ void setAddressAreaColor(QColor const &color);
+ QColor addressAreaColor();
+ void setHighlightingColor(QColor const &color);
+ QColor highlightingColor();
+ void setOverwriteMode(bool);
+ bool overwriteMode();
+ void setReadOnly(bool);
+ bool readOnly();
+ /*! \endcond docNever */
+
+public slots:
+
+ /*! Set the minimum width of the address area.
+ \param addressWidth Width in characters.
+ */
+ void setAddressWidth(int addressWidth);
+
+ /*! Switch the address area on or off.
+ \param addressArea true (show it), false (hide it).
+ */
+ void setAddressArea(bool addressArea);
+
+ /*! Switch the ascii area on or off.
+ \param asciiArea true (show it), false (hide it).
+ */
+ void setAsciiArea(bool asciiArea);
+
+ /*! Switch the highlighting feature on or of.
+ \param mode true (show it), false (hide it).
+ */
+ void setHighlighting(bool mode);
+
+signals:
+
+ /*! Contains the address, where the cursor is located. */
+ void currentAddressChanged(int address);
+
+ /*! Contains the size of the data to edit. */
+ void currentSizeChanged(int size);
+
+ /*! The signal is emited every time, the data is changed. */
+ void dataChanged();
+
+ /*! The signal is emited every time, the overwrite mode is changed. */
+ void overwriteModeChanged(bool state);
+
+private:
+ /*! \cond docNever */
+ QHexEditPrivate *qHexEdit_p;
+ QHBoxLayout *layout;
+ QScrollArea *scrollArea;
+ /*! \endcond docNever */
+};
+
+#endif
+
diff --git a/tags/fred-0.2.0/qhexedit/qhexedit_p.cpp b/tags/fred-0.2.0/qhexedit/qhexedit_p.cpp
new file mode 100644
index 0000000..12f9784
--- /dev/null
+++ b/tags/fred-0.2.0/qhexedit/qhexedit_p.cpp
@@ -0,0 +1,630 @@
+/*******************************************************************************
+* qhexedit Copyright (c) 2011-2020 by Gillen Daniel <gillen.dan@pinguin.lu> *
+* *
+* Simple hex editor widget for Qt. *
+* *
+* Derived from code by Simon Winfried under a compatible license: *
+* Copyright (c) 2010 by Simon Winfried *
+* *
+* This program is free software: you can redistribute it and/or modify it *
+* under the terms of the GNU General Public License as published by the Free *
+* Software Foundation, either version 3 of the License, or (at your option) *
+* any later version. *
+* *
+* This program is distributed in the hope that it will be useful, but WITHOUT *
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or *
+* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for *
+* more details. *
+* *
+* You should have received a copy of the GNU General Public License along with *
+* this program. If not, see <http://www.gnu.org/licenses/>. *
+*******************************************************************************/
+
+#include <QApplication>
+#include <QClipboard>
+#include <QKeyEvent>
+#include <QPainter>
+
+#include "qhexedit_p.h"
+
+const int HEXCHARS_IN_LINE = 47;
+const int GAP_ADR_HEX = 10;
+const int GAP_HEX_ASCII = 16;
+const int BYTES_PER_LINE = 16;
+
+QHexEditPrivate::QHexEditPrivate(QScrollArea *parent) : QWidget(parent) {
+ _scrollArea = parent;
+ setAddressWidth(4);
+ setAddressOffset(0);
+ setAddressArea(true);
+ setAsciiArea(true);
+ setHighlighting(true);
+ setOverwriteMode(true);
+ setAddressAreaColor(QColor(Qt::lightGray).lighter(110));
+ setHighlightingColor(QColor(Qt::yellow).lighter(160));
+ this->setReadOnly(true);
+ this->sel_origin=QPoint(0,0);
+ this->sel_start=QPoint(0,0);
+ this->sel_end=QPoint(0,0);
+
+ setFont(QFont("Mono", 10));
+ connect(&_cursorTimer, SIGNAL(timeout()), this, SLOT(updateCursor()));
+
+ _cursorTimer.setInterval(500);
+
+ setFocusPolicy(Qt::StrongFocus);
+ _size = -1;
+
+ // Create context menu
+ this->p_menu_copy=new QMenu(tr("Copy"),this);
+ this->p_action_copy_selected_bytes=
+ new QAction(tr("Selected bytes"),this->p_menu_copy);
+ this->p_action_copy_selected_text_ascii=
+ new QAction(tr("Selected bytes converted to ASCII"),this->p_menu_copy);
+/*
+ this->p_action_copy_selected_text_utf8=
+ new QAction(tr("Selected text as UTF8"),this->p_menu_copy);
+*/
+
+ this->p_menu_copy->addAction(this->p_action_copy_selected_bytes);
+ this->p_menu_copy->addAction(this->p_action_copy_selected_text_ascii);
+/*
+ this->p_menu_copy->addAction(this->p_action_copy_selected_text_utf8);
+*/
+
+ this->connect(this->p_action_copy_selected_bytes,
+ SIGNAL(triggered()),
+ this,
+ SLOT(SlotCopySelectedBytes()));
+ this->connect(this->p_action_copy_selected_text_ascii,
+ SIGNAL(triggered()),
+ this,
+ SLOT(SlotCopySelectedTextAsAscii()));
+/*
+ this->connect(this->p_action_copy_selected_text_utf8,
+ SIGNAL(triggered()),
+ this,
+ SLOT(SlotCopySelectedTextAsUtf8()));
+*/
+}
+
+QHexEditPrivate::~QHexEditPrivate() {
+ // Delete context menu
+ delete this->p_action_copy_selected_bytes;
+ delete this->p_action_copy_selected_text_ascii;
+/*
+ delete this->p_action_copy_selected_text_utf8;
+*/
+ delete this->p_menu_copy;
+}
+
+void QHexEditPrivate::setAddressOffset(int offset)
+{
+ _addressOffset = offset;
+ adjust();
+}
+
+int QHexEditPrivate::addressOffset()
+{
+ return _addressOffset;
+}
+
+void QHexEditPrivate::setData(const QByteArray &data)
+{
+ // Delete any previous selections
+ this->sel_origin.setX(0);
+ this->sel_origin.setY(0);
+ this->sel_start=this->sel_origin;
+ this->sel_end=this->sel_origin;
+
+ if(!data.isNull() && !data.isEmpty()) this->_cursorTimer.start();
+ else this->_cursorTimer.stop();
+ this->_data = data;
+ this->_originalData = data;
+ this->adjust();
+ this->setCursorPos(0);
+ this->setFocus();
+}
+
+QByteArray QHexEditPrivate::data()
+{
+ return _data;
+}
+
+void QHexEditPrivate::setAddressAreaColor(const QColor &color)
+{
+ _addressAreaColor = color;
+ update();
+}
+
+QColor QHexEditPrivate::addressAreaColor()
+{
+ return _addressAreaColor;
+}
+
+void QHexEditPrivate::setHighlightingColor(const QColor &color)
+{
+ _highlightingColor = color;
+ update();
+}
+
+QColor QHexEditPrivate::highlightingColor()
+{
+ return _highlightingColor;
+}
+
+void QHexEditPrivate::setOverwriteMode(bool overwriteMode)
+{
+ if (overwriteMode != _overwriteMode)
+ {
+ emit overwriteModeChanged(overwriteMode);
+ _overwriteMode = overwriteMode;
+ adjust();
+ }
+}
+
+bool QHexEditPrivate::overwriteMode()
+{
+ return _overwriteMode;
+}
+
+void QHexEditPrivate::setReadOnly(bool read_only) {
+ this->_readOnly=read_only;
+}
+
+bool QHexEditPrivate::readOnly() {
+ return this->_readOnly;
+}
+
+void QHexEditPrivate::insert(int i, const QByteArray & ba)
+{
+ _data.insert(i, ba);
+ _originalData.insert(i, ba);
+}
+
+void QHexEditPrivate::insert(int i, char ch)
+{
+ _data.insert(i, ch);
+ _originalData.insert(i, ch);
+}
+
+void QHexEditPrivate::remove(int index, int len)
+{
+ _data.remove(index, len);
+ _originalData.remove(index, len);
+}
+
+void QHexEditPrivate::setAddressArea(bool addressArea)
+{
+ _addressArea = addressArea;
+ adjust();
+ setCursorPos(_cursorPosition);
+}
+
+void QHexEditPrivate::setAddressWidth(int addressWidth)
+{
+ if ((addressWidth >= 0) and (addressWidth<=6))
+ {
+ _addressNumbers = addressWidth;
+ adjust();
+ setCursorPos(_cursorPosition);
+ }
+}
+
+void QHexEditPrivate::setAsciiArea(bool asciiArea)
+{
+ _asciiArea = asciiArea;
+ adjust();
+}
+
+void QHexEditPrivate::setFont(const QFont &font)
+{
+ QWidget::setFont(font);
+ adjust();
+}
+
+void QHexEditPrivate::setHighlighting(bool mode)
+{
+ _highlighting = mode;
+ update();
+}
+
+void QHexEditPrivate::keyPressEvent(QKeyEvent *event)
+{
+ bool down = false;
+ int charX = (_cursorX - _xPosHex) / _charWidth;
+ int posX = (charX / 3) * 2 + (charX % 3);
+ int posBa = (_cursorY / _charHeight) * BYTES_PER_LINE + posX / 2;
+
+ int key = int(event->text()[0].toLatin1());
+ if (!this->_readOnly &&
+ ((key>='0' && key<='9') || (key>='a' && key <= 'f')))
+ {
+ // insert char
+ if (_overwriteMode == false)
+ if ((charX % 3) == 0)
+ {
+ insert(posBa, char(0));
+ adjust();
+ }
+ if (_data.size() > 0)
+ {
+ QByteArray hexValue = _data.mid(posBa, 1).toHex();
+ if ((charX % 3) == 0)
+ hexValue[0] = key;
+ else
+ hexValue[1] = key;
+ _data.replace(posBa, 1, QByteArray().fromHex(hexValue));
+ emit dataChanged();
+
+ setCursorPos(_cursorPosition + 1);
+ down = true;
+ }
+ }
+
+ // delete char
+ if (!this->_readOnly && event->matches(QKeySequence::Delete)) {
+ remove(posBa);
+ }
+ if (!this->_readOnly && event->key() == Qt::Key_Backspace) {
+ remove(posBa - 1);
+ setCursorPos(_cursorPosition - 2);
+ }
+
+ // handle other function keys
+ if(!this->_readOnly && event->key() == Qt::Key_Insert) {
+ setOverwriteMode(!_overwriteMode);
+ setCursorPos(_cursorPosition);
+ }
+
+ if (event->matches(QKeySequence::MoveToNextChar))
+ {
+ setCursorPos(_cursorPosition + 1);
+ down = true;
+ }
+ if (event->matches(QKeySequence::MoveToPreviousChar))
+ setCursorPos(_cursorPosition - 1);
+ if (event->matches(QKeySequence::MoveToStartOfLine))
+ setCursorPos(_cursorPosition - (_cursorPosition % (2 * BYTES_PER_LINE)));
+ if (event->matches(QKeySequence::MoveToEndOfLine))
+ setCursorPos(_cursorPosition | (2 * BYTES_PER_LINE -1));
+ if (event->matches(QKeySequence::MoveToPreviousLine))
+ setCursorPos(_cursorPosition - (2 * BYTES_PER_LINE));
+ if (event->matches(QKeySequence::MoveToPreviousPage))
+ setCursorPos(_cursorPosition - (((_scrollArea->viewport()->height() / _charHeight) - 1) * 2 * BYTES_PER_LINE));
+ if (event->matches(QKeySequence::MoveToStartOfDocument))
+ setCursorPos(0);
+ if (event->matches(QKeySequence::MoveToNextLine))
+ {
+ setCursorPos(_cursorPosition + (2 * BYTES_PER_LINE));
+ down = true;
+ }
+ if (event->matches(QKeySequence::MoveToEndOfDocument))
+ {
+ setCursorPos(_data.size() * 2);
+ down = true;
+ }
+ if (event->matches(QKeySequence::MoveToNextPage))
+ {
+ setCursorPos(_cursorPosition + (((_scrollArea->viewport()->height() / _charHeight) - 1) * 2 * BYTES_PER_LINE));
+ down = true;
+ }
+
+ // when we move downwards, we have to go a little further
+ if (down)
+ _scrollArea->ensureVisible(_cursorX, _cursorY, 3, 3 + _charHeight);
+ else
+ _scrollArea->ensureVisible(_cursorX, _cursorY, 3, 3);
+ update();
+}
+
+void QHexEditPrivate::mousePressEvent(QMouseEvent *p_event) {
+ if(p_event->button()==Qt::LeftButton) {
+ // Init selection origin, start and end point
+ this->sel_origin=p_event->pos();
+ this->sel_end=this->sel_start=this->sel_origin;
+
+ // Set cursor to current pos
+ int curs_pos=this->Point2Char(this->sel_start);
+ if(curs_pos!=-1) setCursorPos(curs_pos);
+ } else {
+ QWidget::mousePressEvent(p_event);
+ }
+}
+
+void QHexEditPrivate::mouseMoveEvent(QMouseEvent *p_event) {
+ if(p_event->buttons()==Qt::LeftButton) {
+ // Update current selection and repaint hexedit
+ if(this->Point2Char(p_event->pos())>this->Point2Char(this->sel_origin)) {
+ this->sel_start=this->sel_origin;
+ this->sel_end=p_event->pos();
+ } else {
+ this->sel_end=this->sel_origin;
+ this->sel_start=p_event->pos();
+ }
+ this->update();
+ } else {
+ QWidget::mouseMoveEvent(p_event);
+ }
+}
+
+void QHexEditPrivate::paintEvent(QPaintEvent *event) {
+ QPainter painter(this);
+
+ // Draw some patterns if needed
+ painter.fillRect(event->rect(), this->palette().color(QPalette::Base));
+ if(_addressArea) {
+ painter.fillRect(QRect(_xPosAdr,
+ event->rect().top(),
+ _xPosHex-GAP_ADR_HEX+2,
+ height()),
+ _addressAreaColor);
+ }
+ if(_asciiArea) {
+ int linePos=_xPosAscii-(GAP_HEX_ASCII / 2);
+ painter.setPen(Qt::gray);
+ painter.drawLine(linePos,event->rect().top(),linePos,height());
+ }
+
+ painter.setPen(this->palette().color(QPalette::WindowText));
+
+ // Calc positions
+ int firstLineIdx=
+ ((event->rect().top()/_charHeight)-_charHeight)*BYTES_PER_LINE;
+ if(firstLineIdx<0) firstLineIdx=0;
+ int lastLineIdx=
+ ((event->rect().bottom()/_charHeight)+_charHeight)*BYTES_PER_LINE;
+ if(lastLineIdx>_data.size()) lastLineIdx=_data.size();
+ int yPosStart=((firstLineIdx)/BYTES_PER_LINE)*_charHeight+_charHeight;
+
+ // Paint address area
+ if(_addressArea) {
+ for(int lineIdx=firstLineIdx, yPos=yPosStart;
+ lineIdx<lastLineIdx;
+ lineIdx+=BYTES_PER_LINE, yPos+=_charHeight)
+ {
+ QString address=QString("%1").arg(lineIdx+_addressOffset,
+ _realAddressNumbers,
+ 16,
+ QChar('0'));
+ painter.drawText(_xPosAdr, yPos, address);
+ }
+ }
+
+ // Prepare values for a selection
+ int selection_start=0,selection_end=0;
+ bool selection=false;
+ if(!(this->sel_start.isNull() && this->sel_end.isNull()) &&
+ this->sel_start!=this->sel_end)
+ {
+ selection_start=this->Point2Char(this->sel_start)/2;
+ selection_end=this->Point2Char(this->sel_end)/2;
+ selection=true;
+ }
+
+ // Paint hex area
+ QByteArray hexBa(_data.mid(firstLineIdx,lastLineIdx-firstLineIdx+1).toHex());
+ QBrush highLighted=QBrush(_highlightingColor);
+ painter.setBackground(highLighted);
+ painter.setBackgroundMode(Qt::TransparentMode);
+ for(int lineIdx=firstLineIdx, yPos=yPosStart;
+ lineIdx<lastLineIdx;
+ lineIdx+=BYTES_PER_LINE, yPos+=_charHeight)
+ {
+ QByteArray hex;
+ int xPos=_xPosHex;
+ for(int colIdx=0;
+ ((lineIdx+colIdx)<_data.size() && (colIdx<BYTES_PER_LINE));
+ colIdx++)
+ {
+ // Highlight diff bytes
+ if(_highlighting) {
+ int posBa=lineIdx+colIdx;
+ if(posBa>=_originalData.size()) {
+ painter.setBackgroundMode(Qt::TransparentMode);
+ } else {
+ if(_data[posBa]==_originalData[posBa]) {
+ painter.setBackgroundMode(Qt::TransparentMode);
+ } else {
+ painter.setBackgroundMode(Qt::OpaqueMode);
+ }
+ }
+ }
+
+ // Highlight selection
+ if(selection) {
+ int cur_char=lineIdx+colIdx;
+ if(cur_char>=selection_start && cur_char<=selection_end) {
+ painter.setBackgroundMode(Qt::OpaqueMode);
+ } else {
+ painter.setBackgroundMode(Qt::TransparentMode);
+ }
+ }
+
+ // Render hex value
+ if(colIdx==0) {
+ hex=hexBa.mid((lineIdx-firstLineIdx)*2,2);
+ painter.drawText(xPos,yPos,hex);
+ xPos+=2*_charWidth;
+ } else {
+ hex=hexBa.mid((lineIdx+colIdx-firstLineIdx)*2,2).prepend(" ");
+ painter.drawText(xPos,yPos,hex);
+ xPos+=3*_charWidth;
+ }
+ }
+ }
+
+ // Paint ascii area
+ if(_asciiArea) {
+ for(int lineIdx=firstLineIdx, yPos=yPosStart;
+ lineIdx<lastLineIdx;
+ lineIdx+=BYTES_PER_LINE, yPos+=_charHeight)
+ {
+ QByteArray ascii=_data.mid(lineIdx,BYTES_PER_LINE);
+ for(int idx=0, xpos=_xPosAscii;
+ idx<ascii.size();
+ idx++, xpos+=_charWidth)
+ {
+ // Highlight selection
+ if(selection) {
+ int cur_char=lineIdx+idx;
+ if(cur_char>=selection_start && cur_char<=selection_end) {
+ painter.setBackgroundMode(Qt::OpaqueMode);
+ } else {
+ painter.setBackgroundMode(Qt::TransparentMode);
+ }
+ }
+
+ // Render char
+ if(((char)ascii[idx]<0x20) || ((char)ascii[idx]>0x7e)) {
+ painter.drawText(xpos, yPos, QString("."));
+ } else {
+ painter.drawText(xpos, yPos, QString(ascii.at(idx)));
+ }
+ }
+ }
+ }
+
+ // Reset painter background if it is still set from highlighting
+ painter.setBackgroundMode(Qt::TransparentMode);
+
+ // Paint cursor
+ if(_blink && !this->_data.isNull() && !this->_data.isEmpty()) {
+ if(_overwriteMode) {
+ painter.fillRect(_cursorX,
+ _cursorY+_charHeight-2,
+ _charWidth,
+ 2,
+ this->palette().color(QPalette::WindowText));
+ } else {
+ painter.fillRect(_cursorX,
+ _cursorY,
+ 2,
+ _charHeight,
+ this->palette().color(QPalette::WindowText));
+ }
+ }
+
+ if(_size!=_data.size()) {
+ _size=_data.size();
+ emit currentSizeChanged(_size);
+ }
+}
+
+void QHexEditPrivate::setCursorPos(int position)
+{
+ // delete cursor
+ _blink=false;
+ update();
+
+ // cursor in range?
+ if(_overwriteMode) {
+ if(position>(_data.size()*2-1)) position=_data.size()*2-1;
+ } else {
+ if(position>(_data.size()*2)) position=_data.size()*2;
+ }
+
+ if(position < 0) position=0;
+
+ // calc position
+ _cursorPosition=position;
+ _cursorY=(position/(2*BYTES_PER_LINE))*_charHeight+4;
+ int x=(position%(2*BYTES_PER_LINE));
+ _cursorX=(((x/2)*3)+(x%2))*_charWidth+_xPosHex;
+
+ // immiadately draw cursor
+ _blink=true;
+ update();
+ emit currentAddressChanged(_cursorPosition/2);
+}
+
+void QHexEditPrivate::contextMenuEvent(QContextMenuEvent *p_event) {
+ // Only show context menu when something is selected
+ if(!(this->sel_start.isNull() && this->sel_end.isNull()) &&
+ this->sel_start!=this->sel_end)
+ {
+ // Create context menu and add actions
+ QMenu context_menu(this);
+ context_menu.addMenu(this->p_menu_copy);
+ context_menu.exec(p_event->globalPos());
+ }
+}
+
+void QHexEditPrivate::updateCursor()
+{
+ if (_blink)
+ _blink = false;
+ else
+ _blink = true;
+ update(_cursorX, _cursorY, _charWidth, _charHeight);
+}
+
+void QHexEditPrivate::SlotCopySelectedBytes() {
+ int selection_start=this->Point2Char(this->sel_start)/2;
+ int selection_count=this->Point2Char(this->sel_end)/2;
+ selection_count-=(selection_start-1);
+
+ QByteArray hex(this->_data.mid(selection_start,selection_count).toHex());
+
+ QApplication::clipboard()->setText(hex,QClipboard::Clipboard);
+}
+
+void QHexEditPrivate::SlotCopySelectedTextAsAscii() {
+ int selection_start=this->Point2Char(this->sel_start)/2;
+ int selection_count=this->Point2Char(this->sel_end)/2;
+ selection_count-=(selection_start-1);
+
+ QByteArray values(this->_data.mid(selection_start,selection_count));
+
+ QString ascii="";
+ int i=0;
+ for(i=0;i<values.size();i++) {
+ if(!(((char)values[i]<0x20) || ((char)values[i]>0x7e))) {
+ ascii.append(values.at(i));
+ }
+ }
+
+ QApplication::clipboard()->setText(ascii,QClipboard::Clipboard);
+}
+
+/*
+void QHexEditPrivate::SlotCopySelectedTextAsUtf8() {
+ // TODO: Implement
+}
+*/
+
+void QHexEditPrivate::adjust()
+{
+ _charWidth = fontMetrics().width(QLatin1Char('9'));
+ _charHeight = fontMetrics().height();
+
+ // is addressNumbers wide enought?
+ QString test = QString("%1")
+ .arg(_data.size() + _addressOffset, _addressNumbers, 16, QChar('0'));
+ _realAddressNumbers = test.size();
+
+ _xPosAdr = 0;
+ if (_addressArea)
+ _xPosHex = _realAddressNumbers *_charWidth + GAP_ADR_HEX;
+ else
+ _xPosHex = 0;
+ _xPosAscii = _xPosHex + HEXCHARS_IN_LINE * _charWidth + GAP_HEX_ASCII;
+
+ // tell QAbstractScollbar, how big we are
+ setMinimumHeight(((_data.size()/16 + 1) * _charHeight) + 3);
+ setMinimumWidth(_xPosAscii + (BYTES_PER_LINE * _charWidth));
+
+ update();
+}
+
+int QHexEditPrivate::Point2Char(QPoint pos) {
+ // find char under cursor
+ if((pos.x()>=_xPosHex) && (pos.x()<(_xPosHex+HEXCHARS_IN_LINE*_charWidth))) {
+ int x=(pos.x()-_xPosHex)/_charWidth;
+ if((x%3)==0) x=(x/3)*2;
+ else x=((x/3)*2)+1;
+ int y=(pos.y()/_charHeight)*2*BYTES_PER_LINE;
+ return x+y;
+ }
+ return -1;
+}
diff --git a/tags/fred-0.2.0/qhexedit/qhexedit_p.h b/tags/fred-0.2.0/qhexedit/qhexedit_p.h
new file mode 100644
index 0000000..c523435
--- /dev/null
+++ b/tags/fred-0.2.0/qhexedit/qhexedit_p.h
@@ -0,0 +1,128 @@
+/*******************************************************************************
+* qhexedit Copyright (c) 2011-2020 by Gillen Daniel <gillen.dan@pinguin.lu> *
+* *
+* Simple hex editor widget for Qt. *
+* *
+* Derived from code by Simon Winfried under a compatible license: *
+* Copyright (c) 2010 by Simon Winfried *
+* *
+* This program is free software: you can redistribute it and/or modify it *
+* under the terms of the GNU General Public License as published by the Free *
+* Software Foundation, either version 3 of the License, or (at your option) *
+* any later version. *
+* *
+* This program is distributed in the hope that it will be useful, but WITHOUT *
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or *
+* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for *
+* more details. *
+* *
+* You should have received a copy of the GNU General Public License along with *
+* this program. If not, see <http://www.gnu.org/licenses/>. *
+*******************************************************************************/
+
+#ifndef QHEXEDIT_P_H
+#define QHEXEDIT_P_H
+
+/** \cond docNever */
+
+#include <QPoint>
+#include <QTimer>
+#include <QWidget>
+#include <QScrollArea>
+#include <QMenu>
+
+class QHexEditPrivate : public QWidget {
+ Q_OBJECT
+
+ public:
+ QHexEditPrivate(QScrollArea *parent);
+ ~QHexEditPrivate();
+
+ void setAddressOffset(int offset);
+ int addressOffset();
+
+ void setData(QByteArray const &data);
+ QByteArray data();
+
+ void setAddressAreaColor(QColor const &color);
+ QColor addressAreaColor();
+
+ void setHighlightingColor(QColor const &color);
+ QColor highlightingColor();
+
+ void setOverwriteMode(bool overwriteMode);
+ bool overwriteMode();
+ void setReadOnly(bool read_only);
+ bool readOnly();
+
+ void insert(int i, const QByteArray & ba);
+ void insert(int i, char ch);
+ void remove(int index, int len=1);
+
+ void setAddressArea(bool addressArea);
+ void setAddressWidth(int addressWidth);
+ void setAsciiArea(bool asciiArea);
+ void setHighlighting(bool mode);
+ virtual void setFont(const QFont &font);
+
+ signals:
+ void currentAddressChanged(int address);
+ void currentSizeChanged(int size);
+ void dataChanged();
+ void overwriteModeChanged(bool state);
+
+ protected:
+ void keyPressEvent(QKeyEvent * event);
+ void mousePressEvent(QMouseEvent *p_event);
+ void mouseMoveEvent(QMouseEvent *p_event);
+ void paintEvent(QPaintEvent *event);
+ void setCursorPos(int position);
+ void contextMenuEvent(QContextMenuEvent *p_event);
+
+ private slots:
+ void updateCursor();
+ void SlotCopySelectedBytes();
+ void SlotCopySelectedTextAsAscii();
+/*
+ void SlotCopySelectedTextAsUtf8();
+*/
+
+ private:
+ void adjust();
+ int Point2Char(QPoint pos);
+
+ QColor _addressAreaColor;
+ QByteArray _data;
+ QByteArray _originalData;
+ QColor _highlightingColor;
+ QScrollArea *_scrollArea;
+ QTimer _cursorTimer;
+ QPoint sel_origin;
+ QPoint sel_start;
+ QPoint sel_end;
+ QMenu *p_menu_copy;
+ QAction *p_action_copy_selected_bytes;
+ QAction *p_action_copy_selected_text_ascii;
+/*
+ QAction *p_action_copy_selected_text_utf8;
+*/
+
+ bool _blink;
+ bool _addressArea;
+ bool _asciiArea;
+ bool _highlighting;
+ bool _overwriteMode;
+ bool _readOnly;
+
+ int _addressNumbers, _realAddressNumbers;
+ int _addressOffset;
+ int _charWidth, _charHeight;
+ int _cursorX, _cursorY, _cursorPosition;
+ int _xPosAdr, _xPosHex, _xPosAscii;
+ int _size;
+};
+
+/** \endcond docNever */
+
+#endif
+
diff --git a/tags/fred-0.2.0/qt_patches/mingw32-qt-4.8.0-no-webkit-tests.patch b/tags/fred-0.2.0/qt_patches/mingw32-qt-4.8.0-no-webkit-tests.patch
new file mode 100644
index 0000000..3913cdc
--- /dev/null
+++ b/tags/fred-0.2.0/qt_patches/mingw32-qt-4.8.0-no-webkit-tests.patch
@@ -0,0 +1,13 @@
+diff --git a/src/3rdparty/webkit/Source/WebKit.pro b/src/3rdparty/webkit/Source/WebKit.pro
+index 9be0f4a..6744f58 100644
+--- a/src/3rdparty/webkit/Source/WebKit.pro
++++ b/src/3rdparty/webkit/Source/WebKit.pro
+@@ -22,7 +22,7 @@ contains(QT_CONFIG, declarative) {
+ exists($$PWD/WebKit/qt/declarative): SUBDIRS += WebKit/qt/declarative
+ }
+
+-exists($$PWD/WebKit/qt/tests): SUBDIRS += WebKit/qt/tests
++#exists($$PWD/WebKit/qt/tests): SUBDIRS += WebKit/qt/tests
+
+ build-qtscript {
+ SUBDIRS += \
diff --git a/tags/fred-0.2.0/qt_patches/qt-4.8.0-fix-include-windows-h.patch b/tags/fred-0.2.0/qt_patches/qt-4.8.0-fix-include-windows-h.patch
new file mode 100644
index 0000000..4e119f9
--- /dev/null
+++ b/tags/fred-0.2.0/qt_patches/qt-4.8.0-fix-include-windows-h.patch
@@ -0,0 +1,13 @@
+diff --git a/tools/linguist/shared/profileevaluator.cpp b/tools/linguist/shared/profileevaluator.cpp
+index 0539efa..f8767b7 100644
+--- a/tools/linguist/shared/profileevaluator.cpp
++++ b/tools/linguist/shared/profileevaluator.cpp
+@@ -65,7 +65,7 @@
+ #include <unistd.h>
+ #include <sys/utsname.h>
+ #else
+-#include <Windows.h>
++#include <windows.h>
+ #endif
+ #include <stdio.h>
+ #include <stdlib.h>
diff --git a/tags/fred-0.2.0/qt_patches/qt-4.8.4-fix-sse-suppport-build-regression.patch b/tags/fred-0.2.0/qt_patches/qt-4.8.4-fix-sse-suppport-build-regression.patch
new file mode 100644
index 0000000..b23212e
--- /dev/null
+++ b/tags/fred-0.2.0/qt_patches/qt-4.8.4-fix-sse-suppport-build-regression.patch
@@ -0,0 +1,11 @@
+--- a/src/gui/gui.pro
++++ b/src/gui/gui.pro
+@@ -80,7 +80,7 @@
+ DEFINES += QT_NO_DIRECTWRITE
+ }
+
+-contains(QMAKE_MAC_XARCH, no) {
++mac:contains(QMAKE_MAC_XARCH, no) {
+ DEFINES += QT_NO_MAC_XARCH
+ } else {
+ win32-g++*|!win32:!win32-icc*:!macx-icc* {
diff --git a/tags/fred-0.2.0/qtscript_types/bytearray.cpp b/tags/fred-0.2.0/qtscript_types/bytearray.cpp
new file mode 100644
index 0000000..44e5f5d
--- /dev/null
+++ b/tags/fred-0.2.0/qtscript_types/bytearray.cpp
@@ -0,0 +1,181 @@
+/*******************************************************************************
+* Copyright (c) 2011-2020 by Gillen Daniel <gillen.dan@pinguin.lu> *
+* *
+* Derived from code by Nokia Corporation and/or its subsidiary(-ies) under a *
+* compatible license: *
+* *
+* Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). *
+* All rights reserved. *
+* *
+* This program is free software: you can redistribute it and/or modify it *
+* under the terms of the GNU General Public License as published by the Free *
+* Software Foundation, either version 3 of the License, or (at your option) *
+* any later version. *
+* *
+* This program is distributed in the hope that it will be useful, but WITHOUT *
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or *
+* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for *
+* more details. *
+* *
+* You should have received a copy of the GNU General Public License along with *
+* this program. If not, see <http://www.gnu.org/licenses/>. *
+*******************************************************************************/
+
+#include <QScriptEngine>
+
+#include <stdlib.h>
+
+#include "bytearray.h"
+#include "bytearrayiterator.h"
+#include "bytearrayprototype.h"
+
+Q_DECLARE_METATYPE(QByteArray*)
+Q_DECLARE_METATYPE(ByteArray*)
+
+ByteArray::ByteArray(QScriptEngine *engine)
+ : QObject(engine), QScriptClass(engine)
+{
+ qScriptRegisterMetaType<QByteArray>(engine,
+ this->toScriptValue,
+ this->fromScriptValue);
+
+ this->length=engine->toStringHandle(QLatin1String("length"));
+
+ this->proto=engine->newQObject(new ByteArrayPrototype(this),
+ QScriptEngine::QtOwnership,
+ QScriptEngine::SkipMethodsInEnumeration |
+ QScriptEngine::ExcludeSuperClassMethods |
+ QScriptEngine::ExcludeSuperClassProperties);
+ QScriptValue global=engine->globalObject();
+ proto.setPrototype(global.property("Object").property("prototype"));
+
+ this->ctor=engine->newFunction(this->construct,this->proto);
+ this->ctor.setData(qScriptValueFromValue(engine,this));
+}
+
+ByteArray::~ByteArray() {}
+
+QScriptClass::QueryFlags ByteArray::queryProperty(const QScriptValue &object,
+ const QScriptString &name,
+ QueryFlags flags,
+ uint *id)
+{
+ QByteArray *ba=qscriptvalue_cast<QByteArray*>(object.data());
+
+ if(!ba) return 0;
+ if(name!=this->length) {
+ bool is_array_index;
+ qint32 pos=name.toArrayIndex(&is_array_index);
+ if(!is_array_index) return 0;
+ *id=pos;
+ if((flags & HandlesReadAccess) && (pos>=ba->size()))
+ flags &= ~HandlesReadAccess;
+ }
+
+ return flags;
+}
+
+QScriptValue ByteArray::property(const QScriptValue &object,
+ const QScriptString &name,
+ uint id)
+{
+ QByteArray *ba=qscriptvalue_cast<QByteArray*>(object.data());
+ if(!ba) return QScriptValue();
+ if(name==length) return ba->length();
+ else {
+ qint32 pos=id;
+ if((pos < 0) || (pos >= ba->size())) return QScriptValue();
+ return uint(ba->at(pos)) & 255;
+ }
+
+ return QScriptValue();
+}
+
+void ByteArray::setProperty(QScriptValue &object,
+ const QScriptString &name,
+ uint id,
+ const QScriptValue &value)
+{
+ QByteArray *ba=qscriptvalue_cast<QByteArray*>(object.data());
+ if(!ba) return;
+ if(name==length) this->resize(*ba,value.toInt32());
+ else {
+ qint32 pos=id;
+ if(pos<0) return;
+ if(ba->size()<=pos) this->resize(*ba,pos + 1);
+ (*ba)[pos]=char(value.toInt32());
+ }
+}
+
+QScriptValue::PropertyFlags ByteArray::propertyFlags(const QScriptValue &object,
+ const QScriptString &name,
+ uint id)
+{
+ Q_UNUSED(object);
+ Q_UNUSED(id);
+
+ if(name==length) {
+ return QScriptValue::Undeletable | QScriptValue::SkipInEnumeration;
+ }
+ return QScriptValue::Undeletable;
+}
+
+QScriptClassPropertyIterator *ByteArray::newIterator(const QScriptValue &object)
+{
+ return new ByteArrayIterator(object);
+}
+
+QString ByteArray::name() const {
+ return QLatin1String("ByteArray");
+}
+
+QScriptValue ByteArray::prototype() const {
+ return proto;
+}
+
+QScriptValue ByteArray::constructor() {
+ return ctor;
+}
+
+QScriptValue ByteArray::newInstance(int size) {
+#if QT_VERSION >= 0x040700
+ this->engine()->reportAdditionalMemoryCost(size);
+#endif
+ return newInstance(QByteArray(size,0));
+}
+
+QScriptValue ByteArray::newInstance(const QByteArray &ba) {
+ QScriptValue data=engine()->newVariant(qVariantFromValue(ba));
+ return engine()->newObject(this,data);
+}
+
+QScriptValue ByteArray::construct(QScriptContext *ctx, QScriptEngine *) {
+ ByteArray *cls=qscriptvalue_cast<ByteArray*>(ctx->callee().data());
+ if(!cls) return QScriptValue();
+ QScriptValue arg=ctx->argument(0);
+ if(arg.instanceOf(ctx->callee()))
+ return cls->newInstance(qscriptvalue_cast<QByteArray>(arg));
+ int size=arg.toInt32();
+ return cls->newInstance(size);
+}
+
+QScriptValue ByteArray::toScriptValue(QScriptEngine *eng, const QByteArray &ba)
+{
+ QScriptValue ctor=eng->globalObject().property("ByteArray");
+ ByteArray *cls=qscriptvalue_cast<ByteArray*>(ctor.data());
+ if(!cls) return eng->newVariant(qVariantFromValue(ba));
+ return cls->newInstance(ba);
+}
+
+void ByteArray::fromScriptValue(const QScriptValue &obj, QByteArray &ba) {
+ ba=qvariant_cast<QByteArray>(obj.data().toVariant());
+}
+
+void ByteArray::resize(QByteArray &ba, int newSize) {
+ int oldSize=ba.size();
+ ba.resize(newSize);
+#if QT_VERSION >= 0x040700
+ if(newSize>oldSize)
+ this->engine()->reportAdditionalMemoryCost(newSize-oldSize);
+#endif
+ }
diff --git a/tags/fred-0.2.0/qtscript_types/bytearray.h b/tags/fred-0.2.0/qtscript_types/bytearray.h
new file mode 100644
index 0000000..a9c66c4
--- /dev/null
+++ b/tags/fred-0.2.0/qtscript_types/bytearray.h
@@ -0,0 +1,79 @@
+/*******************************************************************************
+* Copyright (c) 2011-2020 by Gillen Daniel <gillen.dan@pinguin.lu> *
+* *
+* Derived from code by Nokia Corporation and/or its subsidiary(-ies) under a *
+* compatible license: *
+* *
+* Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). *
+* All rights reserved. *
+* *
+* This program is free software: you can redistribute it and/or modify it *
+* under the terms of the GNU General Public License as published by the Free *
+* Software Foundation, either version 3 of the License, or (at your option) *
+* any later version. *
+* *
+* This program is distributed in the hope that it will be useful, but WITHOUT *
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or *
+* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for *
+* more details. *
+* *
+* You should have received a copy of the GNU General Public License along with *
+* this program. If not, see <http://www.gnu.org/licenses/>. *
+*******************************************************************************/
+
+// Description: http://cs.karelia.ru/~aborod/doc/qt/script-customclass.html
+
+#ifndef BYTEARRAY_H
+#define BYTEARRAY_H
+
+#include <QObject>
+#include <QScriptClass>
+#include <QScriptString>
+
+class QScriptContext;
+
+class ByteArray : public QObject, public QScriptClass {
+ Q_OBJECT
+ public:
+ ByteArray(QScriptEngine *engine);
+ ~ByteArray();
+
+ QScriptValue constructor();
+
+ QScriptValue newInstance(int size = 0);
+ QScriptValue newInstance(const QByteArray &ba);
+
+ QueryFlags queryProperty(const QScriptValue &object,
+ const QScriptString &name,
+ QueryFlags flags,
+ uint *id);
+ QScriptValue property(const QScriptValue &object,
+ const QScriptString &name,
+ uint id);
+ void setProperty(QScriptValue &object,
+ const QScriptString &name,
+ uint id,
+ const QScriptValue &value);
+ QScriptValue::PropertyFlags propertyFlags(const QScriptValue &object,
+ const QScriptString &name,
+ uint id);
+ QScriptClassPropertyIterator *newIterator(const QScriptValue &object);
+
+ QString name() const;
+
+ QScriptValue prototype() const;
+
+ private:
+ static QScriptValue construct(QScriptContext *ctx, QScriptEngine *eng);
+
+ static QScriptValue toScriptValue(QScriptEngine *eng, const QByteArray &ba);
+ static void fromScriptValue(const QScriptValue &obj, QByteArray &ba);
+
+ void resize(QByteArray &ba, int newSize);
+
+ QScriptString length;
+ QScriptValue proto;
+ QScriptValue ctor;
+};
+
+#endif // BYTEARRAY_H
diff --git a/tags/fred-0.2.0/qtscript_types/bytearrayiterator.cpp b/tags/fred-0.2.0/qtscript_types/bytearrayiterator.cpp
new file mode 100644
index 0000000..34884e5
--- /dev/null
+++ b/tags/fred-0.2.0/qtscript_types/bytearrayiterator.cpp
@@ -0,0 +1,74 @@
+/*******************************************************************************
+* Copyright (c) 2011-2020 by Gillen Daniel <gillen.dan@pinguin.lu> *
+* *
+* Derived from code by Nokia Corporation and/or its subsidiary(-ies) under a *
+* compatible license: *
+* *
+* Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). *
+* All rights reserved. *
+* *
+* This program is free software: you can redistribute it and/or modify it *
+* under the terms of the GNU General Public License as published by the Free *
+* Software Foundation, either version 3 of the License, or (at your option) *
+* any later version. *
+* *
+* This program is distributed in the hope that it will be useful, but WITHOUT *
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or *
+* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for *
+* more details. *
+* *
+* You should have received a copy of the GNU General Public License along with *
+* this program. If not, see <http://www.gnu.org/licenses/>. *
+*******************************************************************************/
+
+#include <QtScript/QScriptEngine>
+
+#include "bytearrayiterator.h"
+
+Q_DECLARE_METATYPE(QByteArray*)
+
+ByteArrayIterator::ByteArrayIterator(const QScriptValue &object)
+ : QScriptClassPropertyIterator(object)
+{
+ toFront();
+}
+
+ByteArrayIterator::~ByteArrayIterator() {}
+
+bool ByteArrayIterator::hasNext() const {
+ QByteArray *ba=qscriptvalue_cast<QByteArray*>(object().data());
+ return m_index<ba->size();
+}
+
+void ByteArrayIterator::next() {
+ m_last=m_index;
+ ++m_index;
+}
+
+bool ByteArrayIterator::hasPrevious() const {
+ return(m_index>0);
+}
+
+void ByteArrayIterator::previous() {
+ --m_index;
+ m_last=m_index;
+}
+
+void ByteArrayIterator::toFront() {
+ m_index=0;
+ m_last=-1;
+}
+
+void ByteArrayIterator::toBack() {
+ QByteArray *ba=qscriptvalue_cast<QByteArray*>(object().data());
+ m_index=ba->size();
+ m_last=-1;
+}
+
+QScriptString ByteArrayIterator::name() const {
+ return this->object().engine()->toStringHandle(QString::number(this->m_last));
+}
+
+uint ByteArrayIterator::id() const {
+ return m_last;
+}
diff --git a/tags/fred-0.2.0/qtscript_types/bytearrayiterator.h b/tags/fred-0.2.0/qtscript_types/bytearrayiterator.h
new file mode 100644
index 0000000..59ddb22
--- /dev/null
+++ b/tags/fred-0.2.0/qtscript_types/bytearrayiterator.h
@@ -0,0 +1,51 @@
+/*******************************************************************************
+* Copyright (c) 2011-2020 by Gillen Daniel <gillen.dan@pinguin.lu> *
+* *
+* Derived from code by Nokia Corporation and/or its subsidiary(-ies) under a *
+* compatible license: *
+* *
+* Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). *
+* All rights reserved. *
+* *
+* This program is free software: you can redistribute it and/or modify it *
+* under the terms of the GNU General Public License as published by the Free *
+* Software Foundation, either version 3 of the License, or (at your option) *
+* any later version. *
+* *
+* This program is distributed in the hope that it will be useful, but WITHOUT *
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or *
+* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for *
+* more details. *
+* *
+* You should have received a copy of the GNU General Public License along with *
+* this program. If not, see <http://www.gnu.org/licenses/>. *
+*******************************************************************************/
+
+#ifndef BYTEARRAYITERATOR_H
+#define BYTEARRAYITERATOR_H
+
+#include <QtScript/QScriptClassPropertyIterator>
+
+class ByteArrayIterator : public QScriptClassPropertyIterator {
+ public:
+ ByteArrayIterator(const QScriptValue &object);
+ ~ByteArrayIterator();
+
+ bool hasNext() const;
+ void next();
+
+ bool hasPrevious() const;
+ void previous();
+
+ void toFront();
+ void toBack();
+
+ QScriptString name() const;
+ uint id() const;
+
+ private:
+ int m_index;
+ int m_last;
+};
+
+#endif // BYTEARRAYITERATOR_H
diff --git a/tags/fred-0.2.0/qtscript_types/bytearrayprototype.cpp b/tags/fred-0.2.0/qtscript_types/bytearrayprototype.cpp
new file mode 100644
index 0000000..b655d1f
--- /dev/null
+++ b/tags/fred-0.2.0/qtscript_types/bytearrayprototype.cpp
@@ -0,0 +1,110 @@
+/*******************************************************************************
+* Copyright (c) 2011-2020 by Gillen Daniel <gillen.dan@pinguin.lu> *
+* *
+* Derived from code by Nokia Corporation and/or its subsidiary(-ies) under a *
+* compatible license: *
+* *
+* Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). *
+* All rights reserved. *
+* *
+* This program is free software: you can redistribute it and/or modify it *
+* under the terms of the GNU General Public License as published by the Free *
+* Software Foundation, either version 3 of the License, or (at your option) *
+* any later version. *
+* *
+* This program is distributed in the hope that it will be useful, but WITHOUT *
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or *
+* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for *
+* more details. *
+* *
+* You should have received a copy of the GNU General Public License along with *
+* this program. If not, see <http://www.gnu.org/licenses/>. *
+*******************************************************************************/
+
+#include <QtScript/QScriptEngine>
+
+#include "bytearrayprototype.h"
+
+Q_DECLARE_METATYPE(QByteArray*)
+
+ByteArrayPrototype::ByteArrayPrototype(QObject *p_parent) : QObject(p_parent) {}
+
+ByteArrayPrototype::~ByteArrayPrototype() {}
+
+QByteArray *ByteArrayPrototype::thisByteArray() const {
+ return qscriptvalue_cast<QByteArray*>(thisObject().data());
+}
+
+void ByteArrayPrototype::chop(int n) {
+ thisByteArray()->chop(n);
+}
+
+bool ByteArrayPrototype::equals(const QByteArray &other) {
+ return *thisByteArray()==other;
+}
+
+QByteArray ByteArrayPrototype::left(int len) const {
+ return thisByteArray()->left(len);
+}
+
+QByteArray ByteArrayPrototype::mid(int pos, int len) const {
+ return thisByteArray()->mid(pos,len);
+}
+
+QScriptValue ByteArrayPrototype::remove(int pos, int len) {
+ thisByteArray()->remove(pos,len);
+ return thisObject();
+}
+
+QScriptValue ByteArrayPrototype::append(const QByteArray &ba) {
+ thisByteArray()->append(ba);
+ return thisObject();
+}
+
+QScriptValue ByteArrayPrototype::appendByte(char byte) const {
+ thisByteArray()->append(byte);
+ return thisObject();
+}
+
+QByteArray ByteArrayPrototype::right(int len) const {
+ return thisByteArray()->right(len);
+}
+
+/*
+QByteArray ByteArrayPrototype::simplified() const {
+ return thisByteArray()->simplified();
+}
+*/
+
+int ByteArrayPrototype::size() const {
+ return thisByteArray()->size();
+}
+
+QByteArray ByteArrayPrototype::toBase64() const {
+ return thisByteArray()->toBase64();
+}
+
+QByteArray ByteArrayPrototype::toLower() const {
+ return thisByteArray()->toLower();
+}
+
+QByteArray ByteArrayPrototype::toUpper() const {
+ return thisByteArray()->toUpper();
+}
+
+QByteArray ByteArrayPrototype::trimmed() const {
+ return thisByteArray()->trimmed();
+}
+
+void ByteArrayPrototype::truncate(int pos) {
+ thisByteArray()->truncate(pos);
+}
+
+QString ByteArrayPrototype::toLatin1String() const {
+ return QString::fromLatin1(*thisByteArray());
+}
+
+QScriptValue ByteArrayPrototype::valueOf() const {
+ return thisObject().data();
+}
+
diff --git a/tags/fred-0.2.0/qtscript_types/bytearrayprototype.h b/tags/fred-0.2.0/qtscript_types/bytearrayprototype.h
new file mode 100644
index 0000000..5dea0c5
--- /dev/null
+++ b/tags/fred-0.2.0/qtscript_types/bytearrayprototype.h
@@ -0,0 +1,63 @@
+/*******************************************************************************
+* Copyright (c) 2011-2020 by Gillen Daniel <gillen.dan@pinguin.lu> *
+* *
+* Derived from code by Nokia Corporation and/or its subsidiary(-ies) under a *
+* compatible license: *
+* *
+* Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). *
+* All rights reserved. *
+* *
+* This program is free software: you can redistribute it and/or modify it *
+* under the terms of the GNU General Public License as published by the Free *
+* Software Foundation, either version 3 of the License, or (at your option) *
+* any later version. *
+* *
+* This program is distributed in the hope that it will be useful, but WITHOUT *
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or *
+* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for *
+* more details. *
+* *
+* You should have received a copy of the GNU General Public License along with *
+* this program. If not, see <http://www.gnu.org/licenses/>. *
+*******************************************************************************/
+
+#ifndef BYTEARRAYPROTOTYPE_H
+#define BYTEARRAYPROTOTYPE_H
+
+#include <QByteArray>
+#include <QObject>
+#include <QtScript/QScriptable>
+#include <QtScript/QScriptValue>
+
+class ByteArrayPrototype : public QObject, public QScriptable {
+ Q_OBJECT
+
+ public:
+ ByteArrayPrototype(QObject *p_parent=0);
+ ~ByteArrayPrototype();
+
+ public slots:
+ void chop(int n);
+ bool equals(const QByteArray &other);
+ QByteArray left(int len) const;
+ QByteArray mid(int pos, int len = -1) const;
+ QScriptValue remove(int pos, int len);
+ QScriptValue append(const QByteArray &ba);
+ QScriptValue appendByte(char byte) const;
+ QByteArray right(int len) const;
+ //QByteArray simplified() const;
+ int size() const;
+ QByteArray toBase64() const;
+ QByteArray toLower() const;
+ QByteArray toUpper() const;
+ QByteArray trimmed() const;
+ void truncate(int pos);
+ QString toLatin1String() const;
+ QScriptValue valueOf() const;
+
+ private:
+ QByteArray *thisByteArray() const;
+};
+
+#endif // BYTEARRAYPROTOTYPE_H
+
diff --git a/tags/fred-0.2.0/registryhive.cpp b/tags/fred-0.2.0/registryhive.cpp
new file mode 100644
index 0000000..f0f7362
--- /dev/null
+++ b/tags/fred-0.2.0/registryhive.cpp
@@ -0,0 +1,1401 @@
+/*******************************************************************************
+* fred Copyright (c) 2011-2020 by Gillen Daniel <gillen.dan@pinguin.lu> *
+* *
+* Forensic Registry EDitor (fred) is a cross-platform M$ registry hive editor *
+* with special feautures useful during forensic analysis. *
+* *
+* This program is free software: you can redistribute it and/or modify it *
+* under the terms of the GNU General Public License as published by the Free *
+* Software Foundation, either version 3 of the License, or (at your option) *
+* any later version. *
+* *
+* This program is distributed in the hope that it will be useful, but WITHOUT *
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or *
+* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for *
+* more details. *
+* *
+* You should have received a copy of the GNU General Public License along with *
+* this program. If not, see <http://www.gnu.org/licenses/>. *
+*******************************************************************************/
+
+#include <QStringList>
+#include <QDateTime>
+#include <QtEndian>
+
+#include <QDebug>
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "registryhive.h"
+
+// TODO: __WORDSIZE is not defined under mingw and I currently have no idea how
+// to identify a 64bit windows
+#ifndef __WORDSIZE
+ #define __WORDSIZE 32
+#endif
+
+#if __WORDSIZE == 64
+ #define EPOCH_DIFF 0x19DB1DED53E8000
+#else
+ #define EPOCH_DIFF 0x19DB1DED53E8000LL
+#endif
+
+// Macros to ease UTF16 endianness conversions
+#undef UTF16LETOH
+#define UTF16LETOH(buf,buf_len) { \
+ for(int buf_off=0;buf_off<((buf_len)-1);buf_off+=2) { \
+ *((quint16*)((buf)+buf_off))=qFromLittleEndian(*((quint16*)((buf)+buf_off))); \
+ } \
+}
+#undef UTF16BETOH
+#define UTF16BETOH(buf,buf_len) { \
+ for(int buf_off=0;buf_off<((buf_len)-1);buf_off+=2) { \
+ *((quint16*)((buf)+buf_off))=qFromBigEndian(*((quint16*)((buf)+buf_off))); \
+ } \
+}
+#undef HTOUTF16LE
+#define HTOUTF16LE(buf,buf_len) { \
+ for(int buf_off=0;buf_off<((buf_len)-1);buf_off+=2) { \
+ *((quint16*)((buf)+buf_off))=qToLittleEndian(*((quint16*)((buf)+buf_off))); \
+ } \
+}
+#undef HTOUTF16BE
+#define HTOUTF16BE(buf,buf_len) { \
+ for(int buf_off=0;buf_off<((buf_len)-1);buf_off+=2) { \
+ *((quint16*)((buf)+buf_off))=qToBigEndian(*((quint16*)((buf)+buf_off))); \
+ } \
+}
+
+// Some errno numbers that hivex uses are not defined under Windows
+#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
+ // These are the same values as defined by MSVC 10, for interoperability.
+ #ifndef ENOTSUP
+ #define ENOTSUP 129
+ #endif
+ #ifndef ELOOP
+ #define ELOOP 114
+ #endif
+#endif
+
+/*******************************************************************************
+ * Public
+ ******************************************************************************/
+
+/*
+ * RegistryHive
+ */
+RegistryHive::RegistryHive(QObject *p_parent) : QObject(p_parent) {
+ this->erro_msg="";
+ this->is_error=false;
+ this->hive_file="";
+ this->p_hive=NULL;
+ this->is_hive_open=false;
+ this->is_hive_writable=false;
+ this->has_changes_to_commit=false;
+}
+
+/*
+ * ~RegistryHive
+ */
+RegistryHive::~RegistryHive() {
+ if(this->is_hive_open) this->Close();
+}
+
+/*
+ * Error
+ */
+bool RegistryHive::Error() {
+ return this->is_error;
+}
+
+/*
+ * GetErrorMsg
+ */
+QString RegistryHive::GetErrorMsg() {
+ QString msg=this->erro_msg;
+ this->erro_msg="";
+ this->is_error=false;
+ return msg;
+}
+
+/*
+ * Open
+ */
+bool RegistryHive::Open(QString file, bool read_only) {
+ if(this->is_hive_open) return false;
+
+ // Open hive file
+ this->p_hive=hivex_open(file.toLocal8Bit().constData(),
+ read_only ? 0 : HIVEX_OPEN_WRITE);
+ if(this->p_hive==NULL) return false;
+
+ // Set local vars
+ this->hive_file=file;
+ this->is_hive_open=true;
+ this->is_hive_writable=!read_only;
+ this->has_changes_to_commit=false;
+
+ return true;
+}
+
+/*
+ * Reopen
+ */
+bool RegistryHive::Reopen(bool read_only) {
+ if(!this->is_hive_open) return false;
+
+ // Close hive first
+ if(hivex_close(this->p_hive)!=0) {
+ // According to the docs, even if hivex_close fails, it frees all handles.
+ // So we consider this fatal and final!
+ this->hive_file="";
+ this->is_hive_open=false;
+ this->is_hive_writable=false;
+ this->has_changes_to_commit=false;
+ return false;
+ }
+
+ // Reopen same hive
+ this->p_hive=hivex_open(this->hive_file.toLocal8Bit().constData(),
+ read_only ? 0 : HIVEX_OPEN_WRITE);
+ if(this->p_hive==NULL) {
+ this->hive_file="";
+ this->is_hive_open=false;
+ this->is_hive_writable=false;
+ this->has_changes_to_commit=false;
+ return false;
+ }
+
+ // Update local vars
+ this->is_hive_writable=!read_only;
+ this->has_changes_to_commit=false;
+
+ return true;
+}
+
+/*
+ * CommitChanges
+ */
+bool RegistryHive::CommitChanges() {
+ if(!this->is_hive_open || !this->is_hive_writable) return false;
+ if(!this->has_changes_to_commit) return true;
+
+ // TODO: Maybe it would be more secure to commit changes to a new file and
+ // then move it over the original one.
+ if(hivex_commit(this->p_hive,NULL,0)!=0) {
+ return false;
+ }
+
+ this->has_changes_to_commit=false;
+ return true;
+}
+
+/*
+ * Close
+ */
+bool RegistryHive::Close() {
+ if(this->is_hive_open) {
+ // As hivex_close will _ALWAYS_ free the handle, we don't need the following
+ // values anymore
+ this->hive_file="";
+ this->is_hive_open=false;
+ this->is_hive_writable=false;
+ this->has_changes_to_commit=false;
+
+ // Close hive
+ if(hivex_close(this->p_hive)!=0) return false;
+ }
+ return true;
+}
+
+/*
+ * Filename
+ */
+QString RegistryHive::Filename() {
+ if(this->is_hive_open) return this->hive_file;
+ return QString();
+}
+
+/*
+ * HiveType
+ */
+RegistryHive::teHiveType RegistryHive::HiveType() {
+ // Check for SYSTEM hive
+ if(this->PathExists("\\Select") && this->PathExists("\\MountedDevices"))
+ return RegistryHive::eHiveType_SYSTEM;
+ // Check for SOFTWARE hive
+ if(this->PathExists("\\Microsoft\\Windows\\CurrentVersion") &&
+ this->PathExists("\\Microsoft\\Windows NT\\CurrentVersion"))
+ return RegistryHive::eHiveType_SOFTWARE;
+ // Check for SAM
+ if(this->PathExists("SAM\\Domains\\Account\\Users"))
+ return RegistryHive::eHiveType_SAM;
+ // Check for SECURITY
+ if(this->PathExists("\\Policy\\Accounts") &&
+ this->PathExists("\\Policy\\PolAdtEv"))
+ return RegistryHive::eHiveType_SECURITY;
+ // Check for NTUSER.DAT
+ if(this->PathExists("\\Software\\Microsoft\\Windows\\CurrentVersion"))
+ return RegistryHive::eHiveType_NTUSER;
+ // Unknown hive
+ return RegistryHive::eHiveType_UNKNOWN;
+}
+
+/*
+ * HiveTypeToString
+ */
+QString RegistryHive::HiveTypeToString(teHiveType hive_type) {
+ switch(hive_type) {
+ case RegistryHive::eHiveType_SYSTEM:
+ return "SYSTEM";
+ break;
+ case RegistryHive::eHiveType_SOFTWARE:
+ return "SOFTWARE";
+ break;
+ case RegistryHive::eHiveType_SAM:
+ return "SAM";
+ break;
+ case RegistryHive::eHiveType_SECURITY:
+ return "SECURITY";
+ break;
+ case RegistryHive::eHiveType_NTUSER:
+ return "NTUSER";
+ break;
+ default:
+ return "UNKNOWN";
+ }
+}
+
+/*
+ * HasChangesToCommit
+ */
+bool RegistryHive::HasChangesToCommit() {
+ return this->has_changes_to_commit;
+}
+
+/*
+ * GetNodes
+ */
+QMap<QString,int> RegistryHive::GetNodes(QString path) {
+ hive_node_h parent_node;
+
+ // Get handle to last node in path
+ if(!this->GetNodeHandle(path,&parent_node)) return QMap<QString,int>();
+
+ // Get and return nodes
+ return this->GetNodesHelper(parent_node);
+}
+
+/*
+ * GetNodes
+ */
+QMap<QString,int> RegistryHive::GetNodes(int parent_node) {
+ if(parent_node==0) {
+ this->SetError(tr("Invalid parent node handle specified!"));
+ return QMap<QString,int>();
+ }
+
+ // Get and return nodes
+ return this->GetNodesHelper(parent_node);
+}
+
+/*
+ * GetKeys
+ */
+QMap<QString,int> RegistryHive::GetKeys(QString path) {
+ hive_node_h parent_node;
+
+ // Get handle to last node in path
+ if(!this->GetNodeHandle(path,&parent_node)) return QMap<QString,int>();
+
+ // Get and return keys
+ return this->GetKeysHelper(parent_node);
+}
+
+/*
+ * GetKeys
+ */
+QMap<QString,int> RegistryHive::GetKeys(int parent_node) {
+ if(parent_node==0) {
+ this->SetError(tr("Invalid parent node handle specified!"));
+ return QMap<QString,int>();
+ }
+
+ // Get and return keys
+ return this->GetKeysHelper(parent_node);
+}
+
+/*
+ * GetKeyName
+ */
+bool RegistryHive::GetKeyName(int hive_key, QString &key_name) {
+ char *buf;
+
+ if(!this->is_hive_open) {
+ this->SetError(tr("Need to operate on an open hive!"));
+ return false;
+ }
+
+ buf=hivex_value_key(this->p_hive,(hive_value_h)hive_key);
+ if(buf==NULL) {
+ this->SetError(tr("Unable to get key name for key '%1'").arg(hive_key));
+ return false;
+ }
+
+ key_name=QString(buf);
+ free(buf);
+
+ return true;
+}
+
+/*
+ * GetKeyValue
+ */
+QByteArray RegistryHive::GetKeyValue(QString path,
+ QString key,
+ int *p_value_type,
+ size_t *p_value_len)
+{
+ hive_node_h parent_node;
+ hive_value_h hive_key;
+
+ // Get handle to last node in path
+ if(!this->GetNodeHandle(path,&parent_node)) return QByteArray();
+
+ // Get key handle
+ hive_key=hivex_node_get_value(this->p_hive,
+ parent_node,key.toLatin1().constData());
+ if(hive_key==0) {
+ this->SetError(tr("Unable to get key handle!"));
+ *p_value_len=-1;
+ return QByteArray();
+ }
+
+ // Get and return key value
+ return this->GetKeyValueHelper(hive_key,p_value_type,p_value_len);
+}
+
+/*
+ * GetKeyValue
+ */
+QByteArray RegistryHive::GetKeyValue(int hive_key,
+ int *p_value_type,
+ size_t *p_value_len)
+{
+ if(hive_key==0) {
+ this->SetError(tr("Invalid key handle specified!"));
+ *p_value_type=-1;
+ return QByteArray();
+ }
+
+ // Get and return key value
+ return this->GetKeyValueHelper(hive_key,p_value_type,p_value_len);
+}
+
+/*
+ * GetKeyModTime
+ */
+qint64 RegistryHive::GetNodeModTime(QString path) {
+ hive_node_h node;
+
+ // Get handle to last node in path
+ if(!this->GetNodeHandle(path,&node)) {
+ this->SetError(tr("Unable to get node handle!"));
+ return 0;
+ }
+
+ // Get and return node's last modification timestamp
+ return this->GetNodeModTime(node);
+}
+
+/*
+ * GetKeyModTime
+ */
+qint64 RegistryHive::GetNodeModTime(int node) {
+ if(node==0) {
+ this->SetError(tr("Invalid node handle specified!"));
+ return 0;
+ }
+
+ // Get and return key's last modification timestamp
+ return hivex_node_timestamp(this->p_hive,node);
+}
+
+/*
+ * KeyValueToString
+ */
+QString RegistryHive::KeyValueToString(QByteArray value, int value_type) {
+ QString ret="";
+
+ #define ToHexStr() { \
+ for(int i=0;i<value.size();i++) { \
+ ret.append(QString("%1 ").arg((quint8)(value.constData()[i]), \
+ 2,16,QChar('0'))); \
+ } \
+ ret.chop(1); \
+ }
+
+ // Convert value according to it's type
+ switch(value_type) {
+ case hive_t_REG_SZ:
+ case hive_t_REG_EXPAND_SZ:
+ // A Windows string (REG_SZ), or a Windows string containing %env%
+ // (environment variable expansion) elements (REG_EXPAND_SZ).
+ // Encoding is unknown, but often UTF16-LE (isn't this great?)
+ // Try to detect ANSI vs UNICODE encoding
+ if(value.size()==0) {
+ ret=QString();
+ } else if(value.size()>=2 && value.endsWith(QByteArray("\x00\x00",2))) {
+ // Seems to be a unicode string, convert to host endianness and return
+ // TODO: What if it is UTF16-BE?? Thx Billy!
+ QByteArray buf=value;
+ UTF16LETOH(buf.data(),buf.size());
+ ret=QString().fromUtf16((ushort*)(buf.constData())).toHtmlEscaped();
+ } else if(value.endsWith(QByteArray("\x00",1))) {
+ // Seems to be an ansi string
+ ret=QString().fromLatin1((char*)value.constData()).toHtmlEscaped();
+ } else {
+ // If we can't detect encoding, return string as hex
+ ToHexStr();
+ }
+ break;
+ case hive_t_REG_MULTI_SZ:
+ // Multiple Windows strings.
+ // I suppose this is always LE encoded! M$ devs really suck!
+ ret=RegistryHive::KeyValueToStringList(value).join("\n");
+ break;
+ case hive_t_REG_DWORD:
+ // DWORD (32 bit integer), little endian
+ ret=QString("0x%1")
+ .arg(qFromLittleEndian(*(quint32*)value.constData()),
+ 8,16,QChar('0'));
+ break;
+ case hive_t_REG_DWORD_BIG_ENDIAN:
+ // DWORD (32 bit integer), big endian
+ ret=QString("0x%1")
+ .arg(qFromBigEndian(*(quint32*)value.constData()),
+ 8,16,QChar('0'));
+ break;
+ case hive_t_REG_QWORD:
+ // QWORD (64 bit integer). Usually little endian (grrrr).
+ ret=QString("0x%1")
+ .arg(qFromLittleEndian(*(quint64*)value.constData()),
+ 16,16,QChar('0'));
+ break;
+ case hive_t_REG_NONE:
+ case hive_t_REG_BINARY:
+ case hive_t_REG_LINK:
+ case hive_t_REG_RESOURCE_LIST:
+ case hive_t_REG_FULL_RESOURCE_DESCRIPTOR:
+ case hive_t_REG_RESOURCE_REQUIREMENTS_LIST:
+ default:
+ // A key without a value (REG_NONE), a blob of binary (REG_BINARY), a
+ // symbolic link to another part of the registry tree (REG_LINK), a
+ // resource list (REG_RESOURCE_LIST), a resource descriptor
+ // (FULL_RESOURCE_DESCRIPTOR), a resource requirements list
+ // (REG_RESOURCE_REQUIREMENTS_LIST) or something unknown.
+ // All these are converted to hex.
+ ToHexStr();
+ }
+
+ #undef ToHexStr
+
+ return ret;
+}
+
+/*
+ * KeyValueToString
+ */
+QString RegistryHive::KeyValueToString(QByteArray key_value,
+ QString format,
+ int offset,
+ int length,
+ bool little_endian)
+{
+ int remaining_data_len;
+ const char *p_data;
+ QString ret="";
+
+ // Calculate how many bytes are remainig after specified offset
+ remaining_data_len=key_value.size()-offset;
+ if(!(remaining_data_len>0)) {
+ // Nothing to show
+ return QString();
+ }
+
+ // Get pointer to data at specified offset
+ p_data=key_value.constData();
+ p_data+=offset;
+
+ // Convert value
+ if(format=="int8" && remaining_data_len>=1) {
+ ret=QString("%1").arg(*(qint8*)p_data);
+ } else if(format=="uint8" && remaining_data_len>=1) {
+ ret=QString("%1").arg(*(quint8*)p_data);
+ } else if(format=="int16" && remaining_data_len>=2) {
+ qint16 val;
+ if(little_endian) val=qFromLittleEndian(*(qint16*)p_data);
+ else val=qFromBigEndian(*(qint16*)p_data);
+ ret=QString("%1").arg(val);
+ } else if(format=="uint16" && remaining_data_len>=2) {
+ quint16 val;
+ if(little_endian) val=qFromLittleEndian(*(quint16*)p_data);
+ else val=qFromBigEndian(*(quint16*)p_data);
+ ret=QString("%1").arg(val);
+ } else if(format=="int32" && remaining_data_len>=4) {
+ qint32 val;
+ if(little_endian) val=qFromLittleEndian(*(qint32*)p_data);
+ else val=qFromBigEndian(*(qint32*)p_data);
+ ret=QString("%1").arg(val);
+ } else if(format=="uint32" && remaining_data_len>=4) {
+ quint32 val;
+ if(little_endian) val=qFromLittleEndian(*(quint32*)p_data);
+ else val=qFromBigEndian(*(quint32*)p_data);
+ ret=QString("%1").arg(val);
+ } else if(format=="unixtime" && remaining_data_len>=4) {
+ quint32 val;
+ if(little_endian) val=qFromLittleEndian(*(quint32*)p_data);
+ else val=qFromBigEndian(*(quint32*)p_data);
+ if(val==0) {
+ ret="n/a";
+ } else {
+ QDateTime date_time;
+ date_time.setTimeSpec(Qt::UTC);
+ date_time.setTime_t(val);
+ ret=date_time.toString("yyyy/MM/dd hh:mm:ss");
+ }
+ } else if(format=="int64" && remaining_data_len>=8) {
+ qint64 val;
+ if(little_endian) val=qFromLittleEndian(*(qint64*)p_data);
+ else val=qFromBigEndian(*(qint64*)p_data);
+ ret=QString("%1").arg(val);
+ } else if(format=="uint64" && remaining_data_len>=8) {
+ quint64 val;
+ if(little_endian) val=qFromLittleEndian(*(quint64*)p_data);
+ else val=qFromBigEndian(*(quint64*)p_data);
+ ret=QString("%1").arg(val);
+/*
+ // TODO: Check how one could implement this
+ } else if(format=="unixtime64" && remaining_data_len>=8) {
+ if(*(quint64*)p_data==0) {
+ ret="n/a";
+ } else {
+ quint64 secs=*(quint64*)p_data;
+ QDateTime date_time;
+ date_time.setTimeSpec(Qt::UTC);
+ // Set 32bit part of date/time
+ date_time.setTime_t(secs&0xFFFFFFFF);
+ // Now add high 32bit part of date/time
+ date_time.addSecs(secs>>32);
+ ret=date_time.toString("yyyy/MM/dd hh:mm:ss");
+ }
+*/
+ } else if(format=="filetime" && remaining_data_len>=8) {
+ quint64 val;
+ if(little_endian) val=qFromLittleEndian(*(quint64*)p_data);
+ else val=qFromBigEndian(*(quint64*)p_data);
+ if(val==0) {
+ ret="n/a";
+ } else {
+ // TODO: Warn if >32bit
+ QDateTime date_time;
+ date_time.setTimeSpec(Qt::UTC);
+ date_time.setTime_t(RegistryHive::FiletimeToUnixtime(val));
+ ret=date_time.toString("yyyy/MM/dd hh:mm:ss");
+ }
+ } else if(format=="ascii") {
+ if(length!=-1) {
+ // User specified how many bytes to convert
+ ret=QString().fromLatin1((char*)p_data,length).toHtmlEscaped();
+ } else {
+ // User did not specify how many bytes to convert, make sure data is 0
+ // terminated
+ if(key_value.indexOf("\x00",offset)!=-1) {
+ // Data is 0 terminated
+ ret=QString().fromLatin1((char*)p_data).toHtmlEscaped();
+ } else {
+ // Data is not 0 terminated, convert all remaining_data_len bytes
+ ret=QString().fromLatin1((char*)p_data,remaining_data_len).toHtmlEscaped();
+ }
+ }
+ } else if(format=="utf16" && remaining_data_len>=2) {
+ QByteArray buf;
+ if(length!=-1) {
+ // User specified how many bytes to convert
+ buf=key_value.mid(offset,(length%2)==0 ? length : length-1);
+ buf.append("\x00\x00",2);
+ } else {
+ // User did not specify how many bytes to convert, make sure data is
+ // double 0 terminated
+ int null_offset=RegistryHive::FindUnicodeStringEnd(key_value.mid(offset));
+ if(null_offset!=-1) {
+ // Data is double 0 terminated
+ buf=key_value.mid(offset,null_offset+2);
+ } else {
+ // Data is not double 0 terminated, convert all remaining_data_len bytes
+ buf=key_value.mid(offset,
+ (remaining_data_len%2)==0 ?
+ remaining_data_len : remaining_data_len-1);
+ buf.append("\x00\x00",2);
+ }
+ }
+ // Convert from requested endianness to host
+ if(little_endian) {
+ UTF16LETOH(buf.data(),buf.size());
+ } else {
+ UTF16BETOH(buf.data(),buf.size());
+ }
+ ret=QString().fromUtf16((ushort*)buf.constData()).toHtmlEscaped();
+ } else {
+ // Unknown variant type or another error
+ // TODO: Maybe return an error
+ return QString();
+ }
+
+ return ret;
+}
+
+/*
+ * KeyValueToStringList
+ *
+ * Should only be used for REG_MULTI_SZ values
+ */
+QStringList RegistryHive::KeyValueToStringList(QByteArray value,
+ bool little_endian,
+ bool *p_ansi_encoded)
+{
+ // Try to find value encoding (ANSI vs UNICODE)
+ bool is_ansi;
+ if(value.size()<=2) {
+ // http://blogs.msdn.com/b/oldnewthing/archive/2009/10/08/9904646.aspx
+ // Ansi version of a REG_MULTI_SZ needs to be terminated by 2 \0 chars.
+ // So as long as the byte array has less or equal to 2 chars, it must be
+ // empty.
+ return QStringList();
+ } else if(value.size()==3) {
+ // Only 3 chars, this can only be an ansi string consisting of 1 char and 2
+ // \0 to terminate it
+ return QStringList()
+ <<QString(QChar((char)*((quint8*)(value.constData())))).toHtmlEscaped();
+ } else if(value.size()==4) {
+ if((quint32)*((quint32*)(value.constData()))==0) {
+ // http://blogs.msdn.com/b/oldnewthing/archive/2009/10/08/9904646.aspx
+ // Unicode version of a REG_MULTI_SZ needs to be terminated by 4 \0 chars.
+ // So as long as the byte array has less or equal to 4 chars, and they are
+ // all 0 it must be empty.
+ return QStringList();
+ } else {
+ // Must be the ansi version of REG_MULTI_SZ
+ is_ansi=true;
+ }
+ } else if((quint32)*((quint32*)(value.right(4).constData()))==0) {
+ // Value ends with 4 \0 chars, it must be unicode
+ is_ansi=false;
+ } else if((quint32)*((quint32*)(value.right(3).constData()))==0) {
+ // Value ends with 3 \0 chars. Not possible according to the specs, but
+ // already seen in values M$ is storing! Those were unicode.
+ is_ansi=false;
+ } else if((quint16)*((quint16*)(value.right(2).constData()))==0) {
+ // Value only ends with 2 \0 chars, it must be ansi
+ is_ansi=true;
+ } else {
+ // Value has more than 4 chars but does not end in 2 or 4 \0 chars. This
+ // is not according to specs!
+ return QStringList();
+ }
+
+ // Convert value to string list
+ QStringList result=QStringList();
+ QByteArray buf;
+ int last_pos=0,cur_pos=0;
+ if(!is_ansi) {
+ // Extract unicode strings
+ while(last_pos<value.size() &&
+ (cur_pos=RegistryHive::FindUnicodeStringEnd(value,last_pos))!=-1)
+ {
+ if(cur_pos==last_pos) break;
+ buf=value.mid(last_pos,(cur_pos-last_pos)+2);
+ if(little_endian) {
+ // Convert from LE to host
+ UTF16LETOH(buf.data(),buf.size());
+ } else {
+ // Convert from BE to host
+ UTF16BETOH(buf.data(),buf.size());
+ }
+ result.append(QString().fromUtf16((ushort*)buf.constData()).toHtmlEscaped());
+ last_pos=cur_pos+2;
+ }
+ } else {
+ // Extract ansi strings
+ while(last_pos<value.count() &&
+ (cur_pos=value.indexOf(QByteArray("\x00",1),last_pos))!=-1)
+ {
+ if(cur_pos==last_pos) break;
+ result.append(QString().fromLocal8Bit(value.mid(last_pos,
+ (cur_pos-last_pos)+1)
+ .constData()).toHtmlEscaped());
+ last_pos=cur_pos+1;
+ }
+ }
+
+ if(p_ansi_encoded!=NULL) *p_ansi_encoded=is_ansi;
+ return result;
+}
+
+/*
+ * StringListToKeyValue
+ */
+QByteArray RegistryHive::StringListToKeyValue(QStringList strings,
+ bool little_endian,
+ bool ansi_encoded)
+{
+ // Return empty key value if there are no strings
+ if(strings.count()==0) {
+ if(ansi_encoded) return QByteArray("\x00\x00",2);
+ else return QByteArray("\x00\x00\x00\x00",4);
+ }
+
+ // Convert string list
+ QByteArray result=QByteArray();
+ QString cur_string;
+ QByteArray buf;
+ QListIterator<QString> strings_it(strings);
+ while(strings_it.hasNext()) {
+ cur_string=strings_it.next();
+ if(ansi_encoded) {
+ // Ansi encoding, simply append char string and terminating \0
+ result.append(cur_string.toLatin1().constData(),cur_string.size());
+ result.append("\x00",1);
+ } else {
+ // Unicode encoding
+ // First, convert value to utf16
+ // TODO: May fail if there is a char that needs more than 16 bit
+ buf=QByteArray((char*)(cur_string.utf16()),cur_string.size()*2);
+ // Then convert to correct endianness
+ if(little_endian) {
+ HTOUTF16LE(buf.data(),buf.size());
+ } else {
+ HTOUTF16BE(buf.data(),buf.size());
+ }
+ // And finally append converted value and terminating \0\0 to result
+ result.append(buf);
+ result.append("\x00\x00",2);
+ }
+ }
+
+ // Append terminating \0 chars and return
+ if(ansi_encoded) result.append("\x00",1);
+ else result.append("\x00\x00",2);
+ return result;
+}
+
+/*
+ * GetKeyValueTypes
+ */
+QStringList RegistryHive::GetKeyValueTypes() {
+ return QStringList()<<"REG_NONE"
+ <<"REG_SZ"
+ <<"REG_EXPAND_SZ"
+ <<"REG_BINARY"
+ <<"REG_DWORD"
+ <<"REG_DWORD_BIG_ENDIAN"
+ <<"REG_LINK"
+ <<"REG_MULTI_SZ"
+ <<"REG_RESOURCE_LIST"
+ <<"REG_FULL_RESOURCE_DESC"
+ <<"REG_RESOURCE_REQ_LIST"
+ <<"REG_QWORD";
+}
+
+/*
+ * KeyTypeToString
+ */
+QString RegistryHive::KeyValueTypeToString(int value_type) {
+ QString ret="";
+
+ switch(value_type) {
+ case hive_t_REG_NONE:
+ ret="REG_NONE";
+ break;
+ case hive_t_REG_SZ:
+ ret="REG_SZ";
+ break;
+ case hive_t_REG_EXPAND_SZ:
+ ret="REG_EXPAND_SZ";
+ break;
+ case hive_t_REG_BINARY:
+ ret="REG_BINARY";
+ break;
+ case hive_t_REG_DWORD:
+ ret="REG_DWORD";
+ break;
+ case hive_t_REG_DWORD_BIG_ENDIAN:
+ ret="REG_DWORD_BIG_ENDIAN";
+ break;
+ case hive_t_REG_LINK:
+ ret="REG_LINK";
+ break;
+ case hive_t_REG_MULTI_SZ:
+ ret="REG_MULTI_SZ";
+ break;
+ case hive_t_REG_RESOURCE_LIST:
+ ret="REG_RESOURCE_LIST";
+ break;
+ case hive_t_REG_FULL_RESOURCE_DESCRIPTOR:
+ ret="REG_FULL_RESOURCE_DESC";
+ break;
+ case hive_t_REG_RESOURCE_REQUIREMENTS_LIST:
+ ret="REG_RESOURCE_REQ_LIST";
+ break;
+ case hive_t_REG_QWORD:
+ ret="REG_QWORD";
+ break;
+ default:
+ ret=QString("0x%1").arg((quint32)value_type,8,16,QChar('0'));
+ }
+
+ return ret;
+}
+
+/*
+ * StringToKeyValueType
+ */
+int RegistryHive::StringToKeyValueType(QString value_type) {
+ if(value_type=="REG_NONE") return hive_t_REG_NONE;
+ if(value_type=="REG_SZ") return hive_t_REG_SZ;
+ if(value_type=="REG_EXPAND_SZ") return hive_t_REG_EXPAND_SZ;
+ if(value_type=="REG_BINARY") return hive_t_REG_BINARY;
+ if(value_type=="REG_DWORD") return hive_t_REG_DWORD;
+ if(value_type=="REG_DWORD_BIG_ENDIAN") return hive_t_REG_DWORD_BIG_ENDIAN;
+ if(value_type=="REG_LINK") return hive_t_REG_LINK;
+ if(value_type=="REG_MULTI_SZ") return hive_t_REG_MULTI_SZ;
+ if(value_type=="REG_RESOURCE_LIST") return hive_t_REG_RESOURCE_LIST;
+ if(value_type=="REG_FULL_RESOURCE_DESC")
+ return hive_t_REG_FULL_RESOURCE_DESCRIPTOR;
+ if(value_type=="REG_RESOURCE_REQ_LIST")
+ return hive_t_REG_RESOURCE_REQUIREMENTS_LIST;
+ if(value_type=="REG_QWORD") return hive_t_REG_QWORD;
+
+ // I think this might be a good default :-)
+ return hive_t_REG_BINARY;
+}
+
+/*
+ * FiletimeToUnixtime
+ */
+quint64 RegistryHive::FiletimeToUnixtime(qint64 filetime) {
+ return (unsigned)((filetime-EPOCH_DIFF)/10000000);
+}
+
+/*
+ * AddNode
+ */
+int RegistryHive::AddNode(QString parent_node_path, QString node_name) {
+ if(!this->is_hive_writable) return 0;
+
+ // Make sure name does not contain a backslash char
+ if(node_name.contains('\\')) {
+ this->SetError(tr("Unable to add node with name '%1'. "
+ "Names can not include a backslash character.")
+ .arg(node_name));
+ return 0;
+ }
+
+ // Get node handle to the parent where the new node should be created
+ hive_node_h parent_node;
+ if(!this->GetNodeHandle(parent_node_path,&parent_node)) {
+ this->SetError(tr("Unable to get node handle for '%1'!")
+ .arg(parent_node_path));
+ return 0;
+ }
+
+ // Make sure there is no other node with same name
+ QMap<QString,int> child_nodes=this->GetNodes(parent_node);
+ if(child_nodes.contains(node_name.toLatin1())) {
+ this->SetError(tr("The node '%1\\%2' already exists!")
+ .arg(parent_node_path,node_name));
+ return 0;
+ }
+
+ // Add new node
+ hive_node_h new_node=hivex_node_add_child(this->p_hive,
+ parent_node,
+ node_name.toLatin1().constData());
+ if(new_node==0) {
+ this->SetError(tr("Unable to create new node '%1\\%2'!")
+ .arg(parent_node_path,node_name));
+ return 0;
+ }
+
+ this->has_changes_to_commit=true;
+ return new_node;
+}
+
+/*
+ * DeleteNode
+ */
+bool RegistryHive::DeleteNode(QString node_path) {
+ if(!this->is_hive_writable) return false;
+
+ // Get node handle to the node that should be deleted
+ hive_node_h node;
+ if(!this->GetNodeHandle(node_path,&node)) {
+ this->SetError(tr("Unable to get node handle for '%1'!")
+ .arg(node_path));
+ return false;
+ }
+
+ // Delete node
+ if(hivex_node_delete_child(this->p_hive,node)==-1) {
+ this->SetError(tr("Unable to delete node '%1'!")
+ .arg(node_path));
+ return false;
+ }
+
+ this->has_changes_to_commit=true;
+ return true;
+}
+
+/*
+ * AddKey
+ */
+int RegistryHive::AddKey(QString parent_node_path,
+ QString key_name,
+ QString key_value_type,
+ QByteArray key_value)
+{
+ if(!this->is_hive_open || !this->is_hive_writable) {
+ this->SetError(tr("Hive has not been opened or opened read-only!"));
+ return false;
+ }
+
+ return this->SetKey(parent_node_path,
+ key_name,
+ key_value_type,
+ key_value,
+ true);
+}
+
+/*
+ * UpdateKey
+ */
+int RegistryHive::UpdateKey(QString parent_node_path,
+ QString key_name,
+ QString key_value_type,
+ QByteArray key_value)
+{
+ if(!this->is_hive_open || !this->is_hive_writable) {
+ this->SetError(tr("Hive has not been opened or opened read-only!"));
+ return false;
+ }
+
+ return this->SetKey(parent_node_path,
+ key_name,
+ key_value_type,
+ key_value,
+ false);
+}
+
+/*
+ * DeleteKey
+ */
+bool RegistryHive::DeleteKey(QString parent_node_path, QString key_name) {
+ if(!this->is_hive_open || !this->is_hive_writable) {
+ this->SetError(tr("Hive has not been opened or opened read-only!"));
+ return false;
+ }
+
+ // libhivex offers no possibility to delete a single key :-(
+ // As a work around, this function temporarly stores all keys of the specified
+ // node, then deletes them all an re-creates all but the one that should be
+ // deleted.
+
+ // Get handle to parent node
+ hive_node_h parent_node;
+ if(!this->GetNodeHandle(parent_node_path,&parent_node)) {
+ return false;
+ }
+
+ // Get all child keys
+ hive_value_h *p_keys=hivex_node_values(this->p_hive,parent_node);
+ if(p_keys==NULL) {
+ this->SetError(tr("Unable to enumerate child keys for parent '%1'!")
+ .arg(parent_node_path));
+ return false;
+ }
+
+ // Get all child key values except the one that should be deleted
+ int i=0;
+ char *p_name;
+ int node_keys_count=0;
+ hive_set_value *node_keys=NULL;
+
+#define FREE_NODE_KEYS() { \
+ for(int x=0;x<node_keys_count;x++) { \
+ free(node_keys[x].key); \
+ free(node_keys[x].value); \
+ } \
+ free(node_keys); \
+}
+
+ while(p_keys[i]) {
+ p_name=hivex_value_key(this->p_hive,p_keys[i]);
+ if(p_name==NULL) {
+ this->SetError(tr("Unable to get key name for a child of '%1'!")
+ .arg(parent_node_path));
+ return false;
+ }
+ if(QString(p_name)!=key_name) {
+ // Current key is not the one that should be deleted, save it
+ // Alloc mem for new hive_set_value struct in node_keys array
+ node_keys=(hive_set_value*)realloc(node_keys,
+ sizeof(hive_set_value)*
+ (node_keys_count+1));
+ if(node_keys==NULL) {
+ this->SetError(tr("Unable to alloc enough memory for all child keys!"));
+ return false;
+ }
+ // Save key name in hive_set_value struct
+ node_keys[node_keys_count].key=p_name;
+ // Get key value, key value type and key value len and save to
+ // hive_set_value struct
+ node_keys[node_keys_count].value=
+ hivex_value_value(this->p_hive,
+ p_keys[i],
+ &(node_keys[node_keys_count].t),
+ &(node_keys[node_keys_count].len));
+ if(node_keys[node_keys_count].value==NULL) {
+ this->SetError(tr("Unable to get value for key '%1'!").arg(p_name));
+ free(p_name);
+ // Free all temporary stored keys
+ FREE_NODE_KEYS();
+ return false;
+ }
+ node_keys_count++;
+ } else {
+ // Current key is to be deleted, ignore it
+ free(p_name);
+ }
+ i++;
+ }
+
+ // Save all stored keys to hive, which will discard the one that should be
+ // deleted
+ if(hivex_node_set_values(this->p_hive,
+ parent_node,
+ node_keys_count,
+ node_keys,
+ 0)!=0)
+ {
+ this->SetError(tr("Unable to re-save all child keys! Please discard any "
+ "changes you made and start over. No doing so might end "
+ "in data loss!"));
+ // Free all temporary stored keys
+ FREE_NODE_KEYS();
+ return false;
+ }
+
+ // Free all temporary stored keys and return
+ FREE_NODE_KEYS();
+
+#undef FREE_NODE_KEYS
+
+ this->has_changes_to_commit=true;
+ return true;
+}
+
+/*******************************************************************************
+ * Private
+ ******************************************************************************/
+
+/*
+ * HivexError2String
+ */
+QString RegistryHive::HivexError2String(int error) {
+ switch(error) {
+ case ENOTSUP:
+ return QString("Corrupt or unsupported Registry file format.");
+ break;
+ case HIVEX_NO_KEY:
+ return QString("Missing root key.");
+ break;
+ case EINVAL:
+ return QString("Passed an invalid argument to the function.");
+ break;
+ case EFAULT:
+ return QString("Followed a Registry pointer which goes outside the "
+ "registry or outside a registry block.");
+ break;
+ case ELOOP:
+ return QString("Registry contains cycles.");
+ break;
+ case ERANGE:
+ return QString("Field in the registry out of range.");
+ break;
+ case EEXIST:
+ return QString("Registry key already exists.");
+ break;
+ case EROFS:
+ return QString("Tried to write to a registry which is not opened for "
+ "writing.");
+ break;
+ default:
+ return QString("Unknown error.");
+ }
+}
+
+/*
+ * SetError
+ */
+void RegistryHive::SetError(QString msg) {
+ this->erro_msg=msg;
+ this->is_error=true;
+}
+
+/*
+ * GetNodeHandle
+ */
+bool RegistryHive::GetNodeHandle(QString &path, hive_node_h *p_node) {
+ QStringList nodes;
+ int i=0;
+
+ // Get root node handle
+ *p_node=hivex_root(this->p_hive);
+ if(*p_node==0) {
+ this->SetError(tr("Unable to get root node!"));
+ return false;
+ }
+
+ if(path!="\\") {
+ // If we aren't listing the root node, we have to get a handle to the
+ // last node in the path. Split path into nodes
+ nodes=path.split('\\',QString::SkipEmptyParts);
+
+ // Iterate to the correct parent node
+ for(i=0;i<nodes.count();i++) {
+ *p_node=hivex_node_get_child(this->p_hive,
+ *p_node,
+ nodes.value(i).toLatin1().constData());
+ if(*p_node==0) {
+ this->SetError(tr("Unable to find node '%1'!").arg(nodes.value(i)));
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+/*
+ * GetKeyHandle
+ */
+bool RegistryHive::GetKeyHandle(QString &parent_node_path,
+ QString &key_name,
+ hive_value_h *p_key)
+{
+ // Get handle to parent node
+ hive_node_h parent_node;
+ if(!this->GetNodeHandle(parent_node_path,&parent_node)) {
+ return false;
+ }
+
+ // Get handle to key
+ *p_key=hivex_node_get_value(this->p_hive,
+ parent_node,
+ key_name.toLatin1().constData());
+ if(*p_key==0) {
+ this->SetError(tr("Unable to get handle to key '%1\\%2'!")
+ .arg(parent_node_path,key_name));
+ return false;
+ }
+
+ return true;
+}
+
+/*
+ * GetNodesHelper
+ */
+QMap<QString,int> RegistryHive::GetNodesHelper(hive_node_h parent_node) {
+ QMap<QString,int> keys;
+ char *p_name;
+ int i=0;
+
+ // Get child nodes
+ hive_node_h *child_nodes=hivex_node_children(this->p_hive,parent_node);
+ if(child_nodes==NULL) {
+ this->SetError(
+ tr("Unable to enumerate child nodes!"));
+ return QMap<QString,int>();
+ }
+
+ // Build result
+ keys.clear();
+ i=0;
+ while(child_nodes[i]) {
+ p_name=hivex_node_name(this->p_hive,child_nodes[i]);
+ if(p_name==NULL) {
+ this->SetError(tr("Unable to get node name!"));
+ free(child_nodes);
+ return QMap<QString,int>();
+ }
+ keys.insert(QString(p_name),(int)child_nodes[i]);
+ free(p_name);
+ i++;
+ }
+ free(child_nodes);
+
+ return keys;
+}
+
+/*
+ * GetKeysHelper
+ */
+QMap<QString,int> RegistryHive::GetKeysHelper(hive_node_h parent_node) {
+ QMap<QString,int> keys;
+ char *p_name;
+ int i=0;
+
+ // Get child keys
+ hive_value_h *p_keys=hivex_node_values(this->p_hive,parent_node);
+ if(p_keys==NULL) {
+ this->SetError(
+ tr("Unable to enumerate child keys!"));
+ return QMap<QString,int>();
+ }
+
+ // Build result list
+ keys.clear();
+ i=0;
+
+ while(p_keys[i]) {
+ p_name=hivex_value_key(this->p_hive,p_keys[i]);
+ if(p_name==NULL) {
+ this->SetError(tr("Unable to get key name!"));
+ return QMap<QString,int>();
+ }
+ keys.insert(QString(p_name),p_keys[i]);
+ free(p_name);
+ i++;
+ }
+ free(p_keys);
+
+ return keys;
+}
+
+/*
+ * GetKeyValueHelper
+ */
+QByteArray RegistryHive::GetKeyValueHelper(hive_value_h hive_key,
+ int *p_value_type,
+ size_t *p_value_len)
+{
+ QByteArray key_value;
+ char *p_key_value;
+
+ p_key_value=hivex_value_value(this->p_hive,
+ hive_key,
+ (hive_type*)p_value_type,
+ p_value_len);
+ if(p_key_value==NULL) {
+ this->SetError(tr("Unable to get key value!"));
+ *p_value_type=-1;
+ return QByteArray();
+ }
+
+ // Feed QByteArray and free p_key_value
+ key_value=QByteArray(p_key_value,*p_value_len);
+ free(p_key_value);
+
+ return key_value;
+}
+
+/*
+ * PathExists
+ */
+bool RegistryHive::PathExists(QString path) {
+ bool ret;
+ hive_node_h node;
+
+ ret=this->GetNodeHandle(path,&node);
+ if(!ret || this->Error()) {
+ // Clear error and return false
+ this->GetErrorMsg();
+ return false;
+ }
+
+ return true;
+}
+
+/*
+ * SetKey
+ */
+int RegistryHive::SetKey(QString &parent_node_path,
+ QString &key_name,
+ QString &key_value_type,
+ QByteArray &key_value,
+ bool create_key)
+{
+ // Get node handle to the node that holds the key to create/update
+ hive_node_h parent_node;
+ if(!this->GetNodeHandle(parent_node_path,&parent_node)) {
+ return 0;
+ }
+
+ // Make sure key exists if we should update it
+ if(!create_key) {
+ hive_value_h temp_key=hivex_node_get_value(this->p_hive,
+ parent_node,
+ key_name.toLatin1().constData());
+ if(temp_key==0) {
+ this->SetError(tr("Inexisting key '%1\\%2' can't be updated!")
+ .arg(parent_node_path,key_name));
+ return 0;
+ }
+ }
+
+ // Create and populate hive_set_value structure
+ hive_set_value key_val;
+ key_val.key=(char*)malloc((sizeof(char)*key_name.toLatin1().count())+1);
+ key_val.value=(char*)malloc(sizeof(char)*key_value.size());
+ if(key_val.key==NULL || key_val.value==NULL) {
+ this->SetError(tr("Unable to alloc memory for hive_set_value struct!"));
+ return 0;
+ }
+ strcpy(key_val.key,key_name.toLatin1().constData());
+ key_val.t=(hive_type)this->StringToKeyValueType(key_value_type);
+ key_val.len=key_value.size();
+ memcpy(key_val.value,key_value.constData(),key_value.size());
+
+ // Create/Update key
+ if(hivex_node_set_value(this->p_hive,parent_node,&key_val,0)!=0) {
+ this->SetError(tr("Unable to update key '%1\\%2'!")
+ .arg(parent_node_path,key_name));
+ return 0;
+ }
+
+ // Free the hive_set_value structure
+ free(key_val.key);
+ free(key_val.value);
+
+ // To make sure everything worked, a hadle to the new key is now requeried
+ // from hive and then returned
+ hive_value_h key;
+ if(!this->GetKeyHandle(parent_node_path,key_name,&key)) {
+ return 0;
+ }
+
+ this->has_changes_to_commit=true;
+ return key;
+}
+
+/*
+ * FindUnicodeStringEnd
+ */
+int RegistryHive::FindUnicodeStringEnd(QByteArray data, int offset) {
+ int end_pos;
+ for(end_pos=offset;end_pos<(data.size()-1);end_pos+=2) {
+ if(*((quint16*)(data.constData()+end_pos))==0) break;
+ }
+ return end_pos<(data.size()-1) ? end_pos : -1;
+}
diff --git a/tags/fred-0.2.0/registryhive.h b/tags/fred-0.2.0/registryhive.h
new file mode 100644
index 0000000..a4aaed8
--- /dev/null
+++ b/tags/fred-0.2.0/registryhive.h
@@ -0,0 +1,136 @@
+/*******************************************************************************
+* fred Copyright (c) 2011-2020 by Gillen Daniel <gillen.dan@pinguin.lu> *
+* *
+* Forensic Registry EDitor (fred) is a cross-platform M$ registry hive editor *
+* with special feautures useful during forensic analysis. *
+* *
+* This program is free software: you can redistribute it and/or modify it *
+* under the terms of the GNU General Public License as published by the Free *
+* Software Foundation, either version 3 of the License, or (at your option) *
+* any later version. *
+* *
+* This program is distributed in the hope that it will be useful, but WITHOUT *
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or *
+* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for *
+* more details. *
+* *
+* You should have received a copy of the GNU General Public License along with *
+* this program. If not, see <http://www.gnu.org/licenses/>. *
+*******************************************************************************/
+
+#ifndef REGISTRYHIVE_H
+#define REGISTRYHIVE_H
+
+#include <QObject>
+#include <QMap>
+
+#ifndef HIVEX_STATIC
+ #include <hivex.h>
+#else
+ #include "hivex/lib/hivex.h"
+#endif
+
+class RegistryHive : public QObject {
+ Q_OBJECT
+
+ public:
+ typedef enum eHiveType {
+ eHiveType_UNKNOWN=0,
+ eHiveType_SYSTEM,
+ eHiveType_SOFTWARE,
+ eHiveType_SAM,
+ eHiveType_SECURITY,
+ eHiveType_NTUSER
+ } teHiveType;
+
+ explicit RegistryHive(QObject *p_parent=0);
+ ~RegistryHive();
+
+ bool Error();
+ QString GetErrorMsg();
+
+ bool Open(QString file, bool read_only=true);
+ bool Reopen(bool read_only=true);
+ bool CommitChanges();
+ bool Close();
+
+ QString Filename();
+ teHiveType HiveType();
+ QString HiveTypeToString(teHiveType hive_type);
+ bool HasChangesToCommit();
+
+ QMap<QString,int> GetNodes(QString path="\\");
+ QMap<QString,int> GetNodes(int parent_node=0);
+ QMap<QString,int> GetKeys(QString path="\\");
+ QMap<QString,int> GetKeys(int parent_node=0);
+ bool GetKeyName(int hive_key, QString &key_name);
+ QByteArray GetKeyValue(QString path,
+ QString key,
+ int *p_value_type,
+ size_t *p_value_len);
+ QByteArray GetKeyValue(int hive_key,
+ int *p_value_type,
+ size_t *p_value_len);
+ qint64 GetNodeModTime(QString path);
+ qint64 GetNodeModTime(int node);
+ static QString KeyValueToString(QByteArray value, int value_type);
+ static QString KeyValueToString(QByteArray value,
+ QString format,
+ int offset=0,
+ int length=-1,
+ bool little_endian=true);
+ static QStringList KeyValueToStringList(QByteArray value,
+ bool little_endian=true,
+ bool *p_ansi_encoded=NULL);
+ static QByteArray StringListToKeyValue(QStringList strings,
+ bool little_endian=true,
+ bool ansi_encoded=false);
+ static QStringList GetKeyValueTypes();
+ static QString KeyValueTypeToString(int value_type);
+ static int StringToKeyValueType(QString value_type);
+ static quint64 FiletimeToUnixtime(qint64 filetime);
+
+ int AddNode(QString parent_node_path, QString node_name);
+ bool DeleteNode(QString node_path);
+
+ int AddKey(QString parent_node_path,
+ QString key_name,
+ QString key_value_type,
+ QByteArray key_value);
+ int UpdateKey(QString parent_node_path,
+ QString key_name,
+ QString key_value_type,
+ QByteArray key_value);
+ bool DeleteKey(QString parent_node_path, QString key_name);
+
+ private:
+ QString erro_msg;
+ bool is_error;
+ QString hive_file;
+ hive_h *p_hive;
+ bool is_hive_open;
+ bool is_hive_writable;
+ bool has_changes_to_commit;
+
+ QString HivexError2String(int error);
+ void SetError(QString msg);
+ bool GetNodeHandle(QString &path, hive_node_h *p_node);
+ bool GetKeyHandle(QString &parent_node_path,
+ QString &key_name,
+ hive_value_h *p_key);
+ QMap<QString,int> GetNodesHelper(hive_node_h parent_node);
+ QMap<QString,int> GetKeysHelper(hive_node_h parent_node);
+ QByteArray GetKeyValueHelper(hive_value_h hive_key,
+ int *p_value_type,
+ size_t *p_value_len);
+ bool PathExists(QString path);
+ int SetKey(QString &parent_node_path,
+ QString &key_name,
+ QString &key_value_type,
+ QByteArray &key_value,
+ bool create_key);
+ static int FindUnicodeStringEnd(QByteArray data, int offset=0);
+
+};
+
+#endif // REGISTRYHIVE_H
diff --git a/tags/fred-0.2.0/registrykey.cpp b/tags/fred-0.2.0/registrykey.cpp
new file mode 100644
index 0000000..87138c5
--- /dev/null
+++ b/tags/fred-0.2.0/registrykey.cpp
@@ -0,0 +1,63 @@
+/*******************************************************************************
+* fred Copyright (c) 2011-2020 by Gillen Daniel <gillen.dan@pinguin.lu> *
+* *
+* Forensic Registry EDitor (fred) is a cross-platform M$ registry hive editor *
+* with special feautures useful during forensic analysis. *
+* *
+* This program is free software: you can redistribute it and/or modify it *
+* under the terms of the GNU General Public License as published by the Free *
+* Software Foundation, either version 3 of the License, or (at your option) *
+* any later version. *
+* *
+* This program is distributed in the hope that it will be useful, but WITHOUT *
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or *
+* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for *
+* more details. *
+* *
+* You should have received a copy of the GNU General Public License along with *
+* this program. If not, see <http://www.gnu.org/licenses/>. *
+*******************************************************************************/
+
+#include "registrykey.h"
+
+RegistryKey::RegistryKey(const QList<QVariant> &data) {
+ this->key_data=data;
+}
+
+RegistryKey::~RegistryKey() {
+ qDeleteAll(this->keys);
+}
+
+void RegistryKey::Append(RegistryKey *p_key) {
+ this->keys.append(p_key);
+}
+
+void RegistryKey::SetData(const QList<QVariant> &data) {
+ this->key_data=data;
+}
+
+void RegistryKey::Remove(quint64 row) {
+ RegistryKey *p_key=this->keys.takeAt(row);
+ delete p_key;
+}
+
+RegistryKey* RegistryKey::Key(quint64 row) {
+ return this->keys.value(row);
+}
+
+quint64 RegistryKey::RowCount() {
+ return this->keys.count();
+}
+
+QVariant RegistryKey::Data(int column) const {
+ if(column>=0 && column<3) {
+ return this->key_data.value(column);
+ } else {
+ return QVariant();
+ }
+}
+
+quint64 RegistryKey::Row() const {
+ return this->keys.indexOf(const_cast<RegistryKey*>(this));
+}
+
diff --git a/tags/fred-0.2.0/registrykey.h b/tags/fred-0.2.0/registrykey.h
new file mode 100644
index 0000000..0a59cd3
--- /dev/null
+++ b/tags/fred-0.2.0/registrykey.h
@@ -0,0 +1,45 @@
+/*******************************************************************************
+* fred Copyright (c) 2011-2020 by Gillen Daniel <gillen.dan@pinguin.lu> *
+* *
+* Forensic Registry EDitor (fred) is a cross-platform M$ registry hive editor *
+* with special feautures useful during forensic analysis. *
+* *
+* This program is free software: you can redistribute it and/or modify it *
+* under the terms of the GNU General Public License as published by the Free *
+* Software Foundation, either version 3 of the License, or (at your option) *
+* any later version. *
+* *
+* This program is distributed in the hope that it will be useful, but WITHOUT *
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or *
+* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for *
+* more details. *
+* *
+* You should have received a copy of the GNU General Public License along with *
+* this program. If not, see <http://www.gnu.org/licenses/>. *
+*******************************************************************************/
+
+#ifndef REGISTRYKEY_H
+#define REGISTRYKEY_H
+
+#include <QList>
+#include <QVariant>
+
+class RegistryKey {
+ public:
+ RegistryKey(const QList<QVariant> &data);
+ ~RegistryKey();
+
+ void Append(RegistryKey *p_key);
+ void SetData(const QList<QVariant> &data);
+ void Remove(quint64 row);
+ RegistryKey *Key(quint64 row);
+ quint64 RowCount();
+ QVariant Data(int column) const;
+ quint64 Row() const;
+
+ private:
+ QList<RegistryKey*> keys;
+ QList<QVariant> key_data;
+};
+
+#endif // REGISTRYKEY_H
diff --git a/tags/fred-0.2.0/registrykeytable.cpp b/tags/fred-0.2.0/registrykeytable.cpp
new file mode 100644
index 0000000..2836bc2
--- /dev/null
+++ b/tags/fred-0.2.0/registrykeytable.cpp
@@ -0,0 +1,213 @@
+/*******************************************************************************
+* fred Copyright (c) 2011-2020 by Gillen Daniel <gillen.dan@pinguin.lu> *
+* *
+* Forensic Registry EDitor (fred) is a cross-platform M$ registry hive editor *
+* with special feautures useful during forensic analysis. *
+* *
+* This program is free software: you can redistribute it and/or modify it *
+* under the terms of the GNU General Public License as published by the Free *
+* Software Foundation, either version 3 of the License, or (at your option) *
+* any later version. *
+* *
+* This program is distributed in the hope that it will be useful, but WITHOUT *
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or *
+* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for *
+* more details. *
+* *
+* You should have received a copy of the GNU General Public License along with *
+* this program. If not, see <http://www.gnu.org/licenses/>. *
+*******************************************************************************/
+
+#include <QHeaderView>
+#include <QApplication>
+#include <QClipboard>
+
+#include "registrykeytable.h"
+
+/*******************************************************************************
+ * Public
+ ******************************************************************************/
+
+RegistryKeyTable::RegistryKeyTable(QWidget *p_parent) : QTableView(p_parent) {
+ this->is_writable=false;
+
+ // Configure widget
+ this->setSelectionMode(QAbstractItemView::SingleSelection);
+ this->setSelectionBehavior(QAbstractItemView::SelectRows);
+ this->setAutoScroll(false);
+ this->setHorizontalScrollMode(QAbstractItemView::ScrollPerPixel);
+ this->verticalHeader()->setHidden(true);
+ this->setTextElideMode(Qt::ElideNone);
+
+ // Create context menu item
+ this->p_action_add_key=new QAction(tr("Add new key"),this);
+ this->p_action_edit_key=new QAction(tr("Edit selected key"),this);
+ this->p_action_delete_key=new QAction(tr("Delete selected key"),this);
+ this->p_menu_copy=new QMenu(tr("Copy"),this);
+ this->p_action_copy_key_name=
+ new QAction(tr("Selected key name"),this->p_menu_copy);
+ this->p_menu_copy->addAction(this->p_action_copy_key_name);
+ this->p_action_copy_key_value=
+ new QAction(tr("Selected key value"),this->p_menu_copy);
+ this->p_menu_copy->addAction(this->p_action_copy_key_value);
+
+ // Connect context menu signals
+ this->connect(this->p_action_add_key,
+ SIGNAL(triggered()),
+ this,
+ SLOT(SlotAddKey()));
+ this->connect(this->p_action_edit_key,
+ SIGNAL(triggered()),
+ this,
+ SLOT(SlotEditKey()));
+ this->connect(this->p_action_delete_key,
+ SIGNAL(triggered()),
+ this,
+ SLOT(SlotDeleteKey()));
+ this->connect(this->p_action_copy_key_name,
+ SIGNAL(triggered()),
+ this,
+ SLOT(SlotCopyKeyName()));
+ this->connect(this->p_action_copy_key_value,
+ SIGNAL(triggered()),
+ this,
+ SLOT(SlotCopyKeyValue()));
+}
+
+RegistryKeyTable::~RegistryKeyTable() {
+ // Delete context menu
+ delete this->p_action_copy_key_name;
+ delete this->p_action_copy_key_value;
+ delete this->p_menu_copy;
+ delete this->p_action_delete_key;
+ delete this->p_action_edit_key;
+ delete this->p_action_add_key;
+}
+
+void RegistryKeyTable::setModel(QAbstractItemModel *p_model, bool writable) {
+ QTableView::setModel(p_model);
+ // Resize table rows / columns to fit data
+ this->resizeColumnsToContents();
+ this->resizeRowsToContents();
+ this->horizontalHeader()->stretchLastSection();
+ if(p_model!=NULL && p_model->rowCount()>0) {
+ // Select first table item
+ this->selectRow(0);
+ }
+
+ // Set writable status
+ this->SetWritable(writable);
+}
+
+void RegistryKeyTable::SetWritable(bool writable) {
+ this->is_writable=writable;
+ this->p_action_add_key->setEnabled(this->is_writable);
+ this->p_action_edit_key->setEnabled(this->is_writable);
+ this->p_action_delete_key->setEnabled(this->is_writable);
+}
+
+/*
+void RegistryKeyTable::selectRow(QString key_name) {
+ int i;
+
+ this->clearSelection();
+ for(i=0;i<this->model()->rowCount();i++) {
+ if(this->model())
+ }
+}
+*/
+
+/*******************************************************************************
+ * Protected
+ ******************************************************************************/
+
+int RegistryKeyTable::sizeHintForColumn(int column) const {
+ int size_hint=-1;
+ int i=0;
+ int item_width=0;
+ QFontMetrics fm(this->fontMetrics());
+ QModelIndex idx;
+
+ if(this->model()==NULL) return -1;
+
+ // Find string that needs the most amount of space
+ idx=this->model()->index(i,column);
+ while(idx.isValid()) {
+ item_width=fm.width(this->model()->data(idx).toString())+10;
+ if(item_width>size_hint) size_hint=item_width;
+ idx=this->model()->index(++i,column);
+ }
+
+ return size_hint;
+}
+
+void RegistryKeyTable::contextMenuEvent(QContextMenuEvent *p_event) {
+ // Only show context menu if a hive is open (a model was set)
+ if(this->model()==NULL) return;
+
+ // Decide what menus should be enabled
+ if(this->selectedIndexes().count()==3) {
+ // A row is selected, enable full context menu
+ this->p_action_add_key->setEnabled(this->is_writable);
+ this->p_action_edit_key->setEnabled(this->is_writable);
+ this->p_action_delete_key->setEnabled(this->is_writable);
+ this->p_menu_copy->setEnabled(true);
+ } else {
+ // No row is selected, disable all menu items except AddKey
+ this->p_action_add_key->setEnabled(this->is_writable);
+ this->p_action_edit_key->setEnabled(false);
+ this->p_action_delete_key->setEnabled(false);
+ this->p_menu_copy->setEnabled(false);
+ }
+
+ // Emit clicked signal (makes sure item under cursor is selected if it wasn't)
+ emit(this->clicked(this->indexAt(p_event->pos())));
+
+ // Create context menu, add actions and show it
+ QMenu context_menu(this);
+ context_menu.addAction(this->p_action_add_key);
+ context_menu.addAction(this->p_action_edit_key);
+ context_menu.addAction(this->p_action_delete_key);
+ context_menu.addSeparator();
+ context_menu.addMenu(this->p_menu_copy);
+ context_menu.exec(p_event->globalPos());
+}
+
+void RegistryKeyTable::currentChanged(const QModelIndex &current,
+ const QModelIndex &previous)
+{
+ // Call parent class's currentChanged first
+ QTableView::currentChanged(current,previous);
+
+ // Now emit our signal
+ QModelIndex current_item=QModelIndex(current);
+ emit(RegistryKeyTable::CurrentItemChanged(current_item));
+}
+
+/*******************************************************************************
+ * Private slots
+ ******************************************************************************/
+
+void RegistryKeyTable::SlotAddKey() {
+ emit(this->SignalAddKey());
+}
+
+void RegistryKeyTable::SlotEditKey() {
+ emit(this->SignalEditKey(this->selectedIndexes().at(0)));
+}
+
+void RegistryKeyTable::SlotDeleteKey() {
+ emit(this->SignalDeleteKey(this->selectedIndexes().at(0)));
+}
+
+void RegistryKeyTable::SlotCopyKeyName() {
+ QApplication::clipboard()->
+ setText(this->selectedIndexes().at(0).data().toString(),
+ QClipboard::Clipboard);
+}
+
+void RegistryKeyTable::SlotCopyKeyValue() {
+ QApplication::clipboard()->
+ setText(this->selectedIndexes().at(2).data().toString(),
+ QClipboard::Clipboard);
+}
diff --git a/tags/fred-0.2.0/registrykeytable.h b/tags/fred-0.2.0/registrykeytable.h
new file mode 100644
index 0000000..7436358
--- /dev/null
+++ b/tags/fred-0.2.0/registrykeytable.h
@@ -0,0 +1,69 @@
+/*******************************************************************************
+* fred Copyright (c) 2011-2020 by Gillen Daniel <gillen.dan@pinguin.lu> *
+* *
+* Forensic Registry EDitor (fred) is a cross-platform M$ registry hive editor *
+* with special feautures useful during forensic analysis. *
+* *
+* This program is free software: you can redistribute it and/or modify it *
+* under the terms of the GNU General Public License as published by the Free *
+* Software Foundation, either version 3 of the License, or (at your option) *
+* any later version. *
+* *
+* This program is distributed in the hope that it will be useful, but WITHOUT *
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or *
+* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for *
+* more details. *
+* *
+* You should have received a copy of the GNU General Public License along with *
+* this program. If not, see <http://www.gnu.org/licenses/>. *
+*******************************************************************************/
+
+#ifndef REGISTRYKEYTABLE_H
+#define REGISTRYKEYTABLE_H
+
+#include <QTableView>
+#include <QContextMenuEvent>
+#include <QMenu>
+#include <QAction>
+
+class RegistryKeyTable : public QTableView {
+ Q_OBJECT
+
+ public:
+ RegistryKeyTable(QWidget *p_parent=0);
+ ~RegistryKeyTable();
+
+ void setModel(QAbstractItemModel *p_model, bool writable=false);
+ void SetWritable(bool writable);
+ //void selectRow(QString key_name);
+
+ Q_SIGNALS:
+ void CurrentItemChanged(QModelIndex current);
+ void SignalAddKey();
+ void SignalEditKey(QModelIndex node);
+ void SignalDeleteKey(QModelIndex node);
+
+ protected:
+ int sizeHintForColumn(int column) const;
+ void contextMenuEvent(QContextMenuEvent *p_event);
+ void currentChanged(const QModelIndex &current,
+ const QModelIndex &previous);
+
+ private:
+ bool is_writable;
+ QAction *p_action_add_key;
+ QAction *p_action_edit_key;
+ QAction *p_action_delete_key;
+ QMenu *p_menu_copy;
+ QAction *p_action_copy_key_name;
+ QAction *p_action_copy_key_value;
+
+ private slots:
+ void SlotAddKey();
+ void SlotEditKey();
+ void SlotDeleteKey();
+ void SlotCopyKeyName();
+ void SlotCopyKeyValue();
+};
+
+#endif // REGISTRYKEYTABLE_H
diff --git a/tags/fred-0.2.0/registrykeytablemodel.cpp b/tags/fred-0.2.0/registrykeytablemodel.cpp
new file mode 100644
index 0000000..b63d427
--- /dev/null
+++ b/tags/fred-0.2.0/registrykeytablemodel.cpp
@@ -0,0 +1,286 @@
+/*******************************************************************************
+* fred Copyright (c) 2011-2020 by Gillen Daniel <gillen.dan@pinguin.lu> *
+* *
+* Forensic Registry EDitor (fred) is a cross-platform M$ registry hive editor *
+* with special feautures useful during forensic analysis. *
+* *
+* This program is free software: you can redistribute it and/or modify it *
+* under the terms of the GNU General Public License as published by the Free *
+* Software Foundation, either version 3 of the License, or (at your option) *
+* any later version. *
+* *
+* This program is distributed in the hope that it will be useful, but WITHOUT *
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or *
+* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for *
+* more details. *
+* *
+* You should have received a copy of the GNU General Public License along with *
+* this program. If not, see <http://www.gnu.org/licenses/>. *
+*******************************************************************************/
+
+#include "registrykeytablemodel.h"
+
+/*******************************************************************************
+ * Public
+ ******************************************************************************/
+
+RegistryKeyTableModel::RegistryKeyTableModel(RegistryHive *p_hive,
+ QString node_path,
+ QObject *p_parent)
+ : QAbstractTableModel(p_parent)
+{
+ // Create the "root" key. It's values will be used as header values.
+ this->p_keys=new RegistryKey(QList<QVariant>()<<
+ tr("Key")<<
+ tr("Type")<<
+ tr("Value"));
+ // Build key list
+ this->SetupModelData(p_hive,node_path);
+}
+
+RegistryKeyTableModel::~RegistryKeyTableModel() {
+ delete this->p_keys;
+}
+
+QVariant RegistryKeyTableModel::data(const QModelIndex &index, int role) const {
+ bool ok;
+
+ if(!index.isValid()) return QVariant();
+
+ RegistryKey *p_key=static_cast<RegistryKey*>(index.internalPointer());
+
+ switch(role) {
+ case Qt::DisplayRole: {
+ switch(index.column()) {
+ case RegistryKeyTableModel::ColumnContent_KeyName: {
+ return p_key->Data(index.column());
+ break;
+ }
+ case RegistryKeyTableModel::ColumnContent_KeyType: {
+ int value_type=p_key->Data(index.column()).toInt(&ok);
+ if(!ok) return QVariant();
+ return RegistryHive::KeyValueTypeToString(value_type);
+ break;
+ }
+ case RegistryKeyTableModel::ColumnContent_KeyValue: {
+ // Get index to value type
+ QModelIndex type_index=this->index(index.row(),
+ RegistryKeyTableModel::
+ ColumnContent_KeyType);
+ // Get value type
+ int value_type=this->data(type_index,
+ RegistryKeyTableModel::
+ AdditionalRoles_GetRawData).toInt(&ok);
+ if(!ok) return QVariant();
+ // Return value converted to human readeable string
+ QByteArray value_array=p_key->Data(index.column()).toByteArray();
+ return RegistryHive::KeyValueToString(value_array,value_type);
+ break;
+ }
+ default:
+ return QVariant();
+ }
+ break;
+ }
+ case RegistryKeyTableModel::AdditionalRoles_GetRawData: {
+ return p_key->Data(index.column());
+ break;
+ }
+ default:
+ return QVariant();
+ }
+ return QVariant();
+}
+
+Qt::ItemFlags RegistryKeyTableModel::flags(const QModelIndex &index) const {
+ if(!index.isValid()) return 0;
+
+ return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
+}
+
+QVariant RegistryKeyTableModel::headerData(int section,
+ Qt::Orientation orientation,
+ int role) const
+{
+ // Only horizontal header is supported
+ if(orientation!=Qt::Horizontal) return QVariant();
+
+ switch(role) {
+ case Qt::TextAlignmentRole:
+ // Handle text alignment
+ if(section==2) return Qt::AlignLeft;
+ else return Qt::AlignCenter;
+ break;
+ case Qt::DisplayRole:
+ // Header text
+ return this->p_keys->Data(section);
+ break;
+ default:
+ return QVariant();
+ }
+}
+
+QModelIndex RegistryKeyTableModel::index(int row,
+ int column,
+ const QModelIndex &parent) const
+{
+ if(!this->hasIndex(row,column,parent)) return QModelIndex();
+
+ RegistryKey *p_key=this->p_keys->Key(row);
+
+ return this->createIndex(row,column,p_key);
+}
+
+int RegistryKeyTableModel::rowCount(const QModelIndex &parent) const {
+ // According to Qt doc, when parent in TableModel is valid, we should return 0
+ if(parent.isValid()) return 0;
+ // Get and return row count from the keys list
+ return this->p_keys->RowCount();
+}
+
+int RegistryKeyTableModel::columnCount(const QModelIndex &parent) const {
+ // According to Qt doc, when parent in TableModel is valid, we should return 0
+ if(parent.isValid()) return 0;
+ // There are always 3 columns
+ return 3;
+}
+
+int RegistryKeyTableModel::GetKeyRow(QString key_name) const {
+ int i;
+
+ for(i=0;i<this->p_keys->RowCount();i++) {
+ if(this->p_keys->Key(i)->Data(0)==key_name) {
+ return i;
+ }
+ }
+
+ // When key isn't found, return the first row
+ return 0;
+}
+
+QModelIndex RegistryKeyTableModel::AddKey(RegistryHive *p_hive,
+ int new_key_id)
+{
+ RegistryKey *p_key;
+ QString key_name;
+ QByteArray key_value;
+ int key_value_type;
+ size_t key_value_len;
+
+ // Tell users of this model that we are going to add a row
+ emit(RegistryKeyTableModel::beginInsertRows(QModelIndex(),
+ this->p_keys->RowCount(),
+ this->p_keys->RowCount()));
+
+ // Get key name
+ if(!p_hive->GetKeyName(new_key_id,key_name)) {
+ return QModelIndex();
+ }
+ // Get key value, value type and value length
+ key_value=p_hive->GetKeyValue(new_key_id,&key_value_type,&key_value_len);
+ if(p_hive->GetErrorMsg()!="") {
+ return QModelIndex();
+ }
+ // Create new RegistryKey object and add it to our internal list
+ p_key=new RegistryKey(QList<QVariant>()<<
+ QString(key_name.length() ? key_name : "(default)")<<
+ QVariant(key_value_type)<<
+ key_value);
+ this->p_keys->Append(p_key);
+
+ // Tell users of this model we have finished adding a row
+ emit(RegistryKeyTableModel::endInsertRows());
+
+ // Return an index to the new row
+ return this->index(this->p_keys->RowCount()-1,0);
+}
+
+QModelIndex RegistryKeyTableModel::UpdateKey(RegistryHive *p_hive,
+ int new_key_id)
+{
+ QString key_name;
+ QByteArray key_value;
+ int key_value_type;
+ size_t key_value_len;
+ int key_row=-1;
+
+ // Get key name
+ if(!p_hive->GetKeyName(new_key_id,key_name)) {
+ return QModelIndex();
+ }
+ // Get key value, value type and value length
+ key_value=p_hive->GetKeyValue(new_key_id,&key_value_type,&key_value_len);
+ if(p_hive->GetErrorMsg()!="") {
+ return QModelIndex();
+ }
+
+ // Find row containig the key to update
+ for(int i=0;i<this->p_keys->RowCount();i++) {
+ if(this->p_keys->Key(i)->Data(0).toString().toLower()==key_name.toLower()) {
+ key_row=i;
+ }
+ }
+ if(key_row==-1) return QModelIndex();
+
+ // Update values
+ this->p_keys->Key(key_row)->SetData(QList<QVariant>()<<
+ QString(key_name.length() ?
+ key_name : "(default)")<<
+ QVariant(key_value_type)<<
+ key_value);
+
+ // Tell users of this model that data has changed
+ emit(RegistryKeyTableModel::dataChanged(this->index(key_row,0),
+ this->index(key_row,0)));
+
+ return this->index(key_row,0);
+}
+
+QModelIndex RegistryKeyTableModel::RemoveKey(const QModelIndex &index) {
+ // Tell users of this model that a row is going to be removed
+ emit(RegistryKeyTableModel::beginRemoveRows(QModelIndex(),
+ index.row(),
+ index.row()));
+ // Remove row
+ this->p_keys->Remove(index.row());
+ // Tell users of this model that a row has been removed
+ emit(RegistryKeyTableModel::endRemoveRows());
+ // Return a valid index to be selected
+ if(this->rowCount()==0) return QModelIndex();
+ else if(index.row()==0) return this->index(0,0);
+ else if(index.row()<this->rowCount()) return this->index(index.row(),0);
+ else return this->index(index.row()-1,0);
+}
+
+/*******************************************************************************
+ * Private
+ ******************************************************************************/
+
+void RegistryKeyTableModel::SetupModelData(RegistryHive *p_hive,
+ QString &node_path)
+{
+ QMap<QString,int> node_keys;
+ RegistryKey *p_key;
+ QByteArray key_value;
+ int key_value_type;
+ size_t key_value_len;
+
+ // Get all keys for current node
+ node_keys=p_hive->GetKeys(node_path);
+ if(node_keys.isEmpty()) return;
+
+ // Add all keys to list
+ QMapIterator<QString,int> i(node_keys);
+ while(i.hasNext()) {
+ i.next();
+ key_value=p_hive->GetKeyValue(i.value(),
+ &key_value_type,
+ &key_value_len);
+ if(p_hive->GetErrorMsg()!="") continue;
+ p_key=new RegistryKey(QList<QVariant>()<<
+ QString(i.key().length() ? i.key() : tr("(default)"))<<
+ QVariant(key_value_type)<<
+ key_value);
+ this->p_keys->Append(p_key);
+ }
+}
diff --git a/tags/fred-0.2.0/registrykeytablemodel.h b/tags/fred-0.2.0/registrykeytablemodel.h
new file mode 100644
index 0000000..163a4ee
--- /dev/null
+++ b/tags/fred-0.2.0/registrykeytablemodel.h
@@ -0,0 +1,70 @@
+/*******************************************************************************
+* fred Copyright (c) 2011-2020 by Gillen Daniel <gillen.dan@pinguin.lu> *
+* *
+* Forensic Registry EDitor (fred) is a cross-platform M$ registry hive editor *
+* with special feautures useful during forensic analysis. *
+* *
+* This program is free software: you can redistribute it and/or modify it *
+* under the terms of the GNU General Public License as published by the Free *
+* Software Foundation, either version 3 of the License, or (at your option) *
+* any later version. *
+* *
+* This program is distributed in the hope that it will be useful, but WITHOUT *
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or *
+* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for *
+* more details. *
+* *
+* You should have received a copy of the GNU General Public License along with *
+* this program. If not, see <http://www.gnu.org/licenses/>. *
+*******************************************************************************/
+
+#ifndef REGISTRYKEYTABLEMODEL_H
+#define REGISTRYKEYTABLEMODEL_H
+
+#include <QAbstractTableModel>
+
+#include "registrykey.h"
+#include "registryhive.h"
+
+class RegistryKeyTableModel : public QAbstractTableModel {
+ Q_OBJECT
+
+ public:
+ enum ColumnContent {
+ ColumnContent_KeyName=0,
+ ColumnContent_KeyType,
+ ColumnContent_KeyValue
+ };
+
+ enum AdditionalRoles {
+ AdditionalRoles_GetRawData=Qt::UserRole
+ };
+
+ RegistryKeyTableModel(RegistryHive *p_hive,
+ QString node_path,
+ QObject *p_parent=0);
+ ~RegistryKeyTableModel();
+
+ QVariant data(const QModelIndex &index, int role) const;
+ Qt::ItemFlags flags(const QModelIndex &index) const;
+ QVariant headerData(int section,
+ Qt::Orientation orientation,
+ int role=Qt::DisplayRole) const;
+ QModelIndex index(int row,
+ int column,
+ const QModelIndex &parent=QModelIndex()) const;
+ int rowCount(const QModelIndex &parent=QModelIndex()) const;
+ int columnCount(const QModelIndex &parent=QModelIndex()) const;
+
+ int GetKeyRow(QString key_name) const;
+ QModelIndex AddKey(RegistryHive *p_hive, int new_key_id);
+ QModelIndex UpdateKey(RegistryHive *p_hive, int new_key_id);
+ QModelIndex RemoveKey(const QModelIndex &index);
+
+ private:
+ RegistryKey *p_keys;
+
+ void SetupModelData(RegistryHive *p_hive, QString &node_path);
+};
+
+#endif // REGISTRYKEYTABLEMODEL_H
diff --git a/tags/fred-0.2.0/registrynode.cpp b/tags/fred-0.2.0/registrynode.cpp
new file mode 100644
index 0000000..e90b92e
--- /dev/null
+++ b/tags/fred-0.2.0/registrynode.cpp
@@ -0,0 +1,74 @@
+/*******************************************************************************
+* fred Copyright (c) 2011-2020 by Gillen Daniel <gillen.dan@pinguin.lu> *
+* *
+* Forensic Registry EDitor (fred) is a cross-platform M$ registry hive editor *
+* with special feautures useful during forensic analysis. *
+* *
+* This program is free software: you can redistribute it and/or modify it *
+* under the terms of the GNU General Public License as published by the Free *
+* Software Foundation, either version 3 of the License, or (at your option) *
+* any later version. *
+* *
+* This program is distributed in the hope that it will be useful, but WITHOUT *
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or *
+* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for *
+* more details. *
+* *
+* You should have received a copy of the GNU General Public License along with *
+* this program. If not, see <http://www.gnu.org/licenses/>. *
+*******************************************************************************/
+
+#include "registrynode.h"
+
+RegistryNode::RegistryNode(const QList<QVariant> &data,
+ RegistryNode *p_parent)
+{
+ this->node_data=data;
+ this->p_parent_node=p_parent;
+}
+
+RegistryNode::~RegistryNode() {
+ qDeleteAll(this->child_nodes);
+}
+
+void RegistryNode::AppendChild(RegistryNode *p_child) {
+ this->child_nodes.append(p_child);
+}
+
+void RegistryNode::RemoveChild(quint64 row) {
+ if(row>=this->child_nodes.count()) return;
+
+ // Remove child from list and delete it (Will also delete all sub-nodes)
+ RegistryNode *p_child;
+ p_child=this->child_nodes.takeAt(row);
+ delete p_child;
+}
+
+RegistryNode* RegistryNode::Child(quint64 row) {
+ return this->child_nodes.value(row);
+}
+
+quint64 RegistryNode::ChildCount() const {
+ return this->child_nodes.count();
+}
+
+QVariant RegistryNode::Data(int column) const {
+ if(column>=0 && column<2) {
+ return this->node_data.value(column);
+ } else {
+ return QVariant();
+ }
+}
+
+quint64 RegistryNode::Row() const {
+ if(this->p_parent_node) {
+ return this->p_parent_node->
+ child_nodes.indexOf(const_cast<RegistryNode*>(this));
+ } else {
+ return 0;
+ }
+}
+
+RegistryNode *RegistryNode::Parent() {
+ return this->p_parent_node;
+}
diff --git a/tags/fred-0.2.0/registrynode.h b/tags/fred-0.2.0/registrynode.h
new file mode 100644
index 0000000..7eb0124
--- /dev/null
+++ b/tags/fred-0.2.0/registrynode.h
@@ -0,0 +1,47 @@
+/*******************************************************************************
+* fred Copyright (c) 2011-2020 by Gillen Daniel <gillen.dan@pinguin.lu> *
+* *
+* Forensic Registry EDitor (fred) is a cross-platform M$ registry hive editor *
+* with special feautures useful during forensic analysis. *
+* *
+* This program is free software: you can redistribute it and/or modify it *
+* under the terms of the GNU General Public License as published by the Free *
+* Software Foundation, either version 3 of the License, or (at your option) *
+* any later version. *
+* *
+* This program is distributed in the hope that it will be useful, but WITHOUT *
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or *
+* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for *
+* more details. *
+* *
+* You should have received a copy of the GNU General Public License along with *
+* this program. If not, see <http://www.gnu.org/licenses/>. *
+*******************************************************************************/
+
+#ifndef REGISTRYNODE_H
+#define REGISTRYNODE_H
+
+#include <QList>
+#include <QVariant>
+
+class RegistryNode {
+ public:
+ RegistryNode(const QList<QVariant> &data,
+ RegistryNode *p_parent=0);
+ ~RegistryNode();
+
+ void AppendChild(RegistryNode *p_child);
+ void RemoveChild(quint64 row);
+ RegistryNode *Child(quint64 row);
+ quint64 ChildCount() const;
+ QVariant Data(int column) const;
+ quint64 Row() const;
+ RegistryNode *Parent();
+
+ private:
+ QList<RegistryNode*> child_nodes;
+ QList<QVariant> node_data;
+ RegistryNode *p_parent_node;
+};
+
+#endif // REGISTRYNODE_H
diff --git a/tags/fred-0.2.0/registrynodetree.cpp b/tags/fred-0.2.0/registrynodetree.cpp
new file mode 100644
index 0000000..af9adc1
--- /dev/null
+++ b/tags/fred-0.2.0/registrynodetree.cpp
@@ -0,0 +1,185 @@
+/*******************************************************************************
+* fred Copyright (c) 2011-2020 by Gillen Daniel <gillen.dan@pinguin.lu> *
+* *
+* Forensic Registry EDitor (fred) is a cross-platform M$ registry hive editor *
+* with special feautures useful during forensic analysis. *
+* *
+* This program is free software: you can redistribute it and/or modify it *
+* under the terms of the GNU General Public License as published by the Free *
+* Software Foundation, either version 3 of the License, or (at your option) *
+* any later version. *
+* *
+* This program is distributed in the hope that it will be useful, but WITHOUT *
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or *
+* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for *
+* more details. *
+* *
+* You should have received a copy of the GNU General Public License along with *
+* this program. If not, see <http://www.gnu.org/licenses/>. *
+*******************************************************************************/
+
+#include <QHeaderView>
+#include <QApplication>
+#include <QClipboard>
+
+#include <QDebug>
+
+#include "registrynodetree.h"
+#include "registrynodetreemodel.h"
+
+/*******************************************************************************
+ * Public
+ ******************************************************************************/
+
+RegistryNodeTree::RegistryNodeTree(QWidget *p_parent) : QTreeView(p_parent) {
+ this->is_writable=false;
+
+ // Configure widget
+ this->setTextElideMode(Qt::ElideNone);
+ this->setSelectionMode(QAbstractItemView::SingleSelection);
+ this->setSelectionBehavior(QAbstractItemView::SelectRows);
+ this->sortByColumn(0,Qt::AscendingOrder);
+ this->setSortingEnabled(true);
+
+ // Create context menu items
+ this->p_action_add_node=new QAction(tr("Add new node"),this);
+ this->p_action_delete_node=new QAction(tr("Delete selected node"),this);
+ this->p_menu_copy=new QMenu(tr("Copy"),this);
+ this->p_action_copy_node_name=
+ new QAction(tr("Selected node name"),this->p_menu_copy);
+ this->p_menu_copy->addAction(this->p_action_copy_node_name);
+ this->p_action_copy_node_path=
+ new QAction(tr("Selected node path"),this->p_menu_copy);
+ this->p_menu_copy->addAction(this->p_action_copy_node_path);
+
+ // Connect context menu signals
+ this->connect(this->p_action_add_node,
+ SIGNAL(triggered()),
+ this,
+ SLOT(SlotAddNode()));
+ this->connect(this->p_action_delete_node,
+ SIGNAL(triggered()),
+ this,
+ SLOT(SlotDeleteNode()));
+ this->connect(this->p_action_copy_node_name,
+ SIGNAL(triggered()),
+ this,
+ SLOT(SlotCopyNodeName()));
+ this->connect(this->p_action_copy_node_path,
+ SIGNAL(triggered()),
+ this,
+ SLOT(SlotCopyNodePath()));
+}
+
+RegistryNodeTree::~RegistryNodeTree() {
+ // Delete context menu
+ delete this->p_action_copy_node_name;
+ delete this->p_action_copy_node_path;
+ delete this->p_menu_copy;
+ delete this->p_action_delete_node;
+ delete this->p_action_add_node;
+}
+
+void RegistryNodeTree::setModel(QAbstractItemModel *p_model, bool writable) {
+ // Assign model to view
+ QTreeView::setModel(p_model);
+
+ this->header()->setSectionResizeMode(QHeaderView::ResizeToContents);
+ this->header()->setStretchLastSection(true);
+ if(p_model!=NULL && p_model->index(0,0).isValid()) {
+ // Select first tree item
+ this->setCurrentIndex(p_model->index(0,0));
+ }
+
+ // Set writable status
+ this->SetWritable(writable);
+}
+
+void RegistryNodeTree::SetWritable(bool writable) {
+ this->is_writable=writable;
+ this->p_action_add_node->setEnabled(this->is_writable);
+ this->p_action_delete_node->setEnabled(this->is_writable);
+}
+
+/*******************************************************************************
+ * Protected
+ ******************************************************************************/
+
+void RegistryNodeTree::contextMenuEvent(QContextMenuEvent *p_event) {
+ // Only show context menu when a node is selected
+ if(this->selectedIndexes().count()!=2) return;
+ // Only show context menu when user clicked on selected row
+ if(this->indexAt(p_event->pos()).row()!=this->selectedIndexes().at(0).row())
+ return;
+
+ // Emit a click signal
+ emit(this->clicked(this->indexAt(p_event->pos())));
+
+ // Create context menu and add actions
+ QMenu context_menu(this);
+ context_menu.addAction(this->p_action_add_node);
+ context_menu.addAction(this->p_action_delete_node);
+ context_menu.addSeparator();
+ context_menu.addMenu(this->p_menu_copy);
+ context_menu.exec(p_event->globalPos());
+}
+
+void RegistryNodeTree::keyPressEvent(QKeyEvent *p_event) {
+ // Only react if a node is selected and user pressed Key_Left
+ if(this->selectedIndexes().count()==2 &&
+ p_event->key()==Qt::Key_Left)
+ {
+ QModelIndex cur_index=this->selectedIndexes().at(0);
+
+ if(this->model()->hasChildren(cur_index) && this->isExpanded(cur_index)) {
+ // Current node is expanded. Only collapse this one
+ this->collapse(cur_index);
+ return;
+ }
+ if(!cur_index.parent().isValid()) {
+ // Do no try to collapse anything above root node
+ return;
+ }
+ this->collapse(cur_index.parent());
+ this->setCurrentIndex(cur_index.parent());
+ return;
+ }
+
+ // If we didn't handle the key event, let our parent handle it
+ QTreeView::keyPressEvent(p_event);
+}
+
+void RegistryNodeTree::currentChanged(const QModelIndex &current,
+ const QModelIndex &previous)
+{
+ // Call parent class's currentChanged first
+ QTreeView::currentChanged(current,previous);
+
+ // Now emit our signal
+ QModelIndex current_item=QModelIndex(current);
+ emit(RegistryNodeTree::CurrentItemChanged(current_item));
+}
+
+/*******************************************************************************
+ * Private slots
+ ******************************************************************************/
+
+void RegistryNodeTree::SlotAddNode() {
+ emit(RegistryNodeTree::SignalAddNode(this->selectedIndexes().at(0)));
+}
+
+void RegistryNodeTree::SlotDeleteNode() {
+ emit(RegistryNodeTree::SignalDeleteNode(this->selectedIndexes().at(0)));
+}
+
+void RegistryNodeTree::SlotCopyNodeName() {
+ QApplication::clipboard()->
+ setText(this->selectedIndexes().at(0).data().toString(),
+ QClipboard::Clipboard);
+}
+
+void RegistryNodeTree::SlotCopyNodePath() {
+ QString path=((RegistryNodeTreeModel*)(this->model()))->
+ GetNodePath(this->selectedIndexes().at(0));
+ QApplication::clipboard()->setText(path,QClipboard::Clipboard);
+}
diff --git a/tags/fred-0.2.0/registrynodetree.h b/tags/fred-0.2.0/registrynodetree.h
new file mode 100644
index 0000000..1c07199
--- /dev/null
+++ b/tags/fred-0.2.0/registrynodetree.h
@@ -0,0 +1,68 @@
+/*******************************************************************************
+* fred Copyright (c) 2011-2020 by Gillen Daniel <gillen.dan@pinguin.lu> *
+* *
+* Forensic Registry EDitor (fred) is a cross-platform M$ registry hive editor *
+* with special feautures useful during forensic analysis. *
+* *
+* This program is free software: you can redistribute it and/or modify it *
+* under the terms of the GNU General Public License as published by the Free *
+* Software Foundation, either version 3 of the License, or (at your option) *
+* any later version. *
+* *
+* This program is distributed in the hope that it will be useful, but WITHOUT *
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or *
+* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for *
+* more details. *
+* *
+* You should have received a copy of the GNU General Public License along with *
+* this program. If not, see <http://www.gnu.org/licenses/>. *
+*******************************************************************************/
+
+#ifndef REGISTRYNODETREE_H
+#define REGISTRYNODETREE_H
+
+#include <QTreeView>
+#include <QAbstractItemModel>
+#include <QContextMenuEvent>
+#include <QMenu>
+#include <QAction>
+
+class RegistryNodeTree : public QTreeView {
+ Q_OBJECT
+
+ public:
+ RegistryNodeTree(QWidget *p_parent=0);
+ ~RegistryNodeTree();
+
+ void setModel(QAbstractItemModel *p_model, bool writable=false);
+ void SetWritable(bool writable);
+
+ Q_SIGNALS:
+ void CurrentItemChanged(QModelIndex current);
+ void SignalAddNode(QModelIndex root_node);
+ void SignalRenameNode(QModelIndex node);
+ void SignalDeleteNode(QModelIndex node);
+
+ protected:
+// int sizeHintForColumn(int column) const;
+ void contextMenuEvent(QContextMenuEvent *p_event);
+ void keyPressEvent(QKeyEvent *p_event);
+ void currentChanged(const QModelIndex &current,
+ const QModelIndex &previous);
+
+ private:
+ bool is_writable;
+ QAction *p_action_add_node;
+ QAction *p_action_delete_node;
+ QMenu *p_menu_copy;
+ QAction *p_action_copy_node_name;
+ QAction *p_action_copy_node_path;
+
+ private slots:
+ void SlotAddNode();
+ void SlotDeleteNode();
+ void SlotCopyNodeName();
+ void SlotCopyNodePath();
+};
+
+#endif // REGISTRYNODETREE_H
diff --git a/tags/fred-0.2.0/registrynodetreemodel.cpp b/tags/fred-0.2.0/registrynodetreemodel.cpp
new file mode 100644
index 0000000..56e0b12
--- /dev/null
+++ b/tags/fred-0.2.0/registrynodetreemodel.cpp
@@ -0,0 +1,325 @@
+/*******************************************************************************
+* fred Copyright (c) 2011-2020 by Gillen Daniel <gillen.dan@pinguin.lu> *
+* *
+* Forensic Registry EDitor (fred) is a cross-platform M$ registry hive editor *
+* with special feautures useful during forensic analysis. *
+* *
+* This program is free software: you can redistribute it and/or modify it *
+* under the terms of the GNU General Public License as published by the Free *
+* Software Foundation, either version 3 of the License, or (at your option) *
+* any later version. *
+* *
+* This program is distributed in the hope that it will be useful, but WITHOUT *
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or *
+* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for *
+* more details. *
+* *
+* You should have received a copy of the GNU General Public License along with *
+* this program. If not, see <http://www.gnu.org/licenses/>. *
+*******************************************************************************/
+#include <QList>
+#include <QStringList>
+#include <QVariant>
+#include <QDateTime>
+
+#include "registrynodetreemodel.h"
+
+/*******************************************************************************
+ * Public
+ ******************************************************************************/
+
+RegistryNodeTreeModel::RegistryNodeTreeModel(RegistryHive *p_hive,
+ QObject *p_parent)
+ : QAbstractItemModel(p_parent)
+{
+ // Create root node. It's values will be used as header values.
+ this->p_root_node=new RegistryNode(QList<QVariant>()<<tr("Node")
+ <<tr("Last mod. time"));
+ // Load data
+ this->SetupModelData(p_hive,this->p_root_node);
+}
+
+RegistryNodeTreeModel::~RegistryNodeTreeModel() {
+ delete this->p_root_node;
+}
+
+QVariant RegistryNodeTreeModel::data(const QModelIndex &index, int role) const
+{
+ if(!index.isValid()) return QVariant();
+ if(role!=Qt::DisplayRole) return QVariant();
+
+ RegistryNode *p_node=static_cast<RegistryNode*>(index.internalPointer());
+
+ switch(role) {
+ case Qt::DisplayRole: {
+ switch(index.column()) {
+ case RegistryNodeTreeModel::ColumnContent_NodeName: {
+ return p_node->Data(index.column());
+ break;
+ }
+ case RegistryNodeTreeModel::ColumnContent_NodeModTime: {
+ QDateTime date_time;
+ bool ok=false;
+ date_time.setTimeSpec(Qt::UTC);
+ date_time.setTime_t(RegistryHive::FiletimeToUnixtime(
+ p_node->Data(index.column()).toLongLong(&ok)));
+ if(ok) return date_time.toString("yyyy/MM/dd hh:mm:ss");
+ else return tr("Unknown");
+ break;
+ }
+ default: {
+ return QVariant();
+ }
+ }
+ break;
+ }
+ default: {
+ return QVariant();
+ }
+ }
+
+ // Control will never reach this, but in order to stop g++ complaining...
+ return QVariant();
+}
+
+Qt::ItemFlags RegistryNodeTreeModel::flags(const QModelIndex &index) const {
+ if(!index.isValid()) return 0;
+ return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
+}
+
+QVariant RegistryNodeTreeModel::headerData(int section,
+ Qt::Orientation orientation,
+ int role) const
+{
+ // Only horizontal header is supported
+ if(orientation!=Qt::Horizontal) return QVariant();
+
+ switch(role) {
+ case Qt::TextAlignmentRole:
+ // Handle text alignment
+ return Qt::AlignCenter;
+ break;
+ case Qt::DisplayRole:
+ // Header text
+ return this->p_root_node->Data(section);
+ break;
+ default:
+ return QVariant();
+ }
+}
+
+QModelIndex RegistryNodeTreeModel::index(int row,
+ int column,
+ const QModelIndex &parent) const
+{
+ if(!this->hasIndex(row,column,parent)) return QModelIndex();
+
+ RegistryNode *p_parent_node;
+ if(!parent.isValid()) {
+ p_parent_node=this->p_root_node;
+ } else {
+ p_parent_node=static_cast<RegistryNode*>(parent.internalPointer());
+ }
+
+ RegistryNode *p_child_node=p_parent_node->Child(row);
+ if(p_child_node) {
+ return this->createIndex(row,column,p_child_node);
+ } else {
+ return QModelIndex();
+ }
+}
+
+QModelIndex RegistryNodeTreeModel::parent(const QModelIndex &index) const {
+ if(!index.isValid()) return QModelIndex();
+
+ RegistryNode *p_child_node=
+ static_cast<RegistryNode*>(index.internalPointer());
+ RegistryNode *p_parent_node=p_child_node->Parent();
+
+ if(p_parent_node==this->p_root_node) {
+ return QModelIndex();
+ } else {
+ return this->createIndex(p_parent_node->Row(),0,p_parent_node);
+ }
+}
+
+int RegistryNodeTreeModel::rowCount(const QModelIndex &parent) const {
+ if(parent.column()>0) return 0;
+
+ RegistryNode *p_parent_node;
+ if(!parent.isValid()) {
+ p_parent_node=this->p_root_node;
+ } else {
+ p_parent_node=static_cast<RegistryNode*>(parent.internalPointer());
+ }
+
+ return p_parent_node->ChildCount();
+}
+
+int RegistryNodeTreeModel::columnCount(const QModelIndex &parent) const {
+ Q_UNUSED(parent);
+ return 2;
+}
+
+QList<QModelIndex> RegistryNodeTreeModel::GetIndexListOf(QString path) {
+ RegistryNode *p_parent_node=this->p_root_node;
+ QList<QModelIndex> ret;
+ QStringList nodes=path.split("\\",QString::SkipEmptyParts);
+ bool found=false;
+
+ // Create a list of all index's that form the supplied path
+ ret.clear();
+ for(int i=0;i<nodes.count();i++) {
+ found=false;
+ for(quint64 ii=0;ii<p_parent_node->ChildCount();ii++) {
+ if(p_parent_node->Child(ii)->Data(0)==nodes.at(i)) {
+ ret.append(this->createIndex(ii,0,p_parent_node->Child(ii)));
+ p_parent_node=p_parent_node->Child(ii);
+ found=true;
+ break;
+ }
+ }
+ // Break when last child node was found
+ if(found && i==nodes.count()-1) break;
+ // Return an empty list when a child node wasn't found
+ else if(!found) return QList<QModelIndex>();
+ }
+
+ return ret;
+}
+
+QString RegistryNodeTreeModel::GetNodePath(QModelIndex child_index) {
+ QString path;
+
+ // Make the specified index point to the ColumnContent_NodeName column!
+ child_index=this->GetNodeNameIndex(child_index);
+
+ // Get current node name
+ path=this->data(child_index,Qt::DisplayRole).toString().prepend("\\");
+ // Build node path by prepending all parent nodes names
+ while(this->parent(child_index)!=QModelIndex()) {
+ child_index=this->parent(child_index);
+ path.prepend(this->data(child_index,
+ Qt::DisplayRole).toString().prepend("\\"));
+ }
+
+ return path;
+}
+
+QModelIndex RegistryNodeTreeModel::AddNode(RegistryHive *p_hive,
+ QModelIndex parent_index,
+ int new_node_id,
+ QString new_node_name)
+{
+ RegistryNode *p_parent_node;
+ qint64 key_mod_time;
+ RegistryNode *p_node;
+
+ // Make the specified index point to the ColumnContent_NodeName column!
+ parent_index=this->GetNodeNameIndex(parent_index);
+
+ // Get pointer to parent node
+ p_parent_node=static_cast<RegistryNode*>(parent_index.internalPointer());
+
+ // Tell users of this view that we are going to insert a row
+ emit(RegistryNodeTreeModel::beginInsertRows(parent_index,
+ p_parent_node->ChildCount(),
+ p_parent_node->ChildCount()));
+
+ // Create and add new node in internal node list
+ key_mod_time=p_hive->GetNodeModTime(new_node_id);
+ p_node=new RegistryNode(QList<QVariant>()<<new_node_name<<
+ QVariant((qlonglong)key_mod_time),
+ p_parent_node);
+ p_parent_node->AppendChild(p_node);
+
+ // Tell users of this view we have finished inserting a row
+ emit(RegistryNodeTreeModel::endInsertRows());
+
+ // Return index to new node
+ return this->createIndex(p_parent_node->ChildCount()-1,0,p_node);
+}
+
+QModelIndex RegistryNodeTreeModel::RemoveNode(QModelIndex index) {
+ RegistryNode *p_node;
+ RegistryNode *p_parent_node;
+ int node_row;
+ QModelIndex parent_node_index;
+
+ // Make the specified index point to the ColumnContent_NodeName column!
+ index=this->GetNodeNameIndex(index);
+
+ // Get pointers to current node and its parent
+ p_node=static_cast<RegistryNode*>(index.internalPointer());
+ p_parent_node=p_node->Parent();
+
+ // Get current nodes row
+ node_row=p_node->Row();
+
+ // Create index of parent node
+ parent_node_index=this->createIndex(p_parent_node->Row(),0,p_parent_node);
+
+ // Tell users of this view that we are going to remove a row
+ emit(RegistryNodeTreeModel::beginRemoveRows(parent_node_index,
+ node_row,
+ node_row));
+
+ // Remove node
+ p_parent_node->RemoveChild(node_row);
+
+ // Tell users of this view we have finished removing a row
+ emit(RegistryNodeTreeModel::endRemoveRows());
+
+ // Find a suitable index that should be selected after the current one has
+ // been deleted.
+ if(p_parent_node->ChildCount()>0) {
+ // Parent node still has child nodes, return nearest child node
+ if(node_row<p_parent_node->ChildCount()) {
+ // Any child node removed except the last one, row is still valid
+ return this->createIndex(node_row,0,p_parent_node->Child(node_row));
+ } else {
+ // Last child node removed, row-1 should be valid
+ return this->createIndex(node_row-1,0,p_parent_node->Child(node_row-1));
+ }
+ }
+ // If no child nodes are left, return parent node except if it is our root
+ // node!
+ if(p_parent_node->Parent()!=NULL) return parent_node_index;
+ else return QModelIndex();
+}
+
+/*******************************************************************************
+ * Private
+ ******************************************************************************/
+
+void RegistryNodeTreeModel::SetupModelData(RegistryHive *p_hive,
+ RegistryNode *p_parent,
+ int hive_node)
+{
+ QMap<QString,int> hive_children;
+ RegistryNode *p_node;
+ qint64 key_mod_time;
+
+ // Get all sub nodes of current hive node
+ if(hive_node) hive_children=p_hive->GetNodes(hive_node);
+ else hive_children=p_hive->GetNodes("\\");
+ if(hive_children.isEmpty()) return;
+
+ // Recursivly iterate over all sub nodes
+ QMapIterator<QString, int> i(hive_children);
+ while(i.hasNext()) {
+ i.next();
+ key_mod_time=p_hive->GetNodeModTime(i.value());
+ // TODO: Maybe we have to call GetErrorMsg in case an error occured
+ p_node=new RegistryNode(QList<QVariant>()<<i.key()<<
+ QVariant((qlonglong)key_mod_time),p_parent);
+ p_parent->AppendChild(p_node);
+ this->SetupModelData(p_hive,p_node,i.value());
+ }
+}
+
+QModelIndex RegistryNodeTreeModel::GetNodeNameIndex(QModelIndex index) {
+ return this->index(index.row(),
+ RegistryNodeTreeModel::ColumnContent_NodeName,
+ index.parent());
+}
diff --git a/tags/fred-0.2.0/registrynodetreemodel.h b/tags/fred-0.2.0/registrynodetreemodel.h
new file mode 100644
index 0000000..4d5bbe0
--- /dev/null
+++ b/tags/fred-0.2.0/registrynodetreemodel.h
@@ -0,0 +1,71 @@
+/*******************************************************************************
+* fred Copyright (c) 2011-2020 by Gillen Daniel <gillen.dan@pinguin.lu> *
+* *
+* Forensic Registry EDitor (fred) is a cross-platform M$ registry hive editor *
+* with special feautures useful during forensic analysis. *
+* *
+* This program is free software: you can redistribute it and/or modify it *
+* under the terms of the GNU General Public License as published by the Free *
+* Software Foundation, either version 3 of the License, or (at your option) *
+* any later version. *
+* *
+* This program is distributed in the hope that it will be useful, but WITHOUT *
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or *
+* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for *
+* more details. *
+* *
+* You should have received a copy of the GNU General Public License along with *
+* this program. If not, see <http://www.gnu.org/licenses/>. *
+*******************************************************************************/
+
+#ifndef REGISTRYNODETREEMODEL_H
+#define REGISTRYNODETREEMODEL_H
+
+#include <QAbstractItemModel>
+#include <QList>
+#include <QString>
+
+#include "registrynode.h"
+#include "registryhive.h"
+
+class RegistryNodeTreeModel : public QAbstractItemModel {
+ Q_OBJECT
+
+ public:
+ enum ColumnContent {
+ ColumnContent_NodeName=0,
+ ColumnContent_NodeModTime
+ };
+
+ RegistryNodeTreeModel(RegistryHive *p_hive, QObject *p_parent=0);
+ ~RegistryNodeTreeModel();
+
+ QVariant data(const QModelIndex &index, int role) const;
+ Qt::ItemFlags flags(const QModelIndex &index) const;
+ QVariant headerData(int section,
+ Qt::Orientation orientation,
+ int role=Qt::DisplayRole) const;
+ QModelIndex index(int row,
+ int column,
+ const QModelIndex &parent=QModelIndex()) const;
+ QModelIndex parent(const QModelIndex &index) const;
+ int rowCount(const QModelIndex &parent=QModelIndex()) const;
+ int columnCount(const QModelIndex &parent=QModelIndex()) const;
+
+ QList<QModelIndex> GetIndexListOf(QString path);
+ QString GetNodePath(QModelIndex child_index);
+ QModelIndex AddNode(RegistryHive *p_hive, QModelIndex parent_index,
+ int new_node_id,
+ QString new_node_name);
+ QModelIndex RemoveNode(QModelIndex index);
+
+ private:
+ RegistryNode *p_root_node;
+
+ void SetupModelData(RegistryHive *p_hive,
+ RegistryNode *p_parent,
+ int hive_node=0);
+ QModelIndex GetNodeNameIndex(QModelIndex index);
+};
+
+#endif // REGISTRYNODETREEMODEL_H
diff --git a/tags/fred-0.2.0/registrynodetreemodelproxy.cpp b/tags/fred-0.2.0/registrynodetreemodelproxy.cpp
new file mode 100644
index 0000000..194b250
--- /dev/null
+++ b/tags/fred-0.2.0/registrynodetreemodelproxy.cpp
@@ -0,0 +1,40 @@
+/*******************************************************************************
+* fred Copyright (c) 2011-2020 by Gillen Daniel <gillen.dan@pinguin.lu> *
+* *
+* Forensic Registry EDitor (fred) is a cross-platform M$ registry hive editor *
+* with special feautures useful during forensic analysis. *
+* *
+* This program is free software: you can redistribute it and/or modify it *
+* under the terms of the GNU General Public License as published by the Free *
+* Software Foundation, either version 3 of the License, or (at your option) *
+* any later version. *
+* *
+* This program is distributed in the hope that it will be useful, but WITHOUT *
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or *
+* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for *
+* more details. *
+* *
+* You should have received a copy of the GNU General Public License along with *
+* this program. If not, see <http://www.gnu.org/licenses/>. *
+*******************************************************************************/
+
+#include "registrynodetreemodelproxy.h"
+
+RegistryNodeTreeModelProxy::RegistryNodeTreeModelProxy(QObject *p_parent) :
+ QSortFilterProxyModel(p_parent)
+{
+}
+
+bool RegistryNodeTreeModelProxy::lessThan(const QModelIndex &left,
+ const QModelIndex &right) const
+{
+ QVariant leftData=this->sourceModel()->data(left);
+ QVariant rightData=this->sourceModel()->data(right);
+
+ if(leftData.type()==QVariant::String && rightData.type()==QVariant::String) {
+ // Sort strings case insensitive
+ return leftData.toString().toLower()<rightData.toString().toLower();
+ } else {
+ return QSortFilterProxyModel::lessThan(left,right);
+ }
+}
diff --git a/tags/fred-0.2.0/registrynodetreemodelproxy.h b/tags/fred-0.2.0/registrynodetreemodelproxy.h
new file mode 100644
index 0000000..5374816
--- /dev/null
+++ b/tags/fred-0.2.0/registrynodetreemodelproxy.h
@@ -0,0 +1,36 @@
+/*******************************************************************************
+* fred Copyright (c) 2011-2020 by Gillen Daniel <gillen.dan@pinguin.lu> *
+* *
+* Forensic Registry EDitor (fred) is a cross-platform M$ registry hive editor *
+* with special feautures useful during forensic analysis. *
+* *
+* This program is free software: you can redistribute it and/or modify it *
+* under the terms of the GNU General Public License as published by the Free *
+* Software Foundation, either version 3 of the License, or (at your option) *
+* any later version. *
+* *
+* This program is distributed in the hope that it will be useful, but WITHOUT *
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or *
+* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for *
+* more details. *
+* *
+* You should have received a copy of the GNU General Public License along with *
+* this program. If not, see <http://www.gnu.org/licenses/>. *
+*******************************************************************************/
+
+#ifndef REGISTRYNODETREEMODELPROXY_H
+#define REGISTRYNODETREEMODELPROXY_H
+
+#include <QSortFilterProxyModel>
+
+class RegistryNodeTreeModelProxy : public QSortFilterProxyModel {
+ Q_OBJECT
+
+ public:
+ explicit RegistryNodeTreeModelProxy(QObject *p_parent=0);
+
+ protected:
+ bool lessThan(const QModelIndex &left, const QModelIndex &right) const;
+};
+
+#endif // REGISTRYNODETREEMODELPROXY_H
diff --git a/tags/fred-0.2.0/report_templates/NTUSER_Autoruns.qs b/tags/fred-0.2.0/report_templates/NTUSER_Autoruns.qs
new file mode 100644
index 0000000..e67797c
--- /dev/null
+++ b/tags/fred-0.2.0/report_templates/NTUSER_Autoruns.qs
@@ -0,0 +1,56 @@
+function fred_report_info() {
+ var info={report_cat : "NTUSER",
+ report_name : "Autoruns",
+ report_author : "Gillen Daniel",
+ report_desc : "Dump autorun keys",
+ fred_api : 2,
+ hive : "NTUSER"
+ };
+ return info;
+}
+
+function IsValid(val) {
+ if(typeof val !== 'undefined') return true;
+ else return false;
+}
+
+function print_table_row(cell01,cell02) {
+ println(" <tr><td>",cell01,"</td><td>",cell02,"</td></tr>");
+}
+
+function ListAutoruns(autorun_path,autorun_key) {
+ println(" <p style=\"font-size:12; white-space:nowrap\">");
+ println(" <u>"+autorun_key+"</u><br />");
+ var run_keys=GetRegistryKeys(autorun_path+autorun_key);
+ if(IsValid(run_keys) && run_keys.length>0) {
+ println(" <table style=\"margin-left:20px; font-size:12; white-space:nowrap\">");
+ print_table_row("<b>Name</b>","<b>Executable</b>");
+
+ for(var i=0;i<run_keys.length;i++) {
+ var val=GetRegistryKeyValue(autorun_path+autorun_key,run_keys[i]);
+ print_table_row(run_keys[i],RegistryKeyValueToString(val.value,val.type));
+ }
+
+ println(" </table>");
+ } else {
+ println(" &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;None");
+ }
+ println(" </p>");
+}
+
+function fred_report_html() {
+ var val;
+
+ println(" <h2>User Autoruns</h2>");
+
+ // Run
+ ListAutoruns("\\Microsoft\\Windows\\CurrentVersion\\","Run");
+
+ // RunOnce
+ ListAutoruns("\\Microsoft\\Windows\\CurrentVersion\\","RunOnce");
+
+ // RunOnceEx
+ ListAutoruns("\\Microsoft\\Windows\\CurrentVersion\\","RunOnceEx");
+
+ // TODO: There might be a Run under WindowsNT\CurrentVersion\Run too!
+}
diff --git a/tags/fred-0.2.0/report_templates/NTUSER_InternetDownloadManager.qs b/tags/fred-0.2.0/report_templates/NTUSER_InternetDownloadManager.qs
new file mode 100644
index 0000000..eea83e5
--- /dev/null
+++ b/tags/fred-0.2.0/report_templates/NTUSER_InternetDownloadManager.qs
@@ -0,0 +1,305 @@
+// Internet Download Manager is a program that may integrate itself into all commpon browsers.
+// It claims to download much faster and be more comfortable.
+//
+// The code below has been written after analysis of several systems where IDM was installed.
+// Documentation also can be found under
+// https://tise2015.kku.ac.th/drupal/sites/default/files/1-s2.0-S1742287610000575-main.pdf
+// That documentation refers too a much older version of IDM, but the string obfuscation
+// technique is still the same.
+
+function fred_report_info()
+{
+ var info = {
+ report_cat : "NTUSER",
+ report_name : "Internet Download Manager",
+ report_author : "Guy Voncken <develop@faert.net>",
+ report_desc : "Extract IDM download list and configuration settings",
+ fred_api : 2,
+ hive : "NTUSER"
+ };
+ return info;
+}
+
+function IsValid (val)
+{
+ if(typeof val !== 'undefined') return true;
+ else return false;
+}
+
+
+function GetKeyVal(path, key)
+{
+ var val=GetRegistryKeyValue(path, key);
+ var Ret = (IsValid(val)) ? RegistryKeyValueToString (val.value, val.type) : "";
+ return String (Ret);
+}
+
+
+
+var table_style = "border-collapse:collapse; margin-left:20px; font-family:arial; font-size:14;";
+var cell_style = "border:1px solid #888888; padding:5; max-width:500px; word-wrap: break-word; ";
+
+
+function PrintTableHeaderCell (str)
+{
+ println (" <th style=\"",cell_style,"\">",str,"</th>");
+}
+
+function PrintTableDataCell(alignment,str)
+{
+ var style = cell_style + "text-align:" + alignment + ";";
+ println (" <td style=\"",style,"\">",str,"</td>");
+}
+
+function StrSizeToNum (StrSize)
+{
+ var Str = String(StrSize);
+ var Num = 0;
+ var i = Str.length-1;
+
+ while (i >= 1)
+ {
+ if (Str[i] == " ")
+ {
+ i--;
+ }
+ else
+ {
+ Byte = 16 * parseInt (Str[i-1], 16) +
+ parseInt (Str[i ], 16);
+ Num = Num * 256 + Byte;
+ i -= 2;
+ }
+ }
+ return Num;
+}
+
+function SizeToHuman (StrSize)
+{
+ var Size = parseInt (StrSize,10);
+ var Unit = "&nbsp;&nbsp;B";
+
+ if (Size > 1024) {Size = Size / 1024.0; Unit = "KiB"};
+ if (Size > 1024) {Size = Size / 1024.0; Unit = "MiB"};
+ if (Size > 1024) {Size = Size / 1024.0; Unit = "GiB"};
+ if (Size > 1024) {Size = Size / 1024.0; Unit = "TiB"};
+
+ return Size.toFixed(2) + " " + Unit;
+}
+
+function ConvertSillyDateFormat (DateIn)
+{
+ var DateOut = DateIn.slice (16,20) + " " + DateIn.slice (0,6) + "&nbsp&nbsp;" + DateIn.slice (7,15);
+ return DateOut;
+}
+
+function ConvString8 (EncStr, Encrypted)
+{
+ var Str = "";
+ for (i=0; i<EncStr.length; i+=3)
+ {
+ var N1 = parseInt (EncStr[i] , 16);
+ var N0 = parseInt (EncStr[i+1], 16);
+ if (Encrypted)
+ N0 = N0 ^ 0x0F; // Not really encrypted, but obfuscated
+ var Code = N1*16 + N0;
+ if (Code > 0)
+ Str = Str + String.fromCharCode (Code);
+ }
+ return Str;
+}
+
+function ConvString16 (EncStr, Encrypted)
+{
+ var Str = "";
+ for (i=0; i<EncStr.length; i+=6)
+ {
+ var N1 = parseInt (EncStr[i] , 16);
+ var N0 = parseInt (EncStr[i+1], 16);
+ var N3 = parseInt (EncStr[i+3], 16);
+ var N2 = parseInt (EncStr[i+4], 16);
+ if (Encrypted)
+ N0 = N0 ^ 0x0F; // Not really encrypted, but obfuscated
+ var Code = N3*4096 + N2*256 + N1*16 + N0;
+ if (Code > 0)
+ Str = Str + String.fromCharCode (Code);
+ }
+ return Str;
+}
+
+
+function fred_report_html0 ()
+{
+ var val;
+
+ println(" <h2>Internet Download Manager</h2>");
+ var IDM_Root = "\\Software\\DownloadManager";
+
+
+ if (!IsValid (GetRegistryKeyValue(IDM_Root, "idmvers")))
+ {
+ println ("<p>No IDM installation found.<p>")
+ return;
+ }
+
+ Version = String (GetKeyVal(IDM_Root, "idmvers"));
+ Serial = String (GetKeyVal(IDM_Root, "Serial"));
+ TempPath = String (GetKeyVal(IDM_Root, "TempPath"));
+ println ("<pre>")
+ println ("Installed version: " + Version);
+ println ("Serial: " + Serial);
+ println ("Temp path: " + TempPath);
+ println ("</pre>")
+
+ // Download folders
+ // ----------------
+ var IDM_Folders = IDM_Root + "\\FoldersTree";
+ var FoldersNodes = GetRegistryNodes (IDM_Folders);
+// var Folders = []
+ if (IsValid (FoldersNodes))
+ {
+ println ("<h3>IDM default download paths</h3>");
+ println (" <table style=\""+table_style+"\">");
+ println (" <tr>");
+ PrintTableHeaderCell ("ID");
+ PrintTableHeaderCell ("Name");
+ PrintTableHeaderCell ("Mask");
+ PrintTableHeaderCell ("Path");
+ println(" </tr>");
+
+ for(var i=0; i < FoldersNodes.length; i++)
+ {
+ var Name = FoldersNodes[i];
+ var Key = IDM_Folders + "\\" + Name;
+ IDStr = String (GetKeyVal(Key, "ID"));
+ Mask = String (GetKeyVal(Key, "mask"));
+ PathW = String (GetKeyVal(Key, "pathW"));
+
+ ID = parseInt (IDStr.slice(2),16),
+ Path = ConvString16 (PathW, false);
+
+ println(" </tr>");
+ PrintTableDataCell ("left", ID);
+ PrintTableDataCell ("left", Name);
+ PrintTableDataCell ("left", Mask);
+ PrintTableDataCell ("left", Path);
+ println(" </tr>");
+
+// Folders[IndexStr] = Name;
+ }
+ println(" </table>");
+ }
+ else
+ {
+ println ("<p>No folders found.</p>")
+ }
+
+
+ // Downloaded files
+ // ----------------
+ var RootNodes = GetRegistryNodes (IDM_Root);
+ if (IsValid(RootNodes))
+ {
+ println ("<h3>IDM file downloads</h3>");
+ println(" <table style=\""+table_style+"\">");
+ println(" <tr>");
+ PrintTableHeaderCell("Ref");
+ PrintTableHeaderCell("File Name");
+ PrintTableHeaderCell("Size");
+ PrintTableHeaderCell("Size Human");
+ PrintTableHeaderCell("Date added");
+ PrintTableHeaderCell("Last try date");
+ PrintTableHeaderCell("Status");
+ PrintTableHeaderCell("Save To");
+ PrintTableHeaderCell("Description");
+ PrintTableHeaderCell("URL");
+ PrintTableHeaderCell("Referer");
+ PrintTableHeaderCell("Password");
+ PrintTableHeaderCell("U-User");
+ PrintTableHeaderCell("U-Password");
+ println(" </tr>");
+
+ RootNodes.sort(function(a, b) { return parseInt(a,10) -parseInt(b,10) })
+ for(var i=0; i<RootNodes.length; i++)
+ {
+ if (!isNaN (RootNodes[i]))
+ {
+ Key = IDM_Root + "\\" + RootNodes[i];
+ var Filename = GetKeyVal(Key,"Filename");
+ var SavedToEnc = GetKeyVal(Key,"EncLNFSW");
+ var Renamed = GetKeyVal(Key,"FR_FNCD");
+ var StrSize = GetKeyVal(Key,"FileSize");
+ var DateAdded = GetKeyVal(Key,"DateAdded");
+ var DateLastTry = GetKeyVal(Key,"LastTryDate");
+ var Status = GetKeyVal(Key,"Status");
+ var Category = GetKeyVal(Key,"CategoryID");
+ var Description = GetKeyVal(Key,"Description");
+ var URL = GetKeyVal(Key,"Url0");
+ var Referer = GetKeyVal(Key,"Referer");
+ var PasswordEnc = GetKeyVal(Key,"EncPassword");
+ var U_User = GetKeyVal(Key,"U0_u");
+ var U_PasswordEnc = GetKeyVal(Key,"U0_EncP");
+
+ var PosQ = Filename.indexOf("?");
+ if (PosQ >= 0)
+ Filename = Filename.slice(0, PosQ); // Cut of Filename at first occurence of "?"
+ Size = StrSizeToNum (StrSize);
+ SizeHuman = SizeToHuman (Size);
+ DateAdded = ConvertSillyDateFormat (DateAdded);
+ DateLastTry = ConvertSillyDateFormat (DateLastTry);
+
+ switch (Status)
+ {
+ case "0x00000000": StatusStr = "Not found"; break;
+ case "0x00000003": StatusStr = "Completed"; break;
+ default : StatusStr = Status;
+ }
+// SavedTo = Folders[Category];
+
+ SavedTo = ConvString16 (SavedToEnc , true);
+ Password = ConvString8 (PasswordEnc , true);
+ U_Password = ConvString8 (U_PasswordEnc, true);
+
+ println(" <tr>");
+ PrintTableDataCell ("left", RootNodes[i]);
+ if (IsValid (GetRegistryKeyValue(Key, "FR_FNCD")))
+ PrintTableDataCell ("left", Renamed);
+ else PrintTableDataCell ("left", Filename);
+ PrintTableDataCell ("right", Size);
+ PrintTableDataCell ("right", SizeHuman);
+ PrintTableDataCell ("left", DateAdded);
+ PrintTableDataCell ("left", DateLastTry);
+ PrintTableDataCell ("left", StatusStr);
+ PrintTableDataCell ("left", SavedTo);
+ PrintTableDataCell ("left", Description);
+ PrintTableDataCell ("left", URL);
+ PrintTableDataCell ("left", Referer);
+ PrintTableDataCell ("left", Password);
+ PrintTableDataCell ("left", U_User);
+ PrintTableDataCell ("left", U_Password);
+ println(" </tr>");
+ }
+ }
+ println(" </table>");
+ println ("<p>The results above have been verified with IDM 6.26 under Windows 8.1 pro.</p>");
+ println ("<p>Not tested yet: Download paths with characters above ASCII range.</p>");
+ }
+ else
+ {
+ println ("<p>No file download entries found.</p>")
+ }
+}
+
+function fred_report_html()
+{
+ try
+ {
+ fred_report_html0()
+ }
+
+ catch (Exc)
+ {
+ println ("Exception occured: " + Exc)
+ }
+}
+
diff --git a/tags/fred-0.2.0/report_templates/NTUSER_LaunchedApplications.qs b/tags/fred-0.2.0/report_templates/NTUSER_LaunchedApplications.qs
new file mode 100644
index 0000000..346296f
--- /dev/null
+++ b/tags/fred-0.2.0/report_templates/NTUSER_LaunchedApplications.qs
@@ -0,0 +1,108 @@
+function fred_report_info() {
+ var info={report_cat : "NTUSER",
+ report_name : "Launched applications",
+ report_author : "Gillen Daniel",
+ report_desc : "Dump IE launched applications",
+ fred_api : 2,
+ hive : "NTUSER"
+ };
+ return info;
+}
+
+function IsValid(val) {
+ if(typeof val !== 'undefined') return true;
+ else return false;
+}
+
+function PrintTableRow(cell01,cell02,cell03) {
+ println(" <tr><td style=\"white-space:nowrap\">",cell01,"</td><td style=\"padding:2px; white-space:nowrap\">",cell02,"</td><td style=\"padding:2px; white-space:nowrap\">",cell03,"</td></tr>");
+}
+
+function Rot13Decode(val) {
+ var ret="";
+
+ for(var i=0;i<val.length;i++) {
+ var decoded=val.charCodeAt(i);
+ if((decoded>64 && decoded<91) || (decoded>96 && decoded<123)) {
+ if((decoded-13)<65 || (decoded>96 && (decoded-13)<97)) {
+ decoded=(decoded-13)+26;
+ } else {
+ if(decoded>96 && (decoded-13)<97) {
+ decoded+=13;
+ } else {
+ decoded-=13;
+ }
+ }
+ ret+=String.fromCharCode(decoded);
+ } else {
+ ret+=val[i];
+ }
+ }
+
+ return ret;
+}
+
+function PrintUserAssistEntry(key,val,os) {
+ var run_count;
+ var last_run;
+
+ switch(os) {
+ case "winxp":
+ run_count=RegistryKeyValueToVariant(val.value,"uint32",4);
+
+ break;
+ case "win7":
+ run_count=RegistryKeyValueToVariant(val.value,"uint32",4,0,1);
+ last_run=RegistryKeyValueToVariant(val.value,"filetime",60);
+ break;
+ }
+
+ PrintTableRow(key,run_count,last_run);
+}
+
+function fred_report_html() {
+ println(" <h2>Launched applications</h2>");
+
+ // First, we need to find the correct GUID for the current Windows version
+ var path;
+ var apps;
+ var os;
+
+ // Windows XP
+ os="winxp";
+ path="\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\UserAssist\\{5E6AB780-7743-11CF-A12B-00AA004AE837}\\Count";
+ apps=GetRegistryKeys(path);
+
+ // TODO: Determine GUIDs for Vista / Win8
+
+ if(!IsValid(apps)) {
+ // Windows 7
+ os="win7";
+ path="\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\UserAssist\\{CEBFF5CD-ACE2-4F4F-9178-9926F41749EA}\\Count";
+ apps=GetRegistryKeys(path);
+ }
+
+ if(IsValid(apps)) {
+ if(apps.length!=0) {
+ println(" <p style=\"font-size:12\">");
+ println(" <table style=\"margin-left:20px; font-size:12\">");
+ println(" <tr><td><b>Application</b></td><td style=\"padding:2px\"><b>Run count</b></td><td style=\"padding:2px\"><b>Last run</b></td></tr>");
+
+ for(var i=0;i<apps.length;i++) {
+ var val=GetRegistryKeyValue(path,apps[i]);
+ PrintUserAssistEntry(Rot13Decode(apps[i]),val,os);
+ }
+
+ println(" </table>");
+ println(" </p>");
+ } else {
+ println(" <p><font color='red'>");
+ println(" The list of launched applications is empty.");
+ println(" </font></p>");
+ }
+ } else {
+ println(" <p><font color='red'>");
+ println(" This registry hive does not contain a list of launched applications!");
+ println(" </font></p>");
+ }
+}
diff --git a/tags/fred-0.2.0/report_templates/NTUSER_RecentDocs.qs b/tags/fred-0.2.0/report_templates/NTUSER_RecentDocs.qs
new file mode 100644
index 0000000..bd8b2fa
--- /dev/null
+++ b/tags/fred-0.2.0/report_templates/NTUSER_RecentDocs.qs
@@ -0,0 +1,49 @@
+function fred_report_info() {
+ var info={report_cat : "NTUSER",
+ report_name : "Recent documents",
+ report_author : "Gillen Daniel",
+ report_desc : "Dump recent docs",
+ fred_api : 2,
+ hive : "NTUSER"
+ };
+ return info;
+}
+
+function IsValid(val) {
+ if(typeof val !== 'undefined') return true;
+ else return false;
+}
+
+function fred_report_html() {
+ println(" <h2>Recent documents</h2>");
+
+ // Get list of recent docs
+ var recent_docs=GetRegistryKeyValue("\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\RecentDocs","MRUListEx");
+ if(IsValid(recent_docs)) {
+ // Iterate over all recent docs
+ var i=0;
+ var runlist=RegistryKeyValueToVariant(recent_docs.value,"uint32",i);
+ if(Number(runlist)!=0xffffffff) {
+ println(" <p style=\"font-size:12\">");
+ println(" <table style=\"margin-left:20px; font-size:12\">");
+
+ while(Number(runlist)!=0xffffffff) {
+ var entry=GetRegistryKeyValue("\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\RecentDocs",runlist.toString(10));
+ println(" <tr><td style=\"white-space:nowrap\">",RegistryKeyValueToVariant(entry.value,"utf16",0),"</td></tr>");
+ i+=4;
+ runlist=RegistryKeyValueToVariant(recent_docs.value,"uint32",i);
+ }
+
+ println(" </table>");
+ println(" </p>");
+ } else {
+ println(" <p><font color='red'>");
+ println(" The list of recent documents is empty.");
+ println(" </font></p>");
+ }
+ } else {
+ println(" <p><font color='red'>");
+ println(" This registry hive does not contain a list of recent documents!");
+ println(" </font></p>");
+ }
+}
diff --git a/tags/fred-0.2.0/report_templates/NTUSER_TypedUrls.qs b/tags/fred-0.2.0/report_templates/NTUSER_TypedUrls.qs
new file mode 100644
index 0000000..267408b
--- /dev/null
+++ b/tags/fred-0.2.0/report_templates/NTUSER_TypedUrls.qs
@@ -0,0 +1,68 @@
+function fred_report_info() {
+ var info={report_cat : "NTUSER",
+ report_name : "Typed URLs",
+ report_author : "Gillen Daniel, Voncken Guy",
+ report_desc : "Dump typed URLs",
+ fred_api : 2,
+ hive : "NTUSER"
+ };
+ return info;
+}
+
+function IsValid(val) {
+ if(typeof val !== 'undefined') return true;
+ else return false;
+}
+
+function GetUrlTimestamp (url_id) {
+ ret="Unknown";
+
+ var typed_urls_time=GetRegistryKeys("\\Software\\Microsoft\\Internet Explorer\\TypedURLsTime");
+ if(IsValid(typed_urls_time)) {
+ for(var i=0;i<typed_urls_time.length;i++) {
+ if(typed_urls_time[i]==url_id) {
+ // Found
+ ts=GetRegistryKeyValue("\\Software\\Microsoft\\Internet Explorer\\TypedURLsTime",typed_urls_time[i]);
+ if(!IsValid(ts)) break;
+ ret=RegistryKeyValueToVariant(ts.value,"filetime");
+ break;
+ }
+ }
+ }
+
+ return ret;
+}
+
+function fred_report_html() {
+ println(" <h2>Typed urls</h2>");
+
+ // Iterate over all typed urls
+ var typed_urls=GetRegistryKeys("\\Software\\Microsoft\\Internet Explorer\\TypedURLs");
+ if(IsValid(typed_urls)) {
+ if(typed_urls.length!=0) {
+ println(" <p style=\"font-size:12\">");
+ println(" <table style=\"margin-left:20px; font-size:12\">");
+ println(" <tr><td><b>Last added</b></td><td><b>URL</b></td>");
+
+ for(var i=0;i<typed_urls.length;i++) {
+ var url=GetRegistryKeyValue("\\Software\\Microsoft\\Internet Explorer\\TypedURLs",typed_urls[i]);
+ var ts=GetUrlTimestamp(typed_urls[i]);
+ println(" <tr>");
+ println(" <td style=\"white-space:nowrap\">",ts,"</td>");
+ println(" <td style=\"white-space:nowrap\">",RegistryKeyValueToString(url.value,url.type),"</td>");
+ println(" </tr>");
+ }
+
+ println(" </table>");
+ println(" </p>");
+ } else {
+ println(" <p><font color='red'>");
+ println(" The list of typed urls is empty.");
+ println(" </font></p>");
+ }
+ } else {
+ println(" <p><font color='red'>");
+ println(" This registry hive does not contain a list of typed urls!");
+ println(" </font></p>");
+ }
+}
diff --git a/tags/fred-0.2.0/report_templates/NTUSER_Windows7_SearchKeywords.qs b/tags/fred-0.2.0/report_templates/NTUSER_Windows7_SearchKeywords.qs
new file mode 100644
index 0000000..b4afed4
--- /dev/null
+++ b/tags/fred-0.2.0/report_templates/NTUSER_Windows7_SearchKeywords.qs
@@ -0,0 +1,49 @@
+function fred_report_info() {
+ var info={report_cat : "NTUSER",
+ report_name : "Windows 7 search keywords",
+ report_author : "Gillen Daniel",
+ report_desc : "Dump Windows 7 search keywords",
+ fred_api : 2,
+ hive : "NTUSER"
+ };
+ return info;
+}
+
+function IsValid(val) {
+ if(typeof val !== 'undefined') return true;
+ else return false;
+}
+
+function fred_report_html() {
+ println(" <h2>Document and folder search keywords</h2>");
+
+ // Get list of search keys
+ var mrulist=GetRegistryKeyValue("\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\WordWheelQuery","MRUListEx");
+ if(IsValid(mrulist)) {
+ // Iterate over all items
+ var i=0;
+ var runlist=RegistryKeyValueToVariant(mrulist.value,"uint32",i);
+ if(Number(runlist)!=0xffffffff) {
+ println(" <p style=\"font-size:12\">");
+ println(" <table style=\"margin-left:20px; font-size:12\">");
+
+ while(Number(runlist)!=0xffffffff) {
+ var entry=GetRegistryKeyValue("\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\WordWheelQuery",runlist.toString(10));
+ println(" <tr><td style=\"white-space:nowrap\">",RegistryKeyValueToVariant(entry.value,"utf16",0),"</td></tr>");
+ i+=4;
+ runlist=RegistryKeyValueToVariant(mrulist.value,"uint32",i);
+ }
+
+ println(" </table>");
+ println(" </p>");
+ } else {
+ println(" <p><font color='red'>");
+ println(" The list of document and search keywords is empty.");
+ println(" </font></p>");
+ }
+ } else {
+ println(" <p><font color='red'>");
+ println(" This registry hive does not contain a list of document and folder search keywords!");
+ println(" </font></p>");
+ }
+}
diff --git a/tags/fred-0.2.0/report_templates/NTUSER_Windows7_TypedPaths.qs b/tags/fred-0.2.0/report_templates/NTUSER_Windows7_TypedPaths.qs
new file mode 100644
index 0000000..96ccb20
--- /dev/null
+++ b/tags/fred-0.2.0/report_templates/NTUSER_Windows7_TypedPaths.qs
@@ -0,0 +1,44 @@
+function fred_report_info() {
+ var info={report_cat : "NTUSER",
+ report_name : "Windows 7 typed paths",
+ report_author : "Gillen Daniel",
+ report_desc : "Dump Windows 7 typed paths",
+ fred_api : 2,
+ hive : "NTUSER"
+ };
+ return info;
+}
+
+function IsValid(val) {
+ if(typeof val !== 'undefined') return true;
+ else return false;
+}
+
+function fred_report_html() {
+ println(" <h2>Typed paths</h2>");
+
+ // Iterate over all typed paths
+ var urls=GetRegistryKeys("\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\TypedPaths");
+ if(IsValid(urls)) {
+ if(urls.length!=0) {
+ println(" <p style=\"font-size:12\">");
+ println(" <table style=\"margin-left:20px; font-size:12\">");
+
+ for(var i=0;i<urls.length;i++) {
+ var val=GetRegistryKeyValue("\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\TypedPaths",urls[i]);
+ println(" <tr><td style=\"white-space:nowrap\">",RegistryKeyValueToString(val.value,val.type),"</td></tr>");
+ }
+
+ println(" </table>");
+ println(" </p>");
+ } else {
+ println(" <p><font color='red'>");
+ println(" The list of typed paths is empty.");
+ println(" </font></p>");
+ }
+ } else {
+ println(" <p><font color='red'>");
+ println(" This registry hive does not contain a list of typed paths!");
+ println(" </font></p>");
+ }
+}
diff --git a/tags/fred-0.2.0/report_templates/NTUSER_WindowsLiveAccounts.qs b/tags/fred-0.2.0/report_templates/NTUSER_WindowsLiveAccounts.qs
new file mode 100644
index 0000000..5c48bd1
--- /dev/null
+++ b/tags/fred-0.2.0/report_templates/NTUSER_WindowsLiveAccounts.qs
@@ -0,0 +1,43 @@
+function fred_report_info() {
+ var info={report_cat : "NTUSER",
+ report_name : "Windows Live accounts",
+ report_author : "Gillen Daniel",
+ report_desc : "Dump Windows Live accounts",
+ fred_api : 2,
+ hive : "NTUSER"
+ };
+ return info;
+}
+
+function IsValid(val) {
+ if(typeof val !== 'undefined') return true;
+ else return false;
+}
+
+function fred_report_html() {
+ println(" <h2>Windows live accounts</h2>");
+
+ // Iterate over all contacts
+ var accounts=GetRegistryKeys("\\Software\\Microsoft\\Windows Live Contacts\\Database");
+ if(IsValid(accounts)) {
+ println(" <p style=\"font-size:12\">");
+ println(" <table style=\"margin-left:20px; font-size:12\">");
+
+ for(var i=0;i<accounts.length;i++) {
+ var val=GetRegistryKeyValue("\\Software\\Microsoft\\Windows Live Contacts\\Database",accounts[i]);
+ println(" <tr><td>",accounts[i],"</td><td>",RegistryKeyValueToString(val.value,val.type),"</td></tr>");
+ }
+ accounts=GetRegistryKeys("\\Software\\Microsoft\\Windows Live Contacts\\Me");
+ for(var i=0;i<accounts.length;i++) {
+ var val=GetRegistryKeyValue("\\Software\\Microsoft\\Windows Live Contacts\\Me",accounts[i]);
+ println(" <tr><td>",accounts[i],"</td><td>",RegistryKeyValueToString(val.value,val.type),"</td></tr>");
+ }
+
+ println(" </table>");
+ println(" </p>");
+ } else {
+ println(" <p><font color='red'>");
+ println(" This registry hive does not contain a list of Windows Live Accounts!");
+ println(" </font></p>");
+ }
+}
diff --git a/tags/fred-0.2.0/report_templates/SAM_UserAccounts.qs b/tags/fred-0.2.0/report_templates/SAM_UserAccounts.qs
new file mode 100644
index 0000000..677cf37
--- /dev/null
+++ b/tags/fred-0.2.0/report_templates/SAM_UserAccounts.qs
@@ -0,0 +1,144 @@
+function fred_report_info() {
+ var info={report_cat : "SAM",
+ report_name : "User accounts",
+ report_author : "Gillen Daniel, Voncken Guy",
+ report_desc : "Dump Windows user accounts",
+ fred_api : 2,
+ hive : "SAM"
+ };
+ return info;
+}
+
+var table_style = "border-collapse:collapse; margin-left:20px; font-family:arial; font-size:12;";
+var cell_style = "border:1px solid #888888; padding:5; white-space:nowrap;";
+
+function IsValid(val) {
+ return (typeof val!=='undefined');
+}
+
+function PrintTableHeaderCell(str) {
+ println(" <th style=\"",cell_style,"\">",str,"</th>");
+}
+
+function PrintTableDataCell(alignment,str) {
+ var style=cell_style+" text-align:"+alignment+";";
+ println(" <td style=\"",style,"\">",str,"</td>");
+}
+
+
+function Get_v_info(v_key_value,str_off) {
+ var ret_str="";
+ var offset=Number(RegistryKeyValueToVariant(v_key_value,"uint16",str_off))+0x0cc;
+ var len=Number(RegistryKeyValueToVariant(v_key_value,"uint16",str_off+4));
+ if(len>0) ret_str=RegistryKeyValueToVariant(v_key_value,"utf16",offset,len)
+
+ return ret_str;
+}
+
+function fred_report_html() {
+ // See http://windowsir.blogspot.com/2006/08/getting-user-info-from-image.html
+ println(" <h2>User accounts</h2>");
+
+ // Iterate over all user names
+ var user_names=GetRegistryNodes("\\SAM\\Domains\\Account\\Users\\Names");
+ if(IsValid(user_names)) {
+ println(" <table style=\""+table_style+"\">");
+
+ println(" <tr>");
+ PrintTableHeaderCell("Name");
+ PrintTableHeaderCell("RID");
+ PrintTableHeaderCell("Full<br>name");
+ PrintTableHeaderCell("Last<br>login");
+ PrintTableHeaderCell("Last PW<br>change");
+ PrintTableHeaderCell("Last failed<br>login");
+ PrintTableHeaderCell("Account<br>expiry");
+ PrintTableHeaderCell("Total<br>logins");
+ PrintTableHeaderCell("Failed<br>logins");
+ PrintTableHeaderCell("Flags");
+ PrintTableHeaderCell("Password<br>hint");
+ PrintTableHeaderCell("Home drive<br>and dir");
+ PrintTableHeaderCell("Logon<br>script path");
+ PrintTableHeaderCell("Profile<br>path");
+ PrintTableHeaderCell("Comment");
+ println(" </tr>");
+
+ for(var i=0;i<user_names.length;i++) {
+ // Get user rid stored in "default" key
+ var user_rid=GetRegistryKeyValue(String().concat("\\SAM\\Domains\\Account\\Users\\Names\\",user_names[i]),"");
+ user_rid=RegistryKeyTypeToString(user_rid.type);
+ user_rid_dec=Number(user_rid).toString(10);
+
+ // Get user's V key and print various infos
+ user_rid=String(user_rid).substr(2); // Remove "0x"
+ var v_key=GetRegistryKeyValue(String().concat("\\SAM\\Domains\\Account\\Users\\",user_rid),"V");
+ var full_name=Get_v_info(v_key.value,0x18);
+ var comment=Get_v_info(v_key.value,0x24);
+ var home_dir=Get_v_info(v_key.value,0x48);
+ var home_dir_drive=Get_v_info(v_key.value,0x54);
+ var logon_script_path=Get_v_info(v_key.value,0x60);
+ var profile_path=Get_v_info(v_key.value,0x6c);
+
+ // Get user's F key and print various infos
+ var f_key=GetRegistryKeyValue(String().concat("\\SAM\\Domains\\Account\\Users\\",user_rid),"F");
+ var last_login_time=RegistryKeyValueToVariant(f_key.value,"filetime",8);
+ var last_pw_change=RegistryKeyValueToVariant(f_key.value,"filetime",24);
+ var last_failed_login=RegistryKeyValueToVariant(f_key.value,"filetime",40);
+ var account_expires=RegistryKeyValueToVariant(f_key.value,"filetime",32);
+ var total_logins=RegistryKeyValueToVariant(f_key.value,"uint16",66);
+ var failed_logins=RegistryKeyValueToVariant(f_key.value,"uint16",64);
+
+ var acc_flags=Number(RegistryKeyValueToVariant(f_key.value,"uint16",56));
+ var acc_flags_str="";
+ if(acc_flags&0x0200) acc_flags_str+="NoPwExpiry ";
+ if(acc_flags&0x0001) acc_flags_str+="Disabled ";
+ if(acc_flags&0x0004) acc_flags_str+="PwNotReq ";
+ if(acc_flags&0x0002) acc_flags_str+="HomeDirReq ";
+ if(acc_flags&0x0008) acc_flags_str+="TempDupAcc ";
+// if(acc_flags&0x0010) acc_flags_str+="NormUserAcc "; // I don't think this would be useful to show
+ if(acc_flags&0x0020) acc_flags_str+="MnsAcc ";
+ if(acc_flags&0x0040) acc_flags_str+="DomTrustAcc ";
+ if(acc_flags&0x0080) acc_flags_str+="WksTrustAcc ";
+ if(acc_flags&0x0100) acc_flags_str+="SrvTrustAcc ";
+ if(acc_flags&0x0400) acc_flags_str+="AccAutoLock ";
+
+ // Get password hint if available
+ var hint=GetRegistryKeyValue(String().concat("\\SAM\\Domains\\Account\\Users\\",user_rid),"UserPasswordHint");
+ if(IsValid(hint)) {
+ // Append missing trailing utf16 zero byte
+ hint.value.appendByte(0);
+ hint.value.appendByte(0);
+ hint=RegistryKeyValueToVariant(hint.value,"utf16");
+ } else {
+ hint="";
+ }
+
+ // TODO: User group membership
+
+ println (" <tr>");
+ PrintTableDataCell("left",user_names[i]);
+ PrintTableDataCell("right",String(user_rid_dec)+" (0x"+user_rid+")");
+ PrintTableDataCell("left",full_name);
+ PrintTableDataCell("right",last_login_time);
+ PrintTableDataCell("right",last_pw_change);
+ PrintTableDataCell("right",last_failed_login);
+ PrintTableDataCell("left",account_expires);
+ PrintTableDataCell("right",total_logins);
+ PrintTableDataCell("right",failed_logins);
+ PrintTableDataCell("left",acc_flags_str);
+ PrintTableDataCell("left",hint);
+ PrintTableDataCell("left",home_dir_drive+" "+home_dir);
+ PrintTableDataCell("left",logon_script_path);
+ PrintTableDataCell("left",profile_path);
+ PrintTableDataCell("left",comment);
+
+ println (" </tr>")
+ }
+ println(" </table>");
+ println("</p>");
+ } else {
+ println("<p><font color='red'>");
+ println(" Unable to enumerate users!<br />");
+ println(" Are you sure you are running this report against the correct registry hive?");
+ println("</font></p>");
+ }
+}
diff --git a/tags/fred-0.2.0/report_templates/SAM_UserAccounts_old.qs b/tags/fred-0.2.0/report_templates/SAM_UserAccounts_old.qs
new file mode 100644
index 0000000..c9be641
--- /dev/null
+++ b/tags/fred-0.2.0/report_templates/SAM_UserAccounts_old.qs
@@ -0,0 +1,104 @@
+function fred_report_info() {
+ var info={report_cat : "SAM",
+ report_name : "OLD - User accounts",
+ report_author : "Gillen Daniel",
+ report_desc : "Dump Windows user accounts",
+ fred_api : 2,
+ hive : "SAM"
+ };
+ return info;
+}
+
+function IsValid(val) {
+ if(typeof val !== 'undefined') return true;
+ else return false;
+}
+
+function print_table_row(cell01,cell02) {
+ println(" <tr><td>",cell01,"</td><td>",cell02,"</td></tr>");
+}
+
+function print_v_info(v_key_value,info_name,str_off) {
+ var offset=Number(RegistryKeyValueToVariant(v_key_value,"uint16",str_off))+0x0cc;
+ var len=Number(RegistryKeyValueToVariant(v_key_value,"uint16",str_off+4));
+ if(len>0) print_table_row(info_name,RegistryKeyValueToVariant(v_key_value,"utf16",offset,len));
+}
+
+function fred_report_html() {
+ // See http://windowsir.blogspot.com/2006/08/getting-user-info-from-image.html
+ println(" <h2>User accounts</h2>");
+
+ // Iterate over all user names
+ var user_names=GetRegistryNodes("\\SAM\\Domains\\Account\\Users\\Names");
+ if(IsValid(user_names)) {
+ for(var i=0;i<user_names.length;i++) {
+ println(" <p style=\"font-size:12; white-space:nowrap\">");
+
+ // Print user name
+ println(" <u>",user_names[i],"</u><br />");
+
+ println(" <table style=\"margin-left:20px; font-size:12\">");
+
+ // Get user rid stored in "default" key
+ var user_rid=GetRegistryKeyValue(String().concat("\\SAM\\Domains\\Account\\Users\\Names\\",user_names[i]),"");
+ user_rid=RegistryKeyTypeToString(user_rid.type);
+ println(" <tr><td>RID:</td><td>",Number(user_rid).toString(10)," (",user_rid,")","</td></tr>");
+
+ // RegistryKeyTypeToString returns the rid prepended with "0x". We have to remove that for further processing
+ user_rid=String(user_rid).substr(2);
+
+ // Get user's V key and print various infos
+ var v_key=GetRegistryKeyValue(String().concat("\\SAM\\Domains\\Account\\Users\\",user_rid),"V");
+ print_v_info(v_key.value,"Full name:",0x18);
+ print_v_info(v_key.value,"Comment:",0x24);
+ print_v_info(v_key.value,"Home directory:",0x48);
+ print_v_info(v_key.value,"Home directory drive:",0x54);
+ print_v_info(v_key.value,"Logon script path:",0x60);
+ print_v_info(v_key.value,"Profile path:",0x6c);
+
+ // Get user's F key and print various infos
+ var f_key=GetRegistryKeyValue(String().concat("\\SAM\\Domains\\Account\\Users\\",user_rid),"F");
+ print_table_row("Last login time:",RegistryKeyValueToVariant(f_key.value,"filetime",8));
+ print_table_row("Last pw change:",RegistryKeyValueToVariant(f_key.value,"filetime",24));
+ print_table_row("Last failed login:",RegistryKeyValueToVariant(f_key.value,"filetime",40));
+ print_table_row("Account expires:",RegistryKeyValueToVariant(f_key.value,"filetime",32));
+ print_table_row("Total logins:",RegistryKeyValueToVariant(f_key.value,"uint16",66));
+ print_table_row("Failed logins:",RegistryKeyValueToVariant(f_key.value,"uint16",64));
+ var acc_flags=Number(RegistryKeyValueToVariant(f_key.value,"uint16",56));
+ print(" <tr><td>Account flags:</td><td>");
+ if(acc_flags&0x0001) print("Disabled ");
+ if(acc_flags&0x0002) print("HomeDirReq ");
+ if(acc_flags&0x0004) print("PwNotReq ");
+ if(acc_flags&0x0008) print("TempDupAcc ");
+ // I don't think this would be useful to show
+ //if(acc_flags&0x0010) print("NormUserAcc ");
+ if(acc_flags&0x0020) print("MnsAcc ");
+ if(acc_flags&0x0040) print("DomTrustAcc ");
+ if(acc_flags&0x0080) print("WksTrustAcc ");
+ if(acc_flags&0x0100) print("SrvTrustAcc ");
+ if(acc_flags&0x0200) print("NoPwExpiry ");
+ if(acc_flags&0x0400) print("AccAutoLock ");
+ print(" (",acc_flags,")");
+ println("</td></tr>");
+
+ // Get password hint if available
+ var hint=GetRegistryKeyValue(String().concat("\\SAM\\Domains\\Account\\Users\\",user_rid),"UserPasswordHint");
+ if(typeof hint !== 'undefined') {
+ // Append missing trailing utf16 zero byte
+ hint.value.appendByte(0);
+ hint.value.appendByte(0);
+ print_table_row("Password hint:",RegistryKeyValueToVariant(hint.value,"utf16"));
+ }
+
+ // TODO: User group membership
+
+ println(" </table>");
+ println(" </p>");
+ }
+ } else {
+ println(" <p><font color='red'>");
+ println(" Unable to enumerate users!<br />");
+ println(" Are you sure you are running this report against the correct registry hive?");
+ println(" </font></p>");
+ }
+}
diff --git a/tags/fred-0.2.0/report_templates/SOFTWARE_Autoruns.qs b/tags/fred-0.2.0/report_templates/SOFTWARE_Autoruns.qs
new file mode 100644
index 0000000..2717b72
--- /dev/null
+++ b/tags/fred-0.2.0/report_templates/SOFTWARE_Autoruns.qs
@@ -0,0 +1,83 @@
+function fred_report_info() {
+ var info={report_cat : "SOFTWARE",
+ report_name : "Autoruns",
+ report_author : "Gillen Daniel",
+ report_desc : "Dump autoruns",
+ fred_api : 2,
+ hive : "SOFTWARE"
+ };
+ return info;
+}
+
+var table_style = "border-collapse:collapse; margin-left:20px; font-family:arial; font-size:12";
+var cell_style = "border:1px solid #888888; padding:5; white-space:nowrap;";
+
+function IsValid(val) {
+ return (typeof val!=='undefined');
+}
+
+function PrintTableHeaderCell(str) {
+ println(" <th style=\"",cell_style,"\">",str,"</th>");
+}
+
+function PrintTableDataCell(alignment,str) {
+ var style=cell_style+" text-align:"+alignment+";";
+ println(" <td style=\"",style,"\">",str,"</td>");
+}
+
+function PrintTableDataRowSpanCell(alignment,rows,str) {
+ var style=cell_style+" text-align: "+alignment+";";
+ println(" <td rowspan=\"",rows,"\" style=\"",style,"\">",str,"</td>");
+}
+
+function PrintTableDataColSpanCell(alignment,columns,str) {
+ var style=cell_style+" text-align: "+alignment+";";
+ println(" <td colspan=\"",columns,"\" style=\"",style,"\">",str,"</td>");
+}
+
+function ListAutoruns(autorun_path,autorun_key) {
+ var run_keys=GetRegistryKeys(autorun_path+autorun_key);
+ if(IsValid(run_keys) && run_keys.length>0) {
+ for(var i=0;i<run_keys.length;i++) {
+ var val=GetRegistryKeyValue(autorun_path+autorun_key,run_keys[i]);
+ println(" <tr>");
+ if(i==0) PrintTableDataRowSpanCell("left",run_keys.length,autorun_key);
+ PrintTableDataCell("left",run_keys[i]);
+ PrintTableDataCell("left",RegistryKeyValueToString(val.value,val.type));
+ println(" </tr>");
+ }
+ } else {
+ println(" <tr>");
+ PrintTableDataCell("left",autorun_key);
+ PrintTableDataColSpanCell("center",2,"None");
+ println(" </tr>");
+ }
+}
+
+function fred_report_html() {
+ var val;
+
+ println(" <h2>System Autoruns</h2>");
+ println(" <p style=\"font-size:12; white-space:nowrap\">");
+ println(" <table style=\""+table_style+"\">");
+
+ println(" <tr>");
+ PrintTableHeaderCell("Registry key");
+ PrintTableHeaderCell("Name");
+ PrintTableHeaderCell("Executable");
+ println(" </tr>");
+
+ // Run
+ ListAutoruns("\\Microsoft\\Windows\\CurrentVersion\\","Run");
+
+ // RunOnce
+ ListAutoruns("\\Microsoft\\Windows\\CurrentVersion\\","RunOnce");
+
+ // RunOnceEx
+ ListAutoruns("\\Microsoft\\Windows\\CurrentVersion\\","RunOnceEx");
+
+ // TODO: There might be a Run under WindowsNT\CurrentVersion\Run too!
+
+ println(" </table>");
+ println(" </p>");
+}
diff --git a/tags/fred-0.2.0/report_templates/SOFTWARE_ProfileList.qs b/tags/fred-0.2.0/report_templates/SOFTWARE_ProfileList.qs
new file mode 100644
index 0000000..87b50eb
--- /dev/null
+++ b/tags/fred-0.2.0/report_templates/SOFTWARE_ProfileList.qs
@@ -0,0 +1,68 @@
+function fred_report_info() {
+ var info={report_cat : "SOFTWARE",
+ report_name : "Profile list",
+ report_author : "Gillen Daniel",
+ report_desc : "Dump profile list",
+ fred_api : 2,
+ hive : "SOFTWARE"
+ };
+ return info;
+}
+
+var table_style = "border-collapse:collapse; margin-left:20px; font-family:arial; font-size:12";
+var cell_style = "border:1px solid #888888; padding:5; white-space:nowrap;";
+
+function IsValid(val) {
+ return (typeof val!=='undefined');
+}
+
+function PrintTableHeaderCell(str) {
+ println(" <th style=\"",cell_style,"\">",str,"</th>");
+}
+
+function PrintTableDataCell(alignment,str) {
+ var style=cell_style+" text-align:"+alignment+";";
+ println(" <td style=\"",style,"\">",str,"</td>");
+}
+
+function fred_report_html() {
+ var val;
+
+ println(" <h2>Profile List</h2>");
+
+ var profile_list=GetRegistryNodes("\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList");
+ if(IsValid(profile_list) && profile_list.length>0) {
+ println(" <p style=\"font-size:12; white-space:nowrap\">");
+ println(" <table style=\""+table_style+"\">");
+
+ println(" <tr>");
+ PrintTableHeaderCell("Profile ID");
+ PrintTableHeaderCell("Last load time");
+ PrintTableHeaderCell("Image path");
+ println(" </tr>");
+
+ for(var i=0;i<profile_list.length;i++) {
+ // Get profile image path
+ val=GetRegistryKeyValue("\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList\\"+profile_list[i],"ProfileImagePath");
+ var image_path=IsValid(val) ? RegistryKeyValueToString(val.value,val.type) : "n/a";
+
+ // Get last load time (Saved as 2 dwords. Another "good" idea of M$ ;-))
+ var loadtime_low=GetRegistryKeyValue("\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList\\"+profile_list[i],"ProfileLoadTimeLow");
+ var loadtime_high=GetRegistryKeyValue("\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList\\"+profile_list[i],"ProfileLoadTimeHigh");
+ var load_time=(IsValid(loadtime_low) && IsValid(loadtime_high)) ? RegistryKeyValueToVariant(loadtime_low.value.append(loadtime_high.value),"filetime",0) : "n/a";
+
+ // TODO: There is more to decode under \\Microsoft\\Windows NT\\CurrentVersion\\ProfileList
+
+ println(" <tr>");
+ PrintTableDataCell("left",profile_list[i]);
+ PrintTableDataCell("left",load_time);
+ PrintTableDataCell("left",image_path);
+ println(" </tr>");
+ }
+
+ println(" </table>");
+ println(" </p>");
+ } else {
+ println(" &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;None");
+ }
+}
diff --git a/tags/fred-0.2.0/report_templates/SOFTWARE_WindowsVersion.qs b/tags/fred-0.2.0/report_templates/SOFTWARE_WindowsVersion.qs
new file mode 100644
index 0000000..b2151f4
--- /dev/null
+++ b/tags/fred-0.2.0/report_templates/SOFTWARE_WindowsVersion.qs
@@ -0,0 +1,104 @@
+function fred_report_info() {
+ var info={report_cat : "SOFTWARE",
+ report_name : "Windows version",
+ report_author : "Gillen Daniel",
+ report_desc : "Dump Windows version info",
+ fred_api : 2,
+ hive : "SOFTWARE"
+ };
+ return info;
+}
+
+function IsValid(val) {
+ if(typeof val !== 'undefined') return true;
+ else return false;
+}
+
+function print_table_row(cell01,cell02) {
+ println(" <tr><td>",cell01,"</td><td>",cell02,"</td></tr>");
+}
+
+function DecodeProductKey(arr) {
+ //ProductKey is base24 encoded
+ var keychars=new Array("B","C","D","F","G","H","J","K","M","P","Q","R","T","V","W","X","Y","2","3","4","6","7","8","9");
+ var key=new Array(30);
+ var ret="";
+ var ncur;
+
+ if(arr.length<66) return ret;
+
+ arr=arr.mid(52,15);
+ for(var ilbyte=24;ilbyte>=0;ilbyte--) {
+ ncur=0;
+ for(var ilkeybyte=14;ilkeybyte>=0;ilkeybyte--) {
+ ncur=ncur*256^arr[ilkeybyte];
+ arr[ilkeybyte]=ncur/24;
+ ncur%=24;
+ }
+ ret=keychars[ncur]+ret;
+ if(ilbyte%5==0 && ilbyte!=0) ret="-"+ret;
+ }
+ return ret;
+}
+
+function fred_report_html() {
+ println(" <h2>Windows version info</h2>");
+
+ // Windows version sp and build info
+ var val=GetRegistryKeyValue("\\Microsoft\\Windows NT\\CurrentVersion","ProductName");
+ if(IsValid(val)) {
+ println(" <p style=\"font-size:12; white-space:nowrap\">");
+ println(" <table style=\"margin-left:20px; font-size:12; white-space:nowrap\">");
+
+ print(" <tr><td>Windows version:</td><td>",RegistryKeyValueToString(val.value,val.type));
+ var val=GetRegistryKeyValue("\\Microsoft\\Windows NT\\CurrentVersion","CSDVersion");
+ if(IsValid(val)) {
+ print(" ",RegistryKeyValueToString(val.value,val.type));
+ }
+ var val=GetRegistryKeyValue("\\Microsoft\\Windows NT\\CurrentVersion","CurrentBuildNumber");
+ if(IsValid(val)) {
+ print(" build ",RegistryKeyValueToString(val.value,val.type));
+ }
+ println("</td></tr>");
+ // Build string
+ var val=GetRegistryKeyValue("\\Microsoft\\Windows NT\\CurrentVersion","BuildLab");
+ print_table_row("Build string:",(IsValid(val)) ? RegistryKeyValueToString(val.value,val.type) : "n/a");
+ // Extended build string
+ var val=GetRegistryKeyValue("\\Microsoft\\Windows NT\\CurrentVersion","BuildLabEx");
+ print_table_row("Extended build string:",(IsValid(val)) ? RegistryKeyValueToString(val.value,val.type) : "n/a");
+
+ // Install date
+ var val=GetRegistryKeyValue("\\Microsoft\\Windows NT\\CurrentVersion","InstallDate");
+ print_table_row("Install date:",(IsValid(val)) ? RegistryKeyValueToVariant(val.value,"unixtime") : "n/a");
+
+ // Owner and Organization info
+ var val=GetRegistryKeyValue("\\Microsoft\\Windows NT\\CurrentVersion","RegisteredOwner");
+ print_table_row("Registered owner:",(IsValid(val)) ? RegistryKeyValueToString(val.value,val.type) : "n/a");
+ var val=GetRegistryKeyValue("\\Microsoft\\Windows NT\\CurrentVersion","RegisteredOrganization");
+ print_table_row("Registered organization:",(IsValid(val)) ? RegistryKeyValueToString(val.value,val.type) : "n/a");
+
+ // Windows ID / Key
+ var val=GetRegistryKeyValue("\\Microsoft\\Windows NT\\CurrentVersion","ProductId");
+ print_table_row("Product ID:",(IsValid(val)) ? RegistryKeyValueToString(val.value,val.type) : "n/a");
+ var val=GetRegistryKeyValue("\\Microsoft\\Windows NT\\CurrentVersion","DigitalProductId");
+ if(IsValid(val)) {
+ var key=DecodeProductKey(val.value);
+ if(key!="BBBBB-BBBBB-BBBBB-BBBBB-BBBBB") print_table_row("Product Key:",key);
+ else print_table_row("Product Key:","n/a (Probably a volume license key was used)");
+ } else print_table_row("Product Key:","n/a");
+
+ // Install directory / Source directory
+ var val=GetRegistryKeyValue("\\Microsoft\\Windows NT\\CurrentVersion","PathName");
+ print_table_row("Install path:",(IsValid(val)) ? RegistryKeyValueToString(val.value,val.type) : "n/a");
+ var val=GetRegistryKeyValue("\\Microsoft\\Windows NT\\CurrentVersion","SourcePath");
+ print_table_row("Source path:",(IsValid(val)) ? RegistryKeyValueToString(val.value,val.type) : "n/a");
+
+ println(" </table>");
+ println(" </p>");
+ } else {
+ println(" <p><font color='red'>");
+ println(" Unable to get product name!<br />");
+ println(" Are you sure you are running this report against the correct registry hive?");
+ println(" </font></p>");
+ }
+}
diff --git a/tags/fred-0.2.0/report_templates/SYSTEM_BackupRestore.qs b/tags/fred-0.2.0/report_templates/SYSTEM_BackupRestore.qs
new file mode 100644
index 0000000..ea77769
--- /dev/null
+++ b/tags/fred-0.2.0/report_templates/SYSTEM_BackupRestore.qs
@@ -0,0 +1,104 @@
+function fred_report_info() {
+ var info={report_cat : "SYSTEM",
+ report_name : "Backup / Restore settings",
+ report_author : "Gillen Daniel",
+ report_desc : "Dump files / directories not to snapshot / backup and registry keys not to restore",
+ fred_api : 2,
+ hive : "SYSTEM"
+ };
+ return info;
+}
+
+var table_style = "border-collapse:collapse; margin-left:20px; font-family:arial; font-size:12";
+var cell_style = "border:1px solid #888888; padding:5; white-space:nowrap;";
+
+function IsValid(val) {
+ return (typeof val!=='undefined');
+}
+
+function PrintTableHeaderCell(str) {
+ println(" <th style=\"",cell_style,"\">",str,"</th>");
+}
+
+function PrintTableDataCell(alignment,str) {
+ var style=cell_style+" text-align:"+alignment+";";
+ println(" <td style=\"",style,"\">",str,"</td>");
+}
+
+function PrintTableDataRowSpanCell(alignment,rows,str) {
+ var style=cell_style+" text-align: "+alignment+";";
+ println(" <td rowspan=\"",rows,"\" style=\"",style,"\">",str,"</td>");
+}
+
+function ListValues(root_key) {
+ var values=GetRegistryKeys(root_key);
+ if(IsValid(values)) {
+ println(" <p style=\"font-size:12; white-space:nowrap\">");
+ println(" <table style=\""+table_style+"\">");
+ println(" <tr>");
+ PrintTableHeaderCell("Name");
+ PrintTableHeaderCell("Directory(ies) / File(s)");
+ println(" </tr>");
+ for(var i=0;i<values.length;i++) {
+ var val=GetRegistryKeyValue(root_key,values[i]);
+ if(IsValid(val)) {
+ var strings=RegistryKeyValueToStringList(val.value);
+ if(strings.length>1) {
+ println(" <tr>");
+ PrintTableDataRowSpanCell("left",strings.length,values[i]);
+ PrintTableDataCell("left",strings[0]);
+ println(" </tr>");
+ for(var ii=1;ii<strings.length;ii++) {
+ println(" <tr>");
+ PrintTableDataCell("left",strings[ii]);
+ println(" </tr>");
+ }
+ } else {
+ println(" <tr>");
+ PrintTableDataCell("left",values[i]);
+ PrintTableDataCell("left",strings.length!=0 ? strings[0] : "");
+ println(" </tr>");
+ }
+ }
+ }
+ println(" </table>");
+ println(" </p>");
+ } else {
+ println(" <p style=\"font-size:12; white-space:nowrap; margin-left:20px;\">");
+ println(" None");
+ println(" </p>");
+ }
+}
+
+function fred_report_html() {
+ var val;
+
+ println(" <h2>Backup / Restore settings</h2>");
+
+ // Get current controlset
+ var cur_controlset=GetRegistryKeyValue("\\Select","Current");
+ if(IsValid(cur_controlset)) {
+ cur_controlset=RegistryKeyValueToString(cur_controlset.value,cur_controlset.type);
+ // Current holds a DWORD value, thus we get a string like 0x00000000, but
+ // control sets are referenced only with the last 3 digits.
+ cur_controlset="ControlSet"+String(cur_controlset).substr(7,3);
+
+ println(" <p style=\"font-size:12; white-space:nowrap\">");
+ println(" <u>Directories / files not to back up in Volume Shadow Copies</u>");
+ println(" </p>");
+ ListValues(cur_controlset+"\\Control\\BackupRestore\\FilesNotToSnapshot");
+ println(" <p style=\"font-size:12; white-space:nowrap\">");
+ println(" <u>Directories / files not to back up or restore by backup apps</u>");
+ println(" </p>");
+ ListValues(cur_controlset+"\\Control\\BackupRestore\\FilesNotToBackup");
+ println(" <p style=\"font-size:12; white-space:nowrap\">");
+ println(" <u>Registry nodes or values not to restore by backup apps</u>");
+ println(" </p>");
+ ListValues(cur_controlset+"\\Control\\BackupRestore\\KeysNotToRestore");
+ } else {
+ println(" <p><font color='red'>");
+ println(" Unable to determine current control set!<br />");
+ println(" Are you sure you are running this report against the correct registry hive?");
+ println(" </font></p>");
+ }
+}
diff --git a/tags/fred-0.2.0/report_templates/SYSTEM_CurrentNetworkSettings.qs b/tags/fred-0.2.0/report_templates/SYSTEM_CurrentNetworkSettings.qs
new file mode 100644
index 0000000..19eea09
--- /dev/null
+++ b/tags/fred-0.2.0/report_templates/SYSTEM_CurrentNetworkSettings.qs
@@ -0,0 +1,169 @@
+function fred_report_info() {
+ var info={report_cat : "SYSTEM",
+ report_name : "Current network settings",
+ report_author : "Gillen Daniel",
+ report_desc : "Dump current network settings",
+ fred_api : 2,
+ hive : "SYSTEM"
+ };
+ return info;
+}
+
+var table_style = "border-collapse:collapse; margin-left:20px; font-family:arial; font-size:12";
+var cell_style = "border:1px solid #888888; padding:5; white-space:nowrap;";
+
+function IsValid(val) {
+ return (typeof val!=='undefined');
+}
+
+function PrintTableHeaderCell(str) {
+ println(" <th style=\"",cell_style,"\">",str,"</th>");
+}
+
+function PrintTableDataCell(alignment,str) {
+ var style=cell_style+" text-align:"+alignment+";";
+ println(" <td style=\"",style,"\">",str,"</td>");
+}
+
+function ZeroPad(number,padlen) {
+ var ret=number.toString(10);
+ if(!padlen || ret.length>=padlen) return ret;
+ return Math.pow(10,padlen-ret.length).toString().slice(1)+ret;
+}
+
+function fred_report_html() {
+ // See Appendix A: TCP/IP Configuration Parameters:
+ // http://technet.microsoft.com/de-de/library/cc739819%28v=WS.10%29.aspx
+ var val;
+
+ println(" <h2>Current network settings (Tcp/Ip)</h2>");
+
+ // Get current controlset
+ var cur_controlset=GetRegistryKeyValue("\\Select","Current");
+ if(IsValid(cur_controlset)) {
+ cur_controlset=RegistryKeyValueToString(cur_controlset.value,cur_controlset.type);
+ // Current holds a DWORD value, thus we get a string like 0x00000000, but
+ // control sets are referenced by its decimal representation.
+ cur_controlset="ControlSet"+ZeroPad(parseInt(String(cur_controlset).substr(2,8),16),3)
+
+ // Computer name
+ val=GetRegistryKeyValue(cur_controlset+"\\Control\\ComputerName\\ComputerName","ComputerName");
+
+ println(" <p style=\"font-size:12; white-space:nowrap\">");
+ println(" <table style=\""+table_style+"\">");
+ println(" <tr><td>Active control set:</td><td>",cur_controlset,"</td></tr>");
+ println(" <tr><td>Computer name:</td><td>",(IsValid(val)) ? RegistryKeyValueToString(val.value,val.type) : "","</td></tr>");
+ println(" </table>");
+ println(" <br />");
+ println(" <table style=\""+table_style+"\">");
+ println(" <tr>");
+ PrintTableHeaderCell("Adapter");
+ PrintTableHeaderCell("Configuration");
+ PrintTableHeaderCell("IP address");
+ PrintTableHeaderCell("Subnet mask");
+ PrintTableHeaderCell("Nameserver(s)");
+ PrintTableHeaderCell("Domain");
+ PrintTableHeaderCell("Default gateway");
+ PrintTableHeaderCell("DHCP server");
+ PrintTableHeaderCell("DHCP lease optained");
+ PrintTableHeaderCell("DHCP lease terminates");
+ println(" </tr>");
+
+ // Iterate over all available network adapters
+ var adapters=GetRegistryNodes(cur_controlset+"\\Services\\Tcpip\\Parameters\\Adapters");
+ for(var i=0;i<adapters.length;i++) {
+ // Try to get a human readable name
+ // According to http://technet.microsoft.com/de-de/library/cc780532%28v=ws.10%29.aspx
+ // the {4D36E972-E325-11CE-BFC1-08002BE10318} key name might be (and hopefully is) static :)
+ val=GetRegistryKeyValue(cur_controlset+"\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}\\"+adapters[i]+"\\Connection","Name");
+ var adapter_name=IsValid(val) ? RegistryKeyValueToString(val.value,val.type) : adapters[i];
+
+ // Get settings node
+ val=GetRegistryKeyValue(cur_controlset+"\\Services\\Tcpip\\Parameters\\Adapters\\"+adapters[i],"IpConfig");
+ var adapter_settings_node=RegistryKeyValueToVariant(val.value,"utf16",0);
+
+ // Get configuration mode
+ val=GetRegistryKeyValue(cur_controlset+"\\Services\\"+adapter_settings_node,"EnableDHCP");
+ var dhcp_enabled=Number(RegistryKeyValueToString(val.value,val.type));
+
+ var ip_address="";
+ var subnet_mask="";
+ var nameservers="";
+ var domain="";
+ var default_gateway="";
+ var dhcp_server="";
+ var lease_obtained="";
+ var lease_terminates="";
+
+ if(dhcp_enabled) {
+ // DHCP server
+ val=GetRegistryKeyValue(cur_controlset+"\\Services\\"+adapter_settings_node,"DhcpServer");
+ dhcp_server=(IsValid(val)) ? RegistryKeyValueToString(val.value,val.type) : "";
+ // IP address
+ val=GetRegistryKeyValue(cur_controlset+"\\Services\\"+adapter_settings_node,"DhcpIPAddress");
+ ip_address=(IsValid(val)) ? RegistryKeyValueToString(val.value,val.type) : "";
+ // Subnet mask
+ val=GetRegistryKeyValue(cur_controlset+"\\Services\\"+adapter_settings_node,"DhcpSubnetMask");
+ subnet_mask=(IsValid(val)) ? RegistryKeyValueToString(val.value,val.type) : "";
+ // Nameserver(s)
+ val=GetRegistryKeyValue(cur_controlset+"\\Services\\"+adapter_settings_node,"DhcpNameServer");
+ nameservers=(IsValid(val)) ? RegistryKeyValueToString(val.value,val.type) : "";
+ // Domain
+ val=GetRegistryKeyValue(cur_controlset+"\\Services\\"+adapter_settings_node,"DhcpDomain");
+ domain=(IsValid(val)) ? RegistryKeyValueToString(val.value,val.type) : "";
+ // Default gw
+ val=GetRegistryKeyValue(cur_controlset+"\\Services\\"+adapter_settings_node,"DhcpDefaultGateway");
+ default_gateway=(IsValid(val)) ? RegistryKeyValueToVariant(val.value,"utf16",0) : "";
+ // Lease obtained
+ val=GetRegistryKeyValue(cur_controlset+"\\Services\\"+adapter_settings_node,"LeaseObtainedTime");
+ lease_obtained=(IsValid(val)) ? RegistryKeyValueToVariant(val.value,"unixtime",0) : "";
+ // Lease valid until
+ val=GetRegistryKeyValue(cur_controlset+"\\Services\\"+adapter_settings_node,"LeaseTerminatesTime");
+ lease_terminates=(IsValid(val)) ? RegistryKeyValueToVariant(val.value,"unixtime",0) : "";
+ } else {
+ // IP address
+ val=GetRegistryKeyValue(cur_controlset+"\\Services\\"+adapter_settings_node,"IPAddress");
+ ip_address=(IsValid(val)) ? RegistryKeyValueToVariant(val.value,"utf16",0) : "";
+ // Subnet mask
+ val=GetRegistryKeyValue(cur_controlset+"\\Services\\"+adapter_settings_node,"SubnetMask");
+ subnet_mask=(IsValid(val)) ? RegistryKeyValueToVariant(val.value,"utf16",0) : "";
+ // Nameserver
+ val=GetRegistryKeyValue(cur_controlset+"\\Services\\"+adapter_settings_node,"NameServer");
+ nameservers=(IsValid(val)) ? RegistryKeyValueToVariant(val.value,"utf16",0) : "";
+ // Domain
+ val=GetRegistryKeyValue(cur_controlset+"\\Services\\"+adapter_settings_node,"Domain");
+ domain=(IsValid(val)) ? RegistryKeyValueToString(val.value,val.type) : "";
+ // Default gw
+ val=GetRegistryKeyValue(cur_controlset+"\\Services\\"+adapter_settings_node,"DefaultGateway");
+ default_gateway=(IsValid(val)) ? RegistryKeyValueToVariant(val.value,"utf16",0) : "";
+ dhcp_server="n/a";
+ lease_obtained="n/a";
+ lease_terminates="n/a";
+ }
+
+ println(" <tr>");
+ PrintTableDataCell("left",adapter_name);
+ PrintTableDataCell("left",dhcp_enabled ? "DHCP" : "Static");
+ PrintTableDataCell("left",ip_address);
+ PrintTableDataCell("left",subnet_mask);
+ PrintTableDataCell("left",nameservers);
+ PrintTableDataCell("left",domain);
+ PrintTableDataCell("left",default_gateway);
+ PrintTableDataCell("left",dhcp_server);
+ PrintTableDataCell("left",lease_obtained);
+ PrintTableDataCell("left",lease_terminates);
+ println(" </tr>");
+
+ // TODO: Check for EnableSecurityFilters, TCPAllowedPorts and UDPAllowedPorts to get firewall status.
+
+ // TODO: Get persistent routes from \ControlSet001\Services\Tcpip\Parameters\PersistentRoutes
+ }
+ println(" </table>");
+ println(" </p>");
+ } else {
+ println(" <p><font color='red'>");
+ println(" Unable to determine current control set!<br />");
+ println(" Are you sure you are running this report against the correct registry hive?");
+ println(" </font></p>");
+ }
+}
diff --git a/tags/fred-0.2.0/report_templates/SYSTEM_Services.qs b/tags/fred-0.2.0/report_templates/SYSTEM_Services.qs
new file mode 100644
index 0000000..408ed29
--- /dev/null
+++ b/tags/fred-0.2.0/report_templates/SYSTEM_Services.qs
@@ -0,0 +1,131 @@
+function fred_report_info() {
+ var info={report_cat : "SYSTEM",
+ report_name : "Services",
+ report_author : "Gillen Daniel",
+ report_desc : "Dump services",
+ fred_api : 2,
+ hive : "SYSTEM"
+ };
+ return info;
+}
+
+var table_style = "border-collapse:collapse; margin-left:20px; font-family:arial; font-size:12";
+var cell_style = "border:1px solid #888888; padding:5; white-space:nowrap;";
+
+function IsValid(val) {
+ return (typeof val!=='undefined');
+}
+
+function PrintTableHeaderCell(str) {
+ println(" <th style=\"",cell_style,"\">",str,"</th>");
+}
+
+function PrintTableDataCell(alignment,str) {
+ var style=cell_style+" text-align:"+alignment+";";
+ println(" <td style=\"",style,"\">",str,"</td>");
+}
+
+function ZeroPad(number,padlen) {
+ var ret=number.toString(10);
+ if(!padlen || ret.length>=padlen) return ret;
+ return Math.pow(10,padlen-ret.length).toString().slice(1)+ret;
+}
+
+function PrintTableRow(cell01,cell02,cell03,cell04,cell05) {
+ println(" <tr>");
+ PrintTableDataCell("left",cell01);
+ PrintTableDataCell("left",cell02);
+ PrintTableDataCell("left",cell03);
+ PrintTableDataCell("left",cell04);
+ PrintTableDataCell("left",cell05);
+ println(" </tr>");
+}
+
+function ListService(service_node) {
+ // Service name
+ var name=GetRegistryKeyValue(service_node,"DisplayName");
+ name=(IsValid(name)) ? RegistryKeyValueToString(name.value,name.type) : "Unknwon";
+ // Service group
+ var group=GetRegistryKeyValue(service_node,"Group");
+ group=(IsValid(group)) ? RegistryKeyValueToString(group.value,group.type) : "";
+ // Service exe
+ var image=GetRegistryKeyValue(service_node,"ImagePath");
+ image=(IsValid(image)) ? RegistryKeyValueToString(image.value,image.type) : "Unknwon";
+ // Start
+ var start=GetRegistryKeyValue(service_node,"Start");
+ start=(IsValid(start)) ? RegistryKeyValueToString(start.value,start.type) : -1;
+ switch(Number(start)) {
+ case 0:
+ start="Boot";
+ break;
+ case 1:
+ start="System";
+ break;
+ case 2:
+ start="Automatic";
+ break;
+ case 3:
+ start="Manual";
+ break;
+ case 4:
+ start="Disabled";
+ break;
+ default:
+ start="Unknown";
+ }
+ // Description
+ var desc=GetRegistryKeyValue(service_node,"Description");
+ desc=(IsValid(desc)) ? RegistryKeyValueToString(desc.value,desc.type) : "";
+
+ PrintTableRow(name,group,start,image,desc)
+}
+
+function fred_report_html() {
+ var val;
+
+ println(" <h2>Services</h2>");
+
+ // Get current controlset
+ var cur_controlset=GetRegistryKeyValue("\\Select","Current");
+ if(IsValid(cur_controlset)) {
+ cur_controlset=RegistryKeyValueToString(cur_controlset.value,cur_controlset.type);
+ // Current holds a DWORD value, thus we get a string like 0x00000000, but
+ // control sets are referenced by its decimal representation.
+ cur_controlset="ControlSet"+ZeroPad(parseInt(String(cur_controlset).substr(2,8),16),3)
+
+ // Get list of possible services
+ var services=GetRegistryNodes(cur_controlset+"\\Services");
+ if(IsValid(services)) {
+ println(" <p style=\"font-size:12; white-space:nowrap\">");
+ println(" <table style=\""+table_style+"\">");
+ println(" <tr>");
+ PrintTableHeaderCell("Name");
+ PrintTableHeaderCell("Group");
+ PrintTableHeaderCell("Startup");
+ PrintTableHeaderCell("Image path");
+ PrintTableHeaderCell("Description");
+ println(" </tr>");
+
+ for(var i=0;i<services.length;i++) {
+ // Get service type
+ val=GetRegistryKeyValue(cur_controlset+"\\Services\\"+services[i],"Type");
+ if(!IsValid(val)) continue;
+ val=RegistryKeyValueToString(val.value,val.type);
+ if(Number(val)!=16 && Number(val)!=32) continue;
+ ListService(cur_controlset+"\\Services\\"+services[i]);
+ }
+
+ println(" </table>");
+ println(" </p>");
+ } else {
+ println(" <p><font color='red'>");
+ println(" This registry hive does not contain any services!<br />");
+ println(" </font></p>");
+ }
+ } else {
+ println(" <p><font color='red'>");
+ println(" Unable to determine current control set!<br />");
+ println(" Are you sure you are running this report against the correct registry hive?");
+ println(" </font></p>");
+ }
+}
diff --git a/tags/fred-0.2.0/report_templates/SYSTEM_ShutdownTime.qs b/tags/fred-0.2.0/report_templates/SYSTEM_ShutdownTime.qs
new file mode 100644
index 0000000..1e5ce77
--- /dev/null
+++ b/tags/fred-0.2.0/report_templates/SYSTEM_ShutdownTime.qs
@@ -0,0 +1,52 @@
+function fred_report_info() {
+ var info={report_cat : "SYSTEM",
+ report_name : "Shutdown time",
+ report_author : "Gillen Daniel",
+ report_desc : "Dump last known shutdown time",
+ fred_api : 2,
+ hive : "SYSTEM"
+ };
+ return info;
+}
+
+function IsValid(val) {
+ if(typeof val !== 'undefined') return true;
+ else return false;
+}
+
+function print_table_row(cell01,cell02) {
+ println(" <tr><td>",cell01,"</td><td>",cell02,"</td></tr>");
+}
+
+function fred_report_html() {
+ var val;
+
+ println(" <h2>Last known shutdown time</h2>");
+
+ // Get current controlset
+ var cur_controlset=GetRegistryKeyValue("\\Select","Current");
+ if(IsValid(cur_controlset)) {
+ cur_controlset=RegistryKeyValueToString(cur_controlset.value,cur_controlset.type);
+ // Current holds a DWORD value, thus we get a string like 0x00000000, but
+ // control sets are referenced only with the last 3 digits.
+ cur_controlset="ControlSet"+String(cur_controlset).substr(7,3);
+
+ println(" <p style=\"font-size:12; white-space:nowrap\">");
+ println(" <table style=\"margin-left:20px; font-size:12; white-space:nowrap\">");
+
+ print_table_row("Active control set:",cur_controlset);
+
+ // Shutdown time
+ val=GetRegistryKeyValue(cur_controlset+"\\Control\\Windows","ShutdownTime");
+ print_table_row("Shutdown time:",(IsValid(val)) ? RegistryKeyValueToVariant(val.value,"filetime") : "Unknown");
+
+ println(" </table>");
+ println(" <br />");
+ println(" </p>");
+ } else {
+ println(" <p><font color='red'>");
+ println(" Unable to determine current control set!<br />");
+ println(" Are you sure you are running this report against the correct registry hive?");
+ println(" </font></p>");
+ }
+}
diff --git a/tags/fred-0.2.0/report_templates/SYSTEM_SystemTimeInfo.qs b/tags/fred-0.2.0/report_templates/SYSTEM_SystemTimeInfo.qs
new file mode 100644
index 0000000..9f7c3cb
--- /dev/null
+++ b/tags/fred-0.2.0/report_templates/SYSTEM_SystemTimeInfo.qs
@@ -0,0 +1,141 @@
+function fred_report_info() {
+ var info={report_cat : "SYSTEM",
+ report_name : "System time info",
+ report_author : "Gillen Daniel",
+ report_desc : "Dump system time info",
+ fred_api : 2,
+ hive : "SYSTEM"
+ };
+ return info;
+}
+
+var table_style = "border-collapse:collapse; margin-left:20px; font-family:arial; font-size:12";
+var cell_style = "border:1px solid #888888; padding:5; white-space:nowrap;";
+
+function IsValid(val) {
+ return (typeof val!=='undefined');
+}
+
+function PrintTableHeaderCell(str) {
+ println(" <th style=\"",cell_style,"\">",str,"</th>");
+}
+
+function PrintTableDataCell(alignment,str) {
+ var style=cell_style+" text-align:"+alignment+";";
+ println(" <td style=\"",style,"\">",str,"</td>");
+}
+
+function ToUTC(num) {
+ var retnum=new Number(num);
+ if(retnum&0x80000000) {
+ retnum=((0xFFFFFFFF-retnum)+1)/60;
+ return "UTC+"+Number(retnum).toString(10);
+ } else {
+ retnum=retnum/60;
+ if(retnum!=0) return "UTC-"+Number(retnum).toString(10);
+ else return "UTC+"+Number(retnum).toString(10);
+ }
+}
+
+function ZeroPad(number,padlen) {
+ var ret=number.toString(10);
+ if(!padlen || ret.length>=padlen) return ret;
+ return Math.pow(10,padlen-ret.length).toString().slice(1)+ret;
+}
+
+function fred_report_html() {
+ var val;
+
+ println(" <h2>System time info</h2>");
+
+ // Get current controlset
+ var cur_controlset=GetRegistryKeyValue("\\Select","Current");
+ if(IsValid(cur_controlset)) {
+ cur_controlset=RegistryKeyValueToString(cur_controlset.value,cur_controlset.type);
+ // Current holds a DWORD value, thus we get a string like 0x00000000, but
+ // control sets are referenced by its decimal representation.
+ cur_controlset="ControlSet"+ZeroPad(parseInt(String(cur_controlset).substr(2,8),16),3)
+
+ // Get W32Time service settings
+ var w32time_startup_method="n/a";
+ var w32time_time_servers="n/a";
+ val=GetRegistryKeyValue(cur_controlset+"\\Services\\W32Time","Start");
+ if(IsValid(val)) {
+ val=RegistryKeyValueToString(val.value,val.type);
+ switch(Number(val)) {
+ case 0:
+ w32time_startup_method="Boot";
+ break;
+ case 1:
+ w32time_startup_method="System";
+ break;
+ case 2:
+ w32time_startup_method="Automatic";
+ break;
+ case 3:
+ w32time_startup_method="Manual";
+ break;
+ case 4:
+ w32time_startup_method="Disabled";
+ break;
+ default:
+ w32time_startup_method="Unknown";
+ }
+ // If service is enabled, get ntp server
+ if(Number(val)<4) {
+ val=GetRegistryKeyValue(cur_controlset+"\\Services\\W32Time\\Parameters","NtpServer");
+ if(IsValid(val)) w32time_time_servers=RegistryKeyValueToString(val.value,val.type);
+ }
+ }
+
+ println(" <p style=\"font-size:12; white-space:nowrap\">");
+ println(" <table style=\""+table_style+"\">");
+ println(" <tr><td>Active control set:</td><td>",cur_controlset,"</td></tr>");
+ println(" <tr><td>W32Time startup method:</td><td>",w32time_startup_method,"</td></tr>");
+ println(" <tr><td>W32Time NTP servers:</td><td>",w32time_time_servers,"</td></tr>");
+ println(" </table>");
+ println(" <br />");
+ println(" <table style=\""+table_style+"\">");
+ println(" <tr>");
+ PrintTableHeaderCell("Setting name");
+ PrintTableHeaderCell("Time zone");
+ println(" </tr>");
+
+ // Active time bias
+ val=GetRegistryKeyValue(cur_controlset+"\\Control\\TimeZoneInformation","ActiveTimeBias");
+ var active_bias=(IsValid(val)) ? ToUTC(RegistryKeyValueToString(val.value,val.type)) : "n/a"
+
+ // Std. tz name and bias
+ val=GetRegistryKeyValue(cur_controlset+"\\Control\\TimeZoneInformation","StandardName");
+ var std_name=(IsValid(val)) ? RegistryKeyValueToString(val.value,val.type) : "n/a";
+ val=GetRegistryKeyValue(cur_controlset+"\\Control\\TimeZoneInformation","StandardBias");
+ var std_bias=(IsValid(val)) ? ToUTC(RegistryKeyValueToString(val.value,val.type)) : "n/a";
+
+ // Daylight tz name and bias
+ val=GetRegistryKeyValue(cur_controlset+"\\Control\\TimeZoneInformation","DaylightName");
+ var daylight_name=(IsValid(val)) ? RegistryKeyValueToString(val.value,val.type) : "n/a";
+ val=GetRegistryKeyValue(cur_controlset+"\\Control\\TimeZoneInformation","DaylightBias");
+ var daylight_bias=(IsValid(val)) ? ToUTC(RegistryKeyValueToString(val.value,val.type)) : "n/a";
+
+ println(" <tr>");
+ PrintTableDataCell("left","Active");
+ PrintTableDataCell("left",active_bias);
+ println(" </tr>");
+ println(" <tr>");
+ PrintTableDataCell("left","Standard");
+ PrintTableDataCell("left",std_bias+" ("+std_name+")");
+ println(" </tr>");
+ println(" <tr>");
+ PrintTableDataCell("left","Daylight");
+ PrintTableDataCell("left",daylight_bias+" ("+daylight_name+")");
+ println(" </tr>");
+
+ println(" </table>");
+ println(" </p>");
+ } else {
+ println(" <p><font color='red'>");
+ println(" Unable to determine current control set!<br />");
+ println(" Are you sure you are running this report against the correct registry hive?");
+ println(" </font></p>");
+ }
+}
diff --git a/tags/fred-0.2.0/report_templates/SYSTEM_UsbStorageDevices.qs b/tags/fred-0.2.0/report_templates/SYSTEM_UsbStorageDevices.qs
new file mode 100644
index 0000000..9e42186
--- /dev/null
+++ b/tags/fred-0.2.0/report_templates/SYSTEM_UsbStorageDevices.qs
@@ -0,0 +1,199 @@
+function fred_report_info() {
+ var info={report_cat : "SYSTEM",
+ report_name : "USB storage devices",
+ report_author : "Gillen Daniel, Voncken Guy",
+ report_desc : "Dump USB storage devices",
+ fred_api : 2,
+ hive : "SYSTEM"
+ };
+ return info;
+}
+
+var table_style = "border-collapse:collapse; margin-left:20px; font-family:arial; font-size:12";
+var cell_style = "border:1px solid #888888; padding:5; white-space:nowrap;";
+
+function IsValid(val) {
+ return (typeof val!=='undefined');
+}
+
+function PrintTableHeaderCell(str) {
+ println(" <th style=\"",cell_style,"\">",str,"</th>");
+}
+
+function PrintTableDataCell(alignment,str) {
+ var style=cell_style+" text-align:"+alignment+";";
+ println(" <td style=\"",style,"\">",str,"</td>");
+}
+
+function PrintTableDataRowSpanCell(alignment,rows,str) {
+ var style=cell_style+" text-align: "+alignment+";";
+ println(" <td rowspan=\"",rows,"\" style=\"",style,"\">",str,"</td>");
+}
+
+function ZeroPad(number,padlen) {
+ var ret=number.toString(10);
+ if(!padlen || ret.length>=padlen) return ret;
+ return Math.pow(10,padlen-ret.length).toString().slice(1)+ret;
+}
+
+function GetKeyVal(path, key) {
+ var val=GetRegistryKeyValue(path, key);
+ return (IsValid(val)) ? RegistryKeyValueToString(val.value,val.type) : "";
+}
+
+function fred_report_html() {
+ // TODO: There is more here.
+ // Check http://www.forensicswiki.org/wiki/USB_History_Viewing
+ var val;
+
+ println(" <h2>USB storage devices</h2>");
+
+ // Preload MountedDevices to possibly identify mount points of USB storage
+ // devices
+ var mnt_keys=GetRegistryKeys("\\MountedDevices");
+ var mnt_values=new Array();
+ if(IsValid(mnt_keys)) {
+ for(var i=0;i<mnt_keys.length;i++) {
+ val=GetRegistryKeyValue("\\MountedDevices",mnt_keys[i]);
+ mnt_values[i]=RegistryKeyValueToVariant(val.value,"utf16");
+ }
+ }
+
+ // Get current controlset
+ var cur_controlset=GetRegistryKeyValue("\\Select","Current");
+ if(IsValid(cur_controlset)) {
+ cur_controlset=RegistryKeyValueToString(cur_controlset.value,
+ cur_controlset.type);
+ // Current holds a DWORD value, thus we get a string like 0x00000000, but
+ // control sets are referenced by its decimal representation.
+ cur_controlset="ControlSet"+
+ ZeroPad(parseInt(String(cur_controlset).substr(2,8),16),3);
+
+ println(" <p style=\"font-size:12; white-space:nowrap\">");
+ println(" <table style=\""+table_style+"\">");
+
+ // Are USB storage devices enabled?
+ // http://www.forensicmag.com/article/windows-7-registry-forensics-part-5
+ // Is this true for WinXP etc.. ???
+ var val=GetRegistryKeyValue(cur_controlset+"\\services\\USBSTOR","Start");
+ if(IsValid(val)) {
+ val=RegistryKeyValueToString(val.value,val.type);
+ val=parseInt(String(val).substr(2,8),10);
+ switch(val) {
+ case 3:
+ println(" <tr><td>Storage driver enabled:</td><td>Yes</td></tr>");
+ break;
+ case 4:
+ println(" <tr><td>Storage driver enabled:</td><td>No</td></tr>");
+ break;
+ default:
+ println(" <tr><td>Storage driver enabled:</td><td>Unknown</td></tr>");
+ }
+ } else {
+ println(" <tr><td>Storage driver enabled:</td><td>Unknown</td></tr>");
+ }
+
+ println(" </table>");
+ println(" </p>");
+ println(" <p style=\"font-size:12; white-space:nowrap\">");
+
+ var storage_roots=GetRegistryNodes(cur_controlset+"\\Enum\\USBSTOR");
+ if(IsValid(storage_roots)) {
+ println(" <table style=\""+table_style+"\">");
+ println(" <tr>");
+ PrintTableHeaderCell("Vendor Name");
+ PrintTableHeaderCell("Unique ID");
+ PrintTableHeaderCell("Class");
+ PrintTableHeaderCell("Friendly name");
+ PrintTableHeaderCell("Mount point(s)");
+ PrintTableHeaderCell("Parent ID");
+ PrintTableHeaderCell("Device description");
+ PrintTableHeaderCell("First connection<font color=\"red\"><sup>1</sup></font>");
+ PrintTableHeaderCell("Last connection<font color=\"red\"><sup>1</sup></font>");
+ println(" </tr>");
+
+ for(var i=0;i<storage_roots.length;i++) {
+ var storage_subroots=GetRegistryNodes(cur_controlset+"\\Enum\\USBSTOR\\"+storage_roots[i]);
+ for(var ii=0;ii<storage_subroots.length;ii++) {
+ var device_id=storage_subroots[ii];
+ if(String(device_id).charAt(1)=="&") {
+ // If the second character of the unique instance ID is a '&', then
+ // the ID was generated by the system, as the device did not have a
+ // serial number.
+ device_id=device_id+" (Generated by system)";
+ }
+ var device_key=cur_controlset+"\\Enum\\USBSTOR\\"+storage_roots[i]+"\\"+storage_subroots[ii];
+ var device_class=GetKeyVal(device_key,"Class");
+ var device_desc=GetKeyVal(device_key,"DeviceDesc");
+ var device_friendly_name=GetKeyVal(device_key,"FriendlyName");
+ var device_parent_id=GetKeyVal(device_key,"ParentIdPrefix");
+ var device_first_connection=GetRegistryNodeModTime(cur_controlset+"\\Enum\\USBSTOR\\"+storage_roots[i]);
+ var device_last_connection=GetRegistryNodeModTime(cur_controlset+"\\Enum\\USBSTOR\\"+storage_roots[i]+"\\"+storage_subroots[ii]);
+
+ var search_string="";
+ var device_mount_points=Array();
+ if(device_parent_id != "") {
+ // Windows XP uses the ParentId to link to MountedDevices
+ search_string="#"+device_parent_id+"&";
+ } else {
+ // Since Vista, Unique IDs are used
+ search_string="#"+storage_subroots[ii]+"#";
+ }
+ for(var iii=0; iii<mnt_keys.length; iii++) {
+ if(String(mnt_values[iii]).indexOf(search_string)!=-1) {
+ device_mount_points.push(mnt_keys[iii]);
+ }
+ }
+
+ var mount_points=device_mount_points.length;
+ if(mount_points>1) {
+ println(" <tr>");
+ PrintTableDataRowSpanCell("left",mount_points,storage_roots[i]);
+ PrintTableDataRowSpanCell("left",mount_points,device_id);
+ PrintTableDataRowSpanCell("left",mount_points,device_class);
+ PrintTableDataRowSpanCell("left",mount_points,device_friendly_name);
+ PrintTableDataCell("left",device_mount_points[0]);
+ PrintTableDataRowSpanCell("left",mount_points,device_parent_id);
+ PrintTableDataRowSpanCell("left",mount_points,device_desc);
+ PrintTableDataRowSpanCell("left",mount_points,device_first_connection);
+ PrintTableDataRowSpanCell("left",mount_points,device_last_connection);
+ println(" </tr>");
+ for(var iii=1;iii<device_mount_points.length;iii++) {
+ println(" <tr>");
+ PrintTableDataCell("left",device_mount_points[iii]);
+ println(" </tr>");
+ }
+ } else {
+ println(" <tr>");
+ PrintTableDataCell("left",storage_roots[i]);
+ PrintTableDataCell("left",device_id);
+ PrintTableDataCell("left",device_class);
+ PrintTableDataCell("left",device_friendly_name);
+ if(mount_points!=0) {
+ PrintTableDataCell("left",device_mount_points[0]);
+ } else {
+ PrintTableDataCell("left","n/a");
+ }
+ PrintTableDataCell("left",device_parent_id);
+ PrintTableDataCell("left",device_desc);
+ PrintTableDataCell("left",device_first_connection);
+ PrintTableDataCell("left",device_last_connection);
+ println(" </tr>");
+ }
+ }
+ }
+ println(" </table>");
+ println(" &nbsp;&nbsp;&nbsp;&nbsp;<font color=\"red\"><sup>1</sup></font> Might be incorrect");
+ println(" <br />");
+ } else {
+ println(" <font color=\"red\">This registry hive does not contain a list of attached USB storage devices!</font>");
+ }
+ println(" </p>");
+ } else {
+ println(" <p><font color=\"red\">");
+ println(" Unable to determine current control set!<br />");
+ println(" Are you sure you are running this report against the correct registry hive?");
+ println(" </font></p>");
+ }
+}
+
diff --git a/tags/fred-0.2.0/report_templates/SYSTEM_UsbStorageDevices_old.qs b/tags/fred-0.2.0/report_templates/SYSTEM_UsbStorageDevices_old.qs
new file mode 100644
index 0000000..a36c041
--- /dev/null
+++ b/tags/fred-0.2.0/report_templates/SYSTEM_UsbStorageDevices_old.qs
@@ -0,0 +1,145 @@
+function fred_report_info() {
+ var info={report_cat : "SYSTEM",
+ report_name : "OLD - USB storage devices",
+ report_author : "Gillen Daniel",
+ report_desc : "Dump USB storage devices",
+ fred_api : 2,
+ hive : "SYSTEM"
+ };
+ return info;
+}
+
+function IsValid(val) {
+ if(typeof val !== 'undefined') return true;
+ else return false;
+}
+
+function print_table_row(cell01,cell02) {
+ println(" <tr><td>",cell01,"</td><td>",cell02,"</td></tr>");
+}
+
+function ZeroPad(number,padlen) {
+ var ret=number.toString(10);
+ if(!padlen || ret.length>=padlen) return ret;
+ return Math.pow(10,padlen-ret.length).toString().slice(1)+ret;
+}
+
+function fred_report_html() {
+ // TODO: There is more here. Check http://www.forensicswiki.org/wiki/USB_History_Viewing
+ var val;
+
+ println(" <h2>USB storage devices</h2>");
+
+ // Preload MountedDevices to possibly identify mount points of USB storage devices
+ var mnt_keys=GetRegistryKeys("\\MountedDevices");
+ var mnt_values=new Array();
+ if(IsValid(mnt_keys)) {
+ for(var i=0;i<mnt_keys.length;i++) {
+ val=GetRegistryKeyValue("\\MountedDevices",mnt_keys[i]);
+ mnt_values[i]=RegistryKeyValueToVariant(val.value,"utf16");
+ }
+ }
+
+ // Get current controlset
+ var cur_controlset=GetRegistryKeyValue("\\Select","Current");
+ if(IsValid(cur_controlset)) {
+ cur_controlset=RegistryKeyValueToString(cur_controlset.value,cur_controlset.type);
+ // Current holds a DWORD value, thus we get a string like 0x00000000, but
+ // control sets are referenced by its decimal representation.
+ cur_controlset="ControlSet"+ZeroPad(parseInt(String(cur_controlset).substr(2,8),16),3)
+
+ println(" <p style=\"font-size:12; white-space:nowrap\">");
+ println(" <u>Settings</u><br />");
+ println(" <table style=\"margin-left:20px; font-size:12; white-space:nowrap\">");
+
+ // Are USB storage devices enabled?
+ // http://www.forensicmag.com/article/windows-7-registry-forensics-part-5
+ // Is this true for WinXP etc.. ???
+ var val=GetRegistryKeyValue(cur_controlset+"\\services\\USBSTOR","Start");
+ if(IsValid(val)) {
+ val=RegistryKeyValueToString(val.value,val.type);
+ val=parseInt(String(val).substr(2,8),10);
+ switch(val) {
+ case 3:
+ print_table_row("Storage driver enabled:","Yes");
+ break;
+ case 4:
+ print_table_row("Storage driver enabled:","No");
+ break;
+ default:
+ print_table_row("Storage driver enabled:","Unknown");
+ }
+ } else {
+ print_table_row("Storage driver enabled:","Unknown");
+ }
+
+ println(" </table>");
+ println(" </p>");
+ println(" <p style=\"font-size:12; white-space:nowrap\">");
+ println(" <u>Devices</u><br />");
+
+ var storage_roots=GetRegistryNodes(cur_controlset+"\\Enum\\USBSTOR");
+ if(IsValid(storage_roots)) {
+ for(var i=0;i<storage_roots.length;i++) {
+ println(" <u style=\"margin-left:20px; font-size:12; white-space:nowrap\">",storage_roots[i],"</u><br />");
+ var storage_subroots=GetRegistryNodes(cur_controlset+"\\Enum\\USBSTOR\\"+storage_roots[i]);
+ for(ii=0;ii<storage_subroots.length;ii++) {
+ println(" <table style=\"margin-left:20px; font-size:12; white-space:nowrap\">");
+ // If the second character of the unique instance ID is a '&', then the ID was
+ // generated by the system, as the device did not have a serial number.
+ if(String(storage_subroots[ii]).charAt(1)=="&") print_table_row("Unique ID:",storage_subroots[ii]+" (Generated by system)");
+ else print_table_row("Unique ID:",storage_subroots[ii]);
+
+ val=GetRegistryKeyValue(cur_controlset+"\\Enum\\USBSTOR\\"+storage_roots[i]+"\\"+storage_subroots[ii],"Class");
+ print_table_row("Class:",(IsValid(val)) ? RegistryKeyValueToString(val.value,val.type) : "");
+ val=GetRegistryKeyValue(cur_controlset+"\\Enum\\USBSTOR\\"+storage_roots[i]+"\\"+storage_subroots[ii],"DeviceDesc");
+ print_table_row("Device description:",(IsValid(val)) ? RegistryKeyValueToString(val.value,val.type) : "");
+ val=GetRegistryKeyValue(cur_controlset+"\\Enum\\USBSTOR\\"+storage_roots[i]+"\\"+storage_subroots[ii],"FriendlyName");
+ print_table_row("Friendly name:",(IsValid(val)) ? RegistryKeyValueToString(val.value,val.type) : "");
+ val=GetRegistryKeyValue(cur_controlset+"\\Enum\\USBSTOR\\"+storage_roots[i]+"\\"+storage_subroots[ii],"ParentIdPrefix");
+ if(IsValid(val)) {
+ // Windows XP uses the ParentId to link to MountedDevices
+ var parent_id=RegistryKeyValueToString(val.value,val.type);
+ print_table_row("Parent ID prefix:",parent_id);
+ // Find mount point(s)
+ print(" <tr><td>Mount point(s):</td><td>");
+ var br=0;
+ for(var iii=0;iii<mnt_keys.length;iii++) {
+ if(String(mnt_values[iii]).indexOf("#"+parent_id+"&")!=-1) {
+ if(br==1) print("<br />");
+ else br=1;
+ print(mnt_keys[iii]);
+ }
+ }
+ if(br==0) print("n/a");
+ println("</td></tr>");
+ } else {
+ // Since Vista, Unique IDs are used
+ // Find mount point(s)
+ print(" <tr><td>Mount point(s):</td><td>");
+ var br=0;
+ for(var iii=0;iii<mnt_keys.length;iii++) {
+ if(String(mnt_values[iii]).indexOf("#"+storage_subroots[ii]+"#")!=-1) {
+ if(br==1) print("<br />");
+ else br=1;
+ print(mnt_keys[iii]);
+ }
+ }
+ if(br==0) print("n/a");
+ println("</td></tr>");
+ }
+ println(" </table>");
+ println(" <br />");
+ }
+ }
+ } else {
+ println(" <font color='red'>This registry hive does not contain a list of attached USB storage devices!</font>");
+ }
+ println(" </p>");
+ } else {
+ println(" <p><font color='red'>");
+ println(" Unable to determine current control set!<br />");
+ println(" Are you sure you are running this report against the correct registry hive?");
+ println(" </font></p>");
+ }
+}
diff --git a/tags/fred-0.2.0/reportengine.cpp b/tags/fred-0.2.0/reportengine.cpp
new file mode 100644
index 0000000..5c4de23
--- /dev/null
+++ b/tags/fred-0.2.0/reportengine.cpp
@@ -0,0 +1,562 @@
+/*******************************************************************************
+* fred Copyright (c) 2011-2020 by Gillen Daniel <gillen.dan@pinguin.lu> *
+* *
+* Forensic Registry EDitor (fred) is a cross-platform M$ registry hive editor *
+* with special feautures useful during forensic analysis. *
+* *
+* This program is free software: you can redistribute it and/or modify it *
+* under the terms of the GNU General Public License as published by the Free *
+* Software Foundation, either version 3 of the License, or (at your option) *
+* any later version. *
+* *
+* This program is distributed in the hope that it will be useful, but WITHOUT *
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or *
+* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for *
+* more details. *
+* *
+* You should have received a copy of the GNU General Public License along with *
+* this program. If not, see <http://www.gnu.org/licenses/>. *
+*******************************************************************************/
+
+#include <QFile>
+#include <QTextStream>
+#include <QDateTime>
+#include <QStringList>
+
+#include <QtDebug>
+
+#include "reportengine.h"
+
+/*******************************************************************************
+ * Public
+ ******************************************************************************/
+
+ReportEngine::ReportEngine(RegistryHive *p_hive) : QScriptEngine() {
+ // Init vars
+ this->p_registry_hive=p_hive;
+ this->report_content="";
+
+ // Add our constants
+ this->globalObject().setProperty("ENGINE_API_VERSION",
+ FRED_REPORTENGINE_API_VERSION,
+ QScriptValue::ReadOnly|
+ QScriptValue::Undeletable);
+/*
+ this->globalObject().setProperty("HIVE_FILE",
+ this->p_registry_hive->Filename(),
+ QScriptValue::ReadOnly|
+ QScriptValue::Undeletable);
+*/
+ // Add our types to engine
+ qScriptRegisterMetaType<s_RegistryKeyValue>(this,
+ this->RegistryKeyValueToScript,
+ this->RegistryKeyValueFromScript);
+ this->p_type_byte_array=new ByteArray(this);
+ this->globalObject().setProperty("ByteArray",
+ this->p_type_byte_array->constructor());
+
+ // TODO: Is it really necessary to explicitly export these functions
+ // here ??????????
+ // Add our functions
+ // print
+ QScriptValue func_print=this->newFunction(this->Print);
+ this->globalObject().setProperty("print",func_print);
+ // println
+ QScriptValue func_println=this->newFunction(this->PrintLn);
+ this->globalObject().setProperty("println",func_println);
+
+ // RegistryKeyValueToString
+ QScriptValue func_value_to_string=
+ this->newFunction(this->RegistryKeyValueToString,2);
+ this->globalObject().setProperty("RegistryKeyValueToString",
+ func_value_to_string);
+ // RegistryKeyValueToVariant
+ QScriptValue func_value_to_variant=
+ this->newFunction(this->RegistryKeyValueToVariant);
+ this->globalObject().setProperty("RegistryKeyValueToVariant",
+ func_value_to_variant);
+ // RegistryKeyValueToStringList
+ QScriptValue func_value_to_string_list=
+ this->newFunction(this->RegistryKeyValueToStringList);
+ this->globalObject().setProperty("RegistryKeyValueToStringList",
+ func_value_to_string_list);
+ // RegistryKeyTypeToString
+ QScriptValue func_type_to_string=
+ this->newFunction(this->RegistryKeyTypeToString,1);
+ this->globalObject().setProperty("RegistryKeyTypeToString",
+ func_type_to_string);
+}
+
+ReportEngine::~ReportEngine() {
+ delete this->p_type_byte_array;
+}
+
+/*
+ * GetReportTemplateInfo
+ */
+QMap<QString,QVariant> ReportEngine::GetReportTemplateInfo(QString file) {
+ // Read template file
+ QString report_code;
+ if(!this->GetReportTemplateFileContents(file,report_code)) {
+ QMap<QString,QVariant> error_msg;
+ error_msg["error"]=report_code;
+ return error_msg;
+ }
+
+ // Evaluate report template script
+ QScriptValue report_result=this->evaluate(report_code,file);
+ if (report_result.isError() || this->hasUncaughtException()) {
+ QMap<QString,QVariant> error_msg;
+ error_msg["error"]=QString("File: %1\n Line: %2\nError: %3")
+ .arg(file)
+ .arg(report_result.property("lineNumber").toInt32())
+ .arg(report_result.toString());
+ return error_msg;
+ }
+
+ // Try to call the fred_report_info script function and return result
+ QScriptValue fred_report_info_func=
+ this->globalObject().property("fred_report_info");
+ if(!fred_report_info_func.isFunction()) {
+ QMap<QString,QVariant> error_msg;
+ error_msg["error"]=
+ QString("Report template '%1' does not have a fred_report_info function!")
+ .arg(file)
+ .arg(report_result.property("lineNumber").toInt32())
+ .arg(report_result.toString());
+ return error_msg;
+ }
+ QScriptValue fred_report_info_res=fred_report_info_func.call();
+ // TODO: Maybe do more checking on return value
+ return fred_report_info_res.toVariant().toMap();
+}
+
+/*
+ * GenerateReport
+ */
+bool ReportEngine::GenerateReport(RegistryHive *p_hive,
+ QString report_file,
+ QString &report_result,
+ bool console_mode)
+{
+ // TODO: Support or remove console_mode
+ Q_UNUSED(console_mode);
+
+ // Clear internal buffer
+ this->report_content.clear();
+
+ // Update exported functions
+ this->UpdateExportedFunctions(p_hive);
+
+ // Read template file
+ QString report_code;
+ if(!this->GetReportTemplateFileContents(report_file,report_code)) {
+ report_result=report_code;
+ return false;
+ }
+
+ // Evaluate report template script
+ QScriptValue script_result=this->evaluate(report_code,report_file);
+ if (script_result.isError() || this->hasUncaughtException()) {
+ script_result=QString("File: %1\n Line: %2\nError: %3")
+ .arg(report_file)
+ .arg(script_result.property("lineNumber").toInt32())
+ .arg(script_result.toString());
+ return false;
+ }
+
+ // Try to call the fred_report_html script function and return result
+ QScriptValue fred_report_html_func=
+ this->globalObject().property("fred_report_html");
+ if(!fred_report_html_func.isFunction()) {
+ report_result=
+ QString("Report template '%1' does not have a fred_report_info function!")
+ .arg(report_file)
+ .arg(script_result.property("lineNumber").toInt32())
+ .arg(script_result.toString());
+ return false;
+ }
+ QScriptValue fred_report_html_res=fred_report_html_func.call();
+
+ // TODO: Maybe do more checking on return value
+ report_result=this->report_content;
+ return true;
+}
+
+/*******************************************************************************
+ * Public Slots
+ ******************************************************************************/
+
+/*******************************************************************************
+ * Private
+ ******************************************************************************/
+
+/*
+ * Print
+ */
+QScriptValue ReportEngine::Print(QScriptContext *context,
+ QScriptEngine *engine)
+{
+ int i;
+ QString content;
+
+ // Append all arguments to content
+ for(i=0;i<context->argumentCount();++i) {
+ //if(i>0) content.append(" ");
+ content.append(context->argument(i).toString());
+ }
+
+ qobject_cast<ReportEngine*>(engine)->report_content.append(content);
+
+ return engine->undefinedValue();
+}
+
+/*
+ * PrintLn
+ */
+QScriptValue ReportEngine::PrintLn(QScriptContext *context,
+ QScriptEngine *engine)
+{
+ int i;
+ QString content;
+
+ // Append all arguments to content
+ for(i=0;i<context->argumentCount();++i) {
+ //if(i>0) content.append(" ");
+ content.append(context->argument(i).toString());
+ }
+
+ qobject_cast<ReportEngine*>(engine)->
+ report_content.append(content).append("\n");
+
+ return engine->undefinedValue();
+}
+
+/*
+ * GetRegistryNodes
+ */
+QScriptValue ReportEngine::GetRegistryNodes(QScriptContext *context,
+ QScriptEngine *engine)
+{
+ QScriptValue calleeData;
+ RegistryHive *p_hive;
+ QMap<QString,int> nodes;
+ QScriptValue ret_nodes;
+ int ii=0;
+
+ // This function needs one argument, parent node path
+ if(context->argumentCount()!=1) return engine->undefinedValue();
+
+ // Get calle data (Pointer to RegistryHive class)
+ calleeData=context->callee().data();
+ p_hive=qobject_cast<RegistryHive*>(calleeData.toQObject());
+
+ // Get nodes
+ nodes=p_hive->GetNodes(context->argument(0).toString());
+ if(p_hive->Error()) {
+ // Clear error state
+ p_hive->GetErrorMsg();
+ return engine->undefinedValue();
+ }
+
+ // Build script array
+ ret_nodes=engine->newArray(nodes.count());
+ QMapIterator<QString,int> i(nodes);
+ while(i.hasNext()) {
+ i.next();
+ ret_nodes.setProperty(ii++,QScriptValue(i.key()));
+ }
+
+ return ret_nodes;
+}
+
+/*
+ * GetRegistryKeys
+ */
+QScriptValue ReportEngine::GetRegistryKeys(QScriptContext *context,
+ QScriptEngine *engine)
+{
+ QScriptValue calleeData;
+ RegistryHive *p_hive;
+ QMap<QString,int> keys;
+ QScriptValue ret_keys;
+ int ii=0;
+
+ // This function needs one argument, parent node path
+ if(context->argumentCount()!=1) return engine->undefinedValue();
+
+ // Get calle data (Pointer to RegistryHive class)
+ calleeData=context->callee().data();
+ p_hive=qobject_cast<RegistryHive*>(calleeData.toQObject());
+
+ // Get keys
+ keys=p_hive->GetKeys(context->argument(0).toString());
+ if(p_hive->Error()) {
+ // Clear error state
+ p_hive->GetErrorMsg();
+ return engine->undefinedValue();
+ }
+
+ // Build script array
+ ret_keys=engine->newArray(keys.count());
+ QMapIterator<QString,int> i(keys);
+ while(i.hasNext()) {
+ i.next();
+ ret_keys.setProperty(ii++,QScriptValue(i.key()));
+ }
+
+ return ret_keys;
+}
+
+/*
+ * RegistryKeyValueToScript
+ */
+QScriptValue ReportEngine::RegistryKeyValueToScript(QScriptEngine *engine,
+ const s_RegistryKeyValue &s)
+{
+ QScriptValue obj=engine->newObject();
+ obj.setProperty("type",s.type);
+ obj.setProperty("length",s.length);
+ ByteArray *p_byte_array=new ByteArray(engine);
+ obj.setProperty("value",p_byte_array->newInstance(s.value));
+ return obj;
+}
+
+/*
+ * RegistryKeyValueFromScriptValue
+ */
+void ReportEngine::RegistryKeyValueFromScript(const QScriptValue &obj,
+ s_RegistryKeyValue &s)
+{
+ s.type=obj.property("type").toInt32();
+ s.length=obj.property("length").toInt32();
+ s.value=qvariant_cast<QByteArray>(obj.property("value").data().toVariant());
+}
+
+/*
+ * GetRegistryKeyValue
+ */
+QScriptValue ReportEngine::GetRegistryKeyValue(QScriptContext *context,
+ QScriptEngine *engine)
+{
+ QScriptValue calleeData;
+ RegistryHive *p_hive;
+ QByteArray key_value;
+ int key_type=0;
+ size_t key_length=0;
+ s_RegistryKeyValue script_key_value;
+
+ // This function needs two arguments, key path and key name
+ if(context->argumentCount()!=2) return engine->undefinedValue();
+
+ // Get calle data (Pointer to RegistryHive class)
+ calleeData=context->callee().data();
+ p_hive=qobject_cast<RegistryHive*>(calleeData.toQObject());
+
+ // Get key value
+ key_value=p_hive->GetKeyValue(context->argument(0).toString(),
+ context->argument(1).toString(),
+ &key_type,
+ &key_length);
+ if(p_hive->Error()) {
+ // Get error message to clear error state
+ p_hive->GetErrorMsg();
+// printf("\nError: %s\n",p_hive->GetErrorMsg().toLatin1().constData());
+ return engine->undefinedValue();
+ }
+
+ // Save key value to s_RegistryKeyValue struct
+ script_key_value.type=key_type;
+ script_key_value.length=key_length;
+ script_key_value.value=key_value;
+
+ return ReportEngine::RegistryKeyValueToScript(engine,script_key_value);
+}
+
+/*
+ * RegistryKeyValueToString
+ */
+QScriptValue ReportEngine::RegistryKeyValueToString(QScriptContext *context,
+ QScriptEngine *engine)
+{
+ QByteArray key_value;
+ QString ret="";
+
+ // This function needs two arguments, key value and value type
+ if(context->argumentCount()!=2) return engine->undefinedValue();
+
+ // Cast ByteArray argument to QByteArray and convert
+ key_value=qvariant_cast<QByteArray>(context->argument(0).data().toVariant());
+ ret=RegistryHive::KeyValueToString(key_value,
+ context->argument(1).toInt32());
+
+ return engine->newVariant(ret);
+}
+
+/*
+ * RegistryKeyValueToVariant
+ */
+QScriptValue ReportEngine::RegistryKeyValueToVariant(QScriptContext *context,
+ QScriptEngine *engine)
+{
+ int offset=0;
+ int length=-1;
+ bool little_endian=true;
+ QByteArray key_value;
+ QString format="";
+ QString ret="";
+
+ // This function needs at least two arguments, key value and variant type,
+ // and may have three optional arguments, offset, length and little_endian
+ if(context->argumentCount()<2 || context->argumentCount()>5) {
+ return engine->undefinedValue();
+ }
+ if(context->argumentCount()==3) {
+ offset=context->argument(2).toInt32();
+ }
+ if(context->argumentCount()==4) {
+ offset=context->argument(2).toInt32();
+ length=context->argument(3).toInt32();
+ }
+ if(context->argumentCount()==5) {
+ offset=context->argument(2).toInt32();
+ length=context->argument(3).toInt32();
+ little_endian=(context->argument(4).toInt32()==1);
+ }
+
+ // Cast ByteArray argument to QByteArray
+ key_value=qvariant_cast<QByteArray>(context->argument(0).data().toVariant());
+ format=context->argument(1).toString();
+
+ ret=RegistryHive::KeyValueToString(key_value,format,offset,length,little_endian);
+
+ return engine->newVariant(ret);
+}
+
+/*
+ * RegistryKeyValueToStringList
+ */
+QScriptValue ReportEngine::RegistryKeyValueToStringList(QScriptContext *context,
+ QScriptEngine *engine)
+{
+ QByteArray value;
+ QStringList strings;
+ QScriptValue ret;
+ int i=0;
+ bool little_endian=true;
+
+ // This function needs one arguments, key value, and may have a second
+ // specifying endianness
+ if(context->argumentCount()==0 || context->argumentCount()>2)
+ return engine->undefinedValue();
+ if(context->argumentCount()==2) {
+ little_endian=context->argument(2).toBool();
+ }
+
+ // Cast ByteArray argument to QByteArray and convert
+ value=qvariant_cast<QByteArray>(context->argument(0).data().toVariant());
+ strings=RegistryHive::KeyValueToStringList(value,little_endian);
+
+ // Build script array
+ ret=engine->newArray(strings.count());
+ QListIterator<QString> str_it(strings);
+ while(str_it.hasNext()) {
+ ret.setProperty(i++,QScriptValue(str_it.next()));
+ }
+
+ return ret;
+}
+
+/*
+ * RegistryKeyTypeToString
+ */
+QScriptValue ReportEngine::RegistryKeyTypeToString(QScriptContext *context,
+ QScriptEngine *engine)
+{
+ QString ret="";
+
+ // This function needs one argument, key type
+ if(context->argumentCount()!=1) return engine->undefinedValue();
+
+ ret=RegistryHive::KeyValueTypeToString(context->argument(0).toInt32());
+
+ return engine->newVariant(ret);
+}
+
+/*
+ * GetRegistryNodeModTime
+ */
+QScriptValue ReportEngine::GetRegistryNodeModTime(QScriptContext *context,
+ QScriptEngine *engine)
+{
+ QScriptValue calleeData;
+ RegistryHive *p_hive;
+ qint64 mod_time=0;
+
+ // This function needs one argument, node path
+ if(context->argumentCount()!=1) return engine->undefinedValue();
+
+ // Get calle data (Pointer to RegistryHive class)
+ calleeData=context->callee().data();
+ p_hive=qobject_cast<RegistryHive*>(calleeData.toQObject());
+
+ mod_time=p_hive->GetNodeModTime(context->argument(0).toString());
+ if(p_hive->Error()) {
+ // Get error message to clear error state
+ p_hive->GetErrorMsg();
+ return engine->undefinedValue();
+ }
+
+ QDateTime date_time;
+ date_time.setTimeSpec(Qt::UTC);
+ date_time.setTime_t(RegistryHive::FiletimeToUnixtime(mod_time));
+
+ return engine->newVariant(date_time.toString("yyyy/MM/dd hh:mm:ss"));
+}
+
+/*
+ * GetReportTemplateFileContents
+ */
+bool ReportEngine::GetReportTemplateFileContents(QString file,
+ QString &contents)
+{
+ // Open report template file
+ QFile template_file(file);
+ if(!template_file.open(QIODevice::ReadOnly | QIODevice::Text)) {
+ contents=QString("Couldn't open report template file '%1'!").arg(file);
+ return false;
+ }
+
+ // Read template file and close it
+ contents.clear();
+ QTextStream in(&template_file);
+ while(!in.atEnd()) contents.append(in.readLine()).append("\n");
+ template_file.close();
+
+ return true;
+}
+
+/*
+ * UpdateExportedFunctions
+ */
+void ReportEngine::UpdateExportedFunctions(RegistryHive *p_hive) {
+ this->p_registry_hive=p_hive;
+ // GetRegistryNodes
+ QScriptValue func_get_nodes=this->newFunction(this->GetRegistryNodes,1);
+ func_get_nodes.setData(this->newQObject(this->p_registry_hive));
+ this->globalObject().setProperty("GetRegistryNodes",func_get_nodes);
+ // GetRegistryKeys
+ QScriptValue func_get_keys=this->newFunction(this->GetRegistryKeys,1);
+ func_get_keys.setData(this->newQObject(this->p_registry_hive));
+ this->globalObject().setProperty("GetRegistryKeys",func_get_keys);
+ // GetRegistryKeyValue
+ QScriptValue func_get_key_value=this->newFunction(this->GetRegistryKeyValue,
+ 2);
+ func_get_key_value.setData(this->newQObject(this->p_registry_hive));
+ this->globalObject().setProperty("GetRegistryKeyValue",func_get_key_value);
+ // GetRegistryNodeModTime
+ QScriptValue func_get_node_modt=
+ this->newFunction(this->GetRegistryNodeModTime,1);
+ func_get_node_modt.setData(this->newQObject(this->p_registry_hive));
+ this->globalObject().setProperty("GetRegistryNodeModTime",func_get_node_modt);
+}
diff --git a/tags/fred-0.2.0/reportengine.h b/tags/fred-0.2.0/reportengine.h
new file mode 100644
index 0000000..5075346
--- /dev/null
+++ b/tags/fred-0.2.0/reportengine.h
@@ -0,0 +1,91 @@
+/*******************************************************************************
+* fred Copyright (c) 2011-2020 by Gillen Daniel <gillen.dan@pinguin.lu> *
+* *
+* Forensic Registry EDitor (fred) is a cross-platform M$ registry hive editor *
+* with special feautures useful during forensic analysis. *
+* *
+* This program is free software: you can redistribute it and/or modify it *
+* under the terms of the GNU General Public License as published by the Free *
+* Software Foundation, either version 3 of the License, or (at your option) *
+* any later version. *
+* *
+* This program is distributed in the hope that it will be useful, but WITHOUT *
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or *
+* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for *
+* more details. *
+* *
+* You should have received a copy of the GNU General Public License along with *
+* this program. If not, see <http://www.gnu.org/licenses/>. *
+*******************************************************************************/
+
+#ifndef REPORTENGINE_H
+#define REPORTENGINE_H
+
+#include <QObject>
+#include <QtScript/QScriptEngine>
+#include <QtScript/QScriptValue>
+#include <QtScript/QScriptContext>
+#include <QString>
+#include <QVariant>
+#include <QMap>
+
+#include "registryhive.h"
+#include "qtscript_types/bytearray.h"
+
+#define FRED_REPORTENGINE_API_VERSION 2
+
+class ReportEngine : public QScriptEngine {
+ Q_OBJECT
+
+ public:
+ struct s_RegistryKeyValue {
+ int type;
+ int length;
+ QByteArray value;
+ };
+
+ RegistryHive *p_registry_hive;
+ QString report_content;
+
+ ReportEngine(RegistryHive *p_hive);
+ ~ReportEngine();
+
+ QMap<QString,QVariant> GetReportTemplateInfo(QString file);
+ bool GenerateReport(RegistryHive *p_hive,
+ QString report_file,
+ QString &report_result,
+ bool console_mode=true);
+
+ private:
+ ByteArray *p_type_byte_array;
+
+ static QScriptValue Print(QScriptContext *context, QScriptEngine *engine);
+ static QScriptValue PrintLn(QScriptContext *context, QScriptEngine *engine);
+ static QScriptValue GetRegistryNodes(QScriptContext *context,
+ QScriptEngine *engine);
+ static QScriptValue GetRegistryKeys(QScriptContext *context,
+ QScriptEngine *engine);
+ static QScriptValue RegistryKeyValueToScript(QScriptEngine *engine,
+ const s_RegistryKeyValue &s);
+ static void RegistryKeyValueFromScript(const QScriptValue &obj,
+ s_RegistryKeyValue &s);
+ static QScriptValue GetRegistryKeyValue(QScriptContext *context,
+ QScriptEngine *engine);
+ static QScriptValue RegistryKeyValueToString(QScriptContext *context,
+ QScriptEngine *engine);
+ static QScriptValue RegistryKeyValueToVariant(QScriptContext *context,
+ QScriptEngine *engine);
+ static QScriptValue RegistryKeyValueToStringList(QScriptContext *context,
+ QScriptEngine *engine);
+ static QScriptValue RegistryKeyTypeToString(QScriptContext *context,
+ QScriptEngine *engine);
+ static QScriptValue GetRegistryNodeModTime(QScriptContext *context,
+ QScriptEngine *engine);
+
+ bool GetReportTemplateFileContents(QString file, QString &contents);
+ void UpdateExportedFunctions(RegistryHive *p_hive);
+};
+
+Q_DECLARE_METATYPE(ReportEngine::s_RegistryKeyValue)
+
+#endif // REPORTENGINE_H
diff --git a/tags/fred-0.2.0/reports.cpp b/tags/fred-0.2.0/reports.cpp
new file mode 100644
index 0000000..da4f54b
--- /dev/null
+++ b/tags/fred-0.2.0/reports.cpp
@@ -0,0 +1,205 @@
+/*******************************************************************************
+* fred Copyright (c) 2011-2020 by Gillen Daniel <gillen.dan@pinguin.lu> *
+* *
+* Forensic Registry EDitor (fred) is a cross-platform M$ registry hive editor *
+* with special feautures useful during forensic analysis. *
+* *
+* This program is free software: you can redistribute it and/or modify it *
+* under the terms of the GNU General Public License as published by the Free *
+* Software Foundation, either version 3 of the License, or (at your option) *
+* any later version. *
+* *
+* This program is distributed in the hope that it will be useful, but WITHOUT *
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or *
+* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for *
+* more details. *
+* *
+* You should have received a copy of the GNU General Public License along with *
+* this program. If not, see <http://www.gnu.org/licenses/>. *
+*******************************************************************************/
+
+#include <QStringList>
+#include <QListIterator>
+#include <QDir>
+#include <QMap>
+
+#include <QDebug>
+
+#include "reports.h"
+
+/*******************************************************************************
+ * Public
+ ******************************************************************************/
+
+Reports::Reports(Settings *p_sets) {
+ this->p_settings=p_sets;
+ this->p_engine=new ReportEngine(NULL);
+ this->report_templates.clear();
+
+ if(this->p_settings!=NULL) this->LoadReportTemplates();
+}
+
+Reports::~Reports() {
+ qDeleteAll(this->report_templates);
+ delete this->p_engine;
+}
+
+void Reports::LoadReportTemplates() {
+ // Delete any previously loaded reports
+ qDeleteAll(this->report_templates);
+ this->report_templates.clear();
+
+ // Return if we have no settings loaded
+ if(this->p_settings==NULL) return;
+
+ // Load all available reports
+ QStringList report_dirs=this->p_settings->GetReportTemplateDirs();
+ QListIterator<QString> report_dir_it(report_dirs);
+ while(report_dir_it.hasNext()) {
+ this->LoadReportTemplatesFromDir(report_dir_it.next());
+ }
+}
+
+QStringList Reports::GetAvailableReportCategories() {
+ QStringList ret;
+ QString cat;
+ int i;
+
+ ret.clear();
+ for(i=0;i<this->report_templates.count();i++) {
+ cat=this->report_templates.value(i)->Category();
+ if(!ret.contains(cat)) ret.append(cat);
+ }
+ ret.sort();
+
+ return ret;
+}
+
+
+QList<ReportTemplate*> Reports::GetAvailableReports(QString category) {
+ QList<ReportTemplate*> ret;
+ QString cat;
+ int i=0;
+
+ ret.clear();
+ for(i=0;i<this->report_templates.count();i++) {
+ cat=this->report_templates.value(i)->Category();
+ if(cat==category) ret.append(this->report_templates.value(i));
+ }
+
+ return ret;
+}
+
+bool Reports::GenerateReport(RegistryHive *p_hive,
+ QString report_file,
+ QString &report_result,
+ bool console_mode)
+{
+ return this->p_engine->GenerateReport(p_hive,
+ report_file,
+ report_result,
+ console_mode);
+}
+
+bool Reports::GenerateReport(RegistryHive *p_hive,
+ QList<ReportTemplate*> report_list,
+ QString &report_result,
+ bool console_mode)
+{
+ bool ret;
+ QString res;
+
+ QListIterator<ReportTemplate*> rep_it(report_list);
+ while(rep_it.hasNext()) {
+ res="";
+ ret=this->GenerateReport(p_hive,
+ rep_it.next()->File(),
+ res,
+ console_mode);
+ if(ret) report_result.append(res);
+ // TODO: Inform user something didn't work
+ }
+
+ return true;
+}
+
+/*******************************************************************************
+ * Private
+ ******************************************************************************/
+
+void Reports::LoadReportTemplatesFromDir(QString dir) {
+ QString report_template="";
+ QString report_category,report_name,report_author,report_desc,report_hive;
+ bool found;
+ int i;
+ ReportTemplate *p_report;
+
+ // Get all template files in report_templates directory
+ QDir report_dir(dir);
+ QStringList found_report_templates=report_dir.
+ entryList(QStringList()<<"*.qs");
+
+ QListIterator<QString> it(found_report_templates);
+ while(it.hasNext()) {
+ // Build path to template file
+ report_template=report_dir.path();
+ report_template.append(QDir::separator());
+ report_template.append(it.next());
+
+ // Get report info
+ QMap<QString,QVariant> report_info=this->p_engine->
+ GetReportTemplateInfo(report_template);
+ if(report_info.contains("error")) {
+ // TODO: Inform user
+ qDebug()<<"Error in report '"<<report_template<<"'\n"
+ <<report_info["error"].toString();
+ continue;
+ }
+
+ // Make sure report is compatible with current API
+ if(report_info.value("fred_api",QVariant(0)).toInt()>
+ FRED_REPORTENGINE_API_VERSION)
+ {
+ // TODO: Inform user
+ qDebug()<<"Report '"<<report_template
+ <<"' is not compatible with current API!";
+ continue;
+ }
+
+ // Extract info values. If a value isn't present, it will be set to ""
+ report_category=report_info.value("report_cat").toString();
+ report_name=report_info.value("report_name").toString();
+ report_author=report_info.value("report_author").toString();
+ report_desc=report_info.value("report_desc").toString();
+ report_hive=report_info.value("hive").toString().toUpper();
+
+ // Check if a report with the same category and name was already added
+ found=false;
+ for(i=0;i<this->report_templates.count();i++) {
+ if(this->report_templates.at(i)->Category()==report_category &&
+ this->report_templates.at(i)->Name()==report_name)
+ {
+ found=true;
+ break;
+ }
+ }
+
+ // Add to or update report template list
+ if(!found) {
+ // Add report to list
+ p_report=new ReportTemplate(report_template,
+ report_category,
+ report_name,
+ report_author,
+ report_desc,
+ report_hive);
+ this->report_templates.append(p_report);
+ } else {
+ // Update report entry
+ p_report=this->report_templates.at(i);
+ p_report->SetFile(report_template);
+ p_report->SetAuthor(report_author);
+ p_report->SetDescription(report_desc);
+ }
+ }
+}
diff --git a/tags/fred-0.2.0/reports.h b/tags/fred-0.2.0/reports.h
new file mode 100644
index 0000000..db3f230
--- /dev/null
+++ b/tags/fred-0.2.0/reports.h
@@ -0,0 +1,57 @@
+/*******************************************************************************
+* fred Copyright (c) 2011-2020 by Gillen Daniel <gillen.dan@pinguin.lu> *
+* *
+* Forensic Registry EDitor (fred) is a cross-platform M$ registry hive editor *
+* with special feautures useful during forensic analysis. *
+* *
+* This program is free software: you can redistribute it and/or modify it *
+* under the terms of the GNU General Public License as published by the Free *
+* Software Foundation, either version 3 of the License, or (at your option) *
+* any later version. *
+* *
+* This program is distributed in the hope that it will be useful, but WITHOUT *
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or *
+* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for *
+* more details. *
+* *
+* You should have received a copy of the GNU General Public License along with *
+* this program. If not, see <http://www.gnu.org/licenses/>. *
+*******************************************************************************/
+
+#ifndef REPORTS_H
+#define REPORTS_H
+
+#include <QList>
+#include <QString>
+#include <QStringList>
+
+#include "reporttemplate.h"
+#include "reportengine.h"
+#include "settings.h"
+
+class Reports {
+ public:
+ Reports(Settings *p_sets=NULL);
+ ~Reports();
+
+ void LoadReportTemplates();
+ QStringList GetAvailableReportCategories();
+ QList<ReportTemplate*> GetAvailableReports(QString category);
+
+ bool GenerateReport(RegistryHive *p_hive,
+ QString report_file,
+ QString &report_result,
+ bool console_mode=false);
+ bool GenerateReport(RegistryHive *p_hive,
+ QList<ReportTemplate*> report_list,
+ QString &report_result,
+ bool console_mode=false);
+ private:
+ Settings *p_settings;
+ QList<ReportTemplate*> report_templates;
+ ReportEngine *p_engine;
+
+ void LoadReportTemplatesFromDir(QString dir);
+};
+
+#endif // REPORTS_H
diff --git a/tags/fred-0.2.0/reporttemplate.cpp b/tags/fred-0.2.0/reporttemplate.cpp
new file mode 100644
index 0000000..06ff213
--- /dev/null
+++ b/tags/fred-0.2.0/reporttemplate.cpp
@@ -0,0 +1,84 @@
+/*******************************************************************************
+* fred Copyright (c) 2011-2020 by Gillen Daniel <gillen.dan@pinguin.lu> *
+* *
+* Forensic Registry EDitor (fred) is a cross-platform M$ registry hive editor *
+* with special feautures useful during forensic analysis. *
+* *
+* This program is free software: you can redistribute it and/or modify it *
+* under the terms of the GNU General Public License as published by the Free *
+* Software Foundation, either version 3 of the License, or (at your option) *
+* any later version. *
+* *
+* This program is distributed in the hope that it will be useful, but WITHOUT *
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or *
+* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for *
+* more details. *
+* *
+* You should have received a copy of the GNU General Public License along with *
+* this program. If not, see <http://www.gnu.org/licenses/>. *
+*******************************************************************************/
+
+#include "reporttemplate.h"
+
+ReportTemplate::ReportTemplate(QString report_template_file,
+ QString report_category,
+ QString report_name,
+ QString report_author,
+ QString report_desc,
+ QString report_hive)
+{
+ this->template_file=report_template_file;
+ this->category=report_category;
+ this->name=report_name;
+ this->author=report_author;
+ this->description=report_desc;
+ this->hive=report_hive;
+}
+
+void ReportTemplate::SetFile(QString new_file) {
+ this->template_file=new_file;
+}
+
+void ReportTemplate::SetCategory(QString new_category) {
+ this->category=new_category;
+}
+
+void ReportTemplate::SetName(QString new_name) {
+ this->name=new_name;
+}
+
+void ReportTemplate::SetAuthor(QString new_author) {
+ this->author=new_author;
+}
+
+void ReportTemplate::SetDescription(QString new_desc) {
+ this->description=new_desc;
+}
+
+void ReportTemplate::SetHive(QString new_hive) {
+ this->hive=new_hive;
+}
+
+QString ReportTemplate::ReportTemplate::File() {
+ return this->template_file;
+}
+
+QString ReportTemplate::ReportTemplate::Category() {
+ return this->category;
+}
+
+QString ReportTemplate::ReportTemplate::Name() {
+ return this->name;
+}
+
+QString ReportTemplate::ReportTemplate::Author() {
+ return this->author;
+}
+
+QString ReportTemplate::ReportTemplate::Description() {
+ return this->description;
+}
+
+QString ReportTemplate::ReportTemplate::Hive() {
+ return this->hive;
+}
diff --git a/tags/fred-0.2.0/reporttemplate.h b/tags/fred-0.2.0/reporttemplate.h
new file mode 100644
index 0000000..c4c9260
--- /dev/null
+++ b/tags/fred-0.2.0/reporttemplate.h
@@ -0,0 +1,61 @@
+/*******************************************************************************
+* fred Copyright (c) 2011-2020 by Gillen Daniel <gillen.dan@pinguin.lu> *
+* *
+* Forensic Registry EDitor (fred) is a cross-platform M$ registry hive editor *
+* with special feautures useful during forensic analysis. *
+* *
+* This program is free software: you can redistribute it and/or modify it *
+* under the terms of the GNU General Public License as published by the Free *
+* Software Foundation, either version 3 of the License, or (at your option) *
+* any later version. *
+* *
+* This program is distributed in the hope that it will be useful, but WITHOUT *
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or *
+* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for *
+* more details. *
+* *
+* You should have received a copy of the GNU General Public License along with *
+* this program. If not, see <http://www.gnu.org/licenses/>. *
+*******************************************************************************/
+
+#ifndef REPORTTEMPLATE_H
+#define REPORTTEMPLATE_H
+
+#include <QMetaType>
+#include <QString>
+
+class ReportTemplate {
+ public:
+ ReportTemplate(QString report_template_file,
+ QString report_category,
+ QString report_name,
+ QString report_author,
+ QString report_desc,
+ QString report_hive);
+
+ void SetFile(QString new_file);
+ void SetCategory(QString new_category);
+ void SetName(QString new_name);
+ void SetAuthor(QString new_author);
+ void SetDescription(QString new_desc);
+ void SetHive(QString new_hive);
+
+ QString File();
+ QString Category();
+ QString Name();
+ QString Author();
+ QString Description();
+ QString Hive();
+
+ private:
+ QString template_file;
+ QString category;
+ QString name;
+ QString author;
+ QString description;
+ QString hive;
+};
+
+Q_DECLARE_METATYPE(ReportTemplate*)
+
+#endif // REPORTTEMPLATE_H
diff --git a/tags/fred-0.2.0/resources/close_button.jpg b/tags/fred-0.2.0/resources/close_button.jpg
new file mode 100644
index 0000000..764839c
Binary files /dev/null and b/tags/fred-0.2.0/resources/close_button.jpg differ
diff --git a/tags/fred-0.2.0/resources/fred.desktop b/tags/fred-0.2.0/resources/fred.desktop
new file mode 100755
index 0000000..8e16128
--- /dev/null
+++ b/tags/fred-0.2.0/resources/fred.desktop
@@ -0,0 +1,11 @@
+[Desktop Entry]
+Version=1.0
+Encoding=UTF-8
+Name=Fred
+Type=Application
+Comment=M$ registry hive editor
+Terminal=false
+Exec=fred
+Icon=fred
+Categories=System;
+StartupNotify=true
diff --git a/tags/fred-0.2.0/resources/fred.icns b/tags/fred-0.2.0/resources/fred.icns
new file mode 100644
index 0000000..a6da484
Binary files /dev/null and b/tags/fred-0.2.0/resources/fred.icns differ
diff --git a/tags/fred-0.2.0/resources/fred.ico b/tags/fred-0.2.0/resources/fred.ico
new file mode 100644
index 0000000..e06b47b
Binary files /dev/null and b/tags/fred-0.2.0/resources/fred.ico differ
diff --git a/tags/fred-0.2.0/resources/fred.png b/tags/fred-0.2.0/resources/fred.png
new file mode 100644
index 0000000..6e1124c
Binary files /dev/null and b/tags/fred-0.2.0/resources/fred.png differ
diff --git a/tags/fred-0.2.0/resources/tux.xcf b/tags/fred-0.2.0/resources/tux.xcf
new file mode 100644
index 0000000..676afc2
Binary files /dev/null and b/tags/fred-0.2.0/resources/tux.xcf differ
diff --git a/tags/fred-0.2.0/searchresulttabledelegate.cpp b/tags/fred-0.2.0/searchresulttabledelegate.cpp
new file mode 100644
index 0000000..64af56c
--- /dev/null
+++ b/tags/fred-0.2.0/searchresulttabledelegate.cpp
@@ -0,0 +1,38 @@
+/*******************************************************************************
+* fred Copyright (c) 2011-2020 by Gillen Daniel <gillen.dan@pinguin.lu> *
+* *
+* Forensic Registry EDitor (fred) is a cross-platform M$ registry hive editor *
+* with special feautures useful during forensic analysis. *
+* *
+* This program is free software: you can redistribute it and/or modify it *
+* under the terms of the GNU General Public License as published by the Free *
+* Software Foundation, either version 3 of the License, or (at your option) *
+* any later version. *
+* *
+* This program is distributed in the hope that it will be useful, but WITHOUT *
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or *
+* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for *
+* more details. *
+* *
+* You should have received a copy of the GNU General Public License along with *
+* this program. If not, see <http://www.gnu.org/licenses/>. *
+*******************************************************************************/
+
+#include "searchresulttabledelegate.h"
+
+SearchResultTableDelegate::SearchResultTableDelegate(QObject *parent) :
+ QStyledItemDelegate(parent)
+{
+}
+
+void SearchResultTableDelegate::paint(QPainter *painter,
+ const QStyleOptionViewItem &option,
+ const QModelIndex &index) const
+{
+ if(index.isValid() && index.column()==2) {
+ // TODO: Render match string different
+ QStyledItemDelegate::paint(painter,option,index);
+ } else {
+ QStyledItemDelegate::paint(painter,option,index);
+ }
+}
diff --git a/tags/fred-0.2.0/searchresulttabledelegate.h b/tags/fred-0.2.0/searchresulttabledelegate.h
new file mode 100644
index 0000000..e358710
--- /dev/null
+++ b/tags/fred-0.2.0/searchresulttabledelegate.h
@@ -0,0 +1,36 @@
+/*******************************************************************************
+* fred Copyright (c) 2011-2020 by Gillen Daniel <gillen.dan@pinguin.lu> *
+* *
+* Forensic Registry EDitor (fred) is a cross-platform M$ registry hive editor *
+* with special feautures useful during forensic analysis. *
+* *
+* This program is free software: you can redistribute it and/or modify it *
+* under the terms of the GNU General Public License as published by the Free *
+* Software Foundation, either version 3 of the License, or (at your option) *
+* any later version. *
+* *
+* This program is distributed in the hope that it will be useful, but WITHOUT *
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or *
+* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for *
+* more details. *
+* *
+* You should have received a copy of the GNU General Public License along with *
+* this program. If not, see <http://www.gnu.org/licenses/>. *
+*******************************************************************************/
+
+#ifndef SEARCHRESULTTABLEDELEGATE_H
+#define SEARCHRESULTTABLEDELEGATE_H
+
+#include <QStyledItemDelegate>
+
+class SearchResultTableDelegate : public QStyledItemDelegate {
+ Q_OBJECT
+
+ public:
+ explicit SearchResultTableDelegate(QObject *parent = 0);
+ void paint(QPainter *painter,
+ const QStyleOptionViewItem &option,
+ const QModelIndex &index) const;
+};
+
+#endif // SEARCHRESULTTABLEDELEGATE_H
diff --git a/tags/fred-0.2.0/searchresultwidget.cpp b/tags/fred-0.2.0/searchresultwidget.cpp
new file mode 100644
index 0000000..5135ec0
--- /dev/null
+++ b/tags/fred-0.2.0/searchresultwidget.cpp
@@ -0,0 +1,124 @@
+/*******************************************************************************
+* fred Copyright (c) 2011-2020 by Gillen Daniel <gillen.dan@pinguin.lu> *
+* *
+* Forensic Registry EDitor (fred) is a cross-platform M$ registry hive editor *
+* with special feautures useful during forensic analysis. *
+* *
+* This program is free software: you can redistribute it and/or modify it *
+* under the terms of the GNU General Public License as published by the Free *
+* Software Foundation, either version 3 of the License, or (at your option) *
+* any later version. *
+* *
+* This program is distributed in the hope that it will be useful, but WITHOUT *
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or *
+* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for *
+* more details. *
+* *
+* You should have received a copy of the GNU General Public License along with *
+* this program. If not, see <http://www.gnu.org/licenses/>. *
+*******************************************************************************/
+
+#include <QHeaderView>
+#include <QAbstractItemView>
+#include <QStringList>
+#include <QTableWidgetItem>
+#include <QFontMetrics>
+//#include <QTextEdit>
+
+#include "searchresultwidget.h"
+
+SearchResultWidget::SearchResultWidget(QWidget *p_parent)
+ : QTableWidget(p_parent)
+{
+ // Create our delegate instance
+ this->p_delegate=new SearchResultTableDelegate();
+ this->setItemDelegate(this->p_delegate);
+ this->setColumnCount(3);
+ this->setRowCount(0);
+ this->setTextElideMode(Qt::ElideNone);
+ this->verticalHeader()->setHidden(true);
+ this->setSelectionBehavior(QAbstractItemView::SelectRows);
+ this->setSelectionMode(QAbstractItemView::SingleSelection);
+ this->setHorizontalScrollMode(QAbstractItemView::ScrollPerPixel);
+ this->setHorizontalHeaderLabels(QStringList()<<tr("Path")
+ <<tr("Match type")
+ <<tr("Match text"));
+}
+
+SearchResultWidget::~SearchResultWidget() {
+ delete this->p_delegate;
+}
+
+void SearchResultWidget::SlotFoundMatch(ThreadSearch::eMatchType match_type,
+ QString path,
+ QString key,
+ QString value)
+{
+ QTableWidgetItem *p_item;
+// QTextEdit* p_te;
+
+ QString full_path;
+ QString type;
+ QString match;
+
+ switch(match_type) {
+ case ThreadSearch::eMatchType_NodeName:
+ type=tr("Node name");
+ full_path=path;
+ match=key;
+ break;
+ case ThreadSearch::eMatchType_KeyName:
+ type=tr("Key name");
+ full_path=path;
+ match=key;
+ break;
+ case ThreadSearch::eMatchType_KeyValue:
+ type=tr("Key value");
+ full_path=path+"\\"+key;
+ //if(value.length()<6934) match=value;
+ //else
+ //match=value.left(5610);
+ //match=QString(value);
+ match=value;
+ break;
+ }
+
+ int rows=this->rowCount();
+ this->setRowCount(rows+1);
+ // TODO: Use setCellWidget to add QTextEdit and then use insertText and
+ // insertHtml to format match
+ p_item=new QTableWidgetItem(full_path=="" ? "\\" : full_path);
+ p_item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
+ this->setItem(rows,0,p_item);
+ p_item=new QTableWidgetItem(type);
+ p_item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
+ this->setItem(rows,1,p_item);
+ p_item=new QTableWidgetItem(match);
+ p_item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
+ this->setItem(rows,2,p_item);
+// p_te=new QTextEdit(match);
+// p_te->setReadOnly(true);
+// this->setCellWidget(rows,2,p_te);
+}
+
+int SearchResultWidget::sizeHintForColumn(int column) const {
+ int size_hint=0;
+ int i=0;
+ int item_width=0;
+ QFontMetrics fm(this->fontMetrics());
+
+// if(column<0 || column>=this->columnCount()) return -1;
+
+ // Find string that needs the most amount of space
+ for(i=0;i<this->rowCount();i++) {
+ item_width=fm.width(this->item(i,column)->text())+10;
+ if(item_width>size_hint) size_hint=item_width;
+ }
+
+ return size_hint;
+}
+
+void SearchResultWidget::SlotSearchFinished() {
+ this->resizeColumnsToContents();
+ this->resizeRowsToContents();
+}
diff --git a/tags/fred-0.2.0/searchresultwidget.h b/tags/fred-0.2.0/searchresultwidget.h
new file mode 100644
index 0000000..cd27288
--- /dev/null
+++ b/tags/fred-0.2.0/searchresultwidget.h
@@ -0,0 +1,48 @@
+/*******************************************************************************
+* fred Copyright (c) 2011-2020 by Gillen Daniel <gillen.dan@pinguin.lu> *
+* *
+* Forensic Registry EDitor (fred) is a cross-platform M$ registry hive editor *
+* with special feautures useful during forensic analysis. *
+* *
+* This program is free software: you can redistribute it and/or modify it *
+* under the terms of the GNU General Public License as published by the Free *
+* Software Foundation, either version 3 of the License, or (at your option) *
+* any later version. *
+* *
+* This program is distributed in the hope that it will be useful, but WITHOUT *
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or *
+* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for *
+* more details. *
+* *
+* You should have received a copy of the GNU General Public License along with *
+* this program. If not, see <http://www.gnu.org/licenses/>. *
+*******************************************************************************/
+
+#ifndef SEARCHRESULTWIDGET_H
+#define SEARCHRESULTWIDGET_H
+
+#include <QTableWidget>
+
+#include "threadsearch.h"
+#include "searchresulttabledelegate.h"
+
+class SearchResultWidget : public QTableWidget {
+ Q_OBJECT
+
+ public:
+ SearchResultWidget(QWidget *p_parent=0);
+ ~SearchResultWidget();
+
+ public slots:
+ void SlotFoundMatch(ThreadSearch::eMatchType match_type,
+ QString path,
+ QString key,
+ QString value);
+ void SlotSearchFinished();
+
+ protected:
+ int sizeHintForColumn(int column) const;
+ SearchResultTableDelegate *p_delegate;
+};
+
+#endif // SEARCHRESULTWIDGET_H
diff --git a/tags/fred-0.2.0/settings.cpp b/tags/fred-0.2.0/settings.cpp
new file mode 100644
index 0000000..0772d5b
--- /dev/null
+++ b/tags/fred-0.2.0/settings.cpp
@@ -0,0 +1,206 @@
+/*******************************************************************************
+* fred Copyright (c) 2011-2020 by Gillen Daniel <gillen.dan@pinguin.lu> *
+* *
+* Forensic Registry EDitor (fred) is a cross-platform M$ registry hive editor *
+* with special feautures useful during forensic analysis. *
+* *
+* This program is free software: you can redistribute it and/or modify it *
+* under the terms of the GNU General Public License as published by the Free *
+* Software Foundation, either version 3 of the License, or (at your option) *
+* any later version. *
+* *
+* This program is distributed in the hope that it will be useful, but WITHOUT *
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or *
+* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for *
+* more details. *
+* *
+* You should have received a copy of the GNU General Public License along with *
+* this program. If not, see <http://www.gnu.org/licenses/>. *
+*******************************************************************************/
+
+#include <QDir>
+
+#include "settings.h"
+
+#ifndef SYSTEM_REPORT_TEMPLATE_DIR
+ #ifndef __MINGW32__
+ #define SYSTEM_REPORT_TEMPLATE_DIR "/usr/share/fred/report_templates"
+ #else
+ #define SYSTEM_REPORT_TEMPLATE_DIR ".\\report_templates\\"
+ #endif
+#endif
+
+#define APP_ORGANIZATION "pinguin.lu"
+#define APP_NAME "fred"
+
+// Default settings
+#define DEFAULT_REPORT_TEMPLATE_DIRS QStringList()<<SYSTEM_REPORT_TEMPLATE_DIR \
+ <<this->user_report_template_dir
+#define DEFAULT_WINDOW_GEOMETRY_STATUS true
+#define DEFAULT_RECENT_FILES_DEPTH 5
+#define DEFAULT_LAST_OPEN_LOCATION QDir::homePath()
+#define DEFAULT_OPEN_HIVES_READ_ONLY true
+
+/*******************************************************************************
+ * Public
+ ******************************************************************************/
+
+Settings::Settings(QObject *p_parent) : QObject(p_parent) {
+ // Init vars
+ this->p_settings=NULL;
+ this->initialized=false;
+ this->user_settings_dir=QDir::homePath()
+ .append(QDir::separator()).append(".fred");
+ this->user_report_template_dir=QString(this->user_settings_dir)
+ .append(QDir::separator())
+ .append("report_templates");
+
+ // Make sure config dirs exist
+ if(!QDir(this->user_settings_dir).exists()) {
+ // User config dir does not exists, try to create it
+ if(!QDir().mkpath(this->user_settings_dir)) {
+ // TODO: Maybe warn user
+ return;
+ }
+ }
+ if(!QDir(this->user_report_template_dir).exists()) {
+ // Create config dir sub folder for report templates
+ if(!QDir().mkpath(this->user_report_template_dir)) {
+ // TODO: Maybe warn user
+ return;
+ }
+ }
+
+ // Create / open settings
+#ifndef __MINGW32__
+ // On any Unix-like OS, settings should be saved in the .fred folder
+ this->p_settings=new QSettings(QString(this->user_settings_dir)
+ .append(QDir::separator())
+ .append("fred.conf"),
+ QSettings::NativeFormat,
+ this);
+#else
+ // On Windows, it can be stored inside registry
+ this->p_settings=new QSettings(QSettings::NativeFormat,
+ QSettings::UserScope,
+ APP_ORGANIZATION,
+ APP_NAME,
+ this);
+#endif
+ if(this->p_settings->status()!=QSettings::NoError ||
+ !this->p_settings->isWritable())
+ {
+ return;
+ }
+
+ this->initialized=true;
+}
+
+void Settings::Reset() {
+ if(!this->initialized) return;
+ // Clear all current settings
+ this->p_settings->clear();
+}
+
+void Settings::SetReportTemplateDirs(QStringList &dirs) {
+ if(!this->initialized) return;
+ this->p_settings->setValue("ReportTemplateDirs",dirs);
+}
+
+QStringList Settings::GetReportTemplateDirs() {
+ if(!this->initialized) return DEFAULT_REPORT_TEMPLATE_DIRS;
+ return this->p_settings->value("ReportTemplateDirs",
+ DEFAULT_REPORT_TEMPLATE_DIRS).toStringList();
+}
+
+void Settings::SetWindowGeometryStatus(bool save) {
+ if(!this->initialized) return;
+ this->p_settings->setValue("WindowGeometries/EnableSaving",save);
+}
+
+bool Settings::GetWindowGeometryStatus() {
+ if(!this->initialized) return DEFAULT_WINDOW_GEOMETRY_STATUS;
+ return this->p_settings->value("WindowGeometries/EnableSaving",
+ DEFAULT_WINDOW_GEOMETRY_STATUS).toBool();
+}
+
+void Settings::SetWindowGeometry(QString window_name, QByteArray geometry) {
+ if(!this->initialized || !this->GetWindowGeometryStatus()) return;
+ this->p_settings->setValue(QString("WindowGeometries/%1").arg(window_name),
+ geometry);
+}
+
+QByteArray Settings::GetWindowGeometry(QString window_name) {
+ if(!this->initialized || !this->GetWindowGeometryStatus()) {
+ return QByteArray();
+ }
+ return this->p_settings->value(QString("WindowGeometries/%1")
+ .arg(window_name)).toByteArray();
+}
+
+void Settings::SetRecentFilesDepth(int depth) {
+ if(!this->initialized) return;
+ this->p_settings->setValue("RecentFilesDepth",depth);
+ // Make sure there are currently not more recent files as allowed
+ QStringList recent_files=this->GetRecentFiles();
+ while(recent_files.count()>depth) recent_files.removeLast();
+ this->SetRecentFiles(recent_files);
+}
+
+int Settings::GetRecentFilesDepth() {
+ if(!this->initialized) return DEFAULT_RECENT_FILES_DEPTH;
+ return this->p_settings->value("RecentFilesDepth",
+ DEFAULT_RECENT_FILES_DEPTH).toInt();
+}
+
+void Settings::SetRecentFiles(QStringList &recent_files) {
+ if(!this->initialized) return;
+ this->p_settings->setValue("RecentFiles",recent_files);
+}
+
+void Settings::AddRecentFile(QString file) {
+ // Get recent files
+ QStringList recent_files=this->GetRecentFiles();
+
+ if(recent_files.contains(file)) {
+ // File already exists in recent list. Simply move it to top
+ recent_files.move(recent_files.indexOf(file),0);
+ } else {
+ // We only save RecentFilesDepth() files at max
+ while(recent_files.count()>=this->GetRecentFilesDepth())
+ recent_files.removeLast();
+ recent_files.prepend(file);
+ }
+
+ this->SetRecentFiles(recent_files);
+}
+
+QStringList Settings::GetRecentFiles() {
+ if(!this->initialized) return QStringList();
+ return this->p_settings->value("RecentFiles",QStringList()).toStringList();
+}
+
+void Settings::SetLastOpenLocation(QString dir) {
+ if(!this->initialized) return;
+ this->p_settings->setValue("LastOpenLocation",dir);
+}
+
+QString Settings::GetLastOpenLocation() {
+ if(!this->initialized) return DEFAULT_LAST_OPEN_LOCATION;
+ QString last_loc;
+ last_loc=this->p_settings->value("RecentFiles",
+ DEFAULT_LAST_OPEN_LOCATION).toString();
+ if(QDir(last_loc).exists()) return last_loc;
+ else return DEFAULT_LAST_OPEN_LOCATION;
+}
+
+void Settings::SetOpenHivesReadOnly(bool read_only) {
+ if(!this->initialized) return;
+ this->p_settings->setValue("OpenFilesReadOnly",read_only);
+}
+
+bool Settings::GetOpenHivesReadOnly() {
+ if(!this->initialized) return DEFAULT_OPEN_HIVES_READ_ONLY;
+ return this->p_settings->value("OpenFilesReadOnly",
+ DEFAULT_OPEN_HIVES_READ_ONLY).toBool();
+}
diff --git a/tags/fred-0.2.0/settings.h b/tags/fred-0.2.0/settings.h
new file mode 100644
index 0000000..3a1428a
--- /dev/null
+++ b/tags/fred-0.2.0/settings.h
@@ -0,0 +1,65 @@
+/*******************************************************************************
+* fred Copyright (c) 2011-2020 by Gillen Daniel <gillen.dan@pinguin.lu> *
+* *
+* Forensic Registry EDitor (fred) is a cross-platform M$ registry hive editor *
+* with special feautures useful during forensic analysis. *
+* *
+* This program is free software: you can redistribute it and/or modify it *
+* under the terms of the GNU General Public License as published by the Free *
+* Software Foundation, either version 3 of the License, or (at your option) *
+* any later version. *
+* *
+* This program is distributed in the hope that it will be useful, but WITHOUT *
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or *
+* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for *
+* more details. *
+* *
+* You should have received a copy of the GNU General Public License along with *
+* this program. If not, see <http://www.gnu.org/licenses/>. *
+*******************************************************************************/
+
+#ifndef SETTINGS_H
+#define SETTINGS_H
+
+#include <QObject>
+#include <QSettings>
+#include <QString>
+#include <QStringList>
+#include <QByteArray>
+
+class Settings : public QObject {
+ Q_OBJECT
+
+ public:
+ explicit Settings(QObject *p_parent=0);
+
+ void Reset();
+
+ void SetReportTemplateDirs(QStringList &dirs);
+ QStringList GetReportTemplateDirs();
+
+ void SetWindowGeometryStatus(bool save);
+ bool GetWindowGeometryStatus();
+ void SetWindowGeometry(QString window_name, QByteArray geometry);
+ QByteArray GetWindowGeometry(QString window_name);
+
+ void SetRecentFilesDepth(int depth);
+ int GetRecentFilesDepth();
+ void SetRecentFiles(QStringList &recent_files);
+ void AddRecentFile(QString file);
+ QStringList GetRecentFiles();
+
+ void SetLastOpenLocation(QString dir);
+ QString GetLastOpenLocation();
+
+ void SetOpenHivesReadOnly(bool read_only);
+ bool GetOpenHivesReadOnly();
+
+ private:
+ QSettings *p_settings;
+ bool initialized;
+ QString user_settings_dir;
+ QString user_report_template_dir;
+};
+
+#endif // SETTINGS_H
diff --git a/tags/fred-0.2.0/tabwidget.cpp b/tags/fred-0.2.0/tabwidget.cpp
new file mode 100644
index 0000000..47ea147
--- /dev/null
+++ b/tags/fred-0.2.0/tabwidget.cpp
@@ -0,0 +1,65 @@
+/*******************************************************************************
+* fred Copyright (c) 2011-2020 by Gillen Daniel <gillen.dan@pinguin.lu> *
+* *
+* Forensic Registry EDitor (fred) is a cross-platform M$ registry hive editor *
+* with special feautures useful during forensic analysis. *
+* *
+* This program is free software: you can redistribute it and/or modify it *
+* under the terms of the GNU General Public License as published by the Free *
+* Software Foundation, either version 3 of the License, or (at your option) *
+* any later version. *
+* *
+* This program is distributed in the hope that it will be useful, but WITHOUT *
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or *
+* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for *
+* more details. *
+* *
+* You should have received a copy of the GNU General Public License along with *
+* this program. If not, see <http://www.gnu.org/licenses/>. *
+*******************************************************************************/
+
+#include <QTabBar>
+#include <QPushButton>
+#include <QIcon>
+#include <QSize>
+#include <QPoint>
+
+#include "tabwidget.h"
+
+TabWidget::TabWidget(QWidget *p_parent) : QTabWidget(p_parent) {}
+
+int TabWidget::addTab(QWidget *p_widget,
+ const QString &title,
+ bool close_button)
+{
+ // Add tab
+ int tab_index=QTabWidget::addTab(p_widget,title);
+
+ // If desired, add a close button to the tab
+ if(close_button) {
+ // Create close button
+ QPushButton *p_close_button=
+ new QPushButton(QIcon(":/icons/close_button"),QString());
+ p_close_button->setFlat(true);
+ p_close_button->setIconSize(QSize(14,14));
+ p_close_button->setGeometry(p_close_button->x(),p_close_button->y(),14,14);
+ // Connect clicked signal
+ this->connect(p_close_button,
+ SIGNAL(clicked()),
+ this,
+ SLOT(SlotCloseButtonClicked()));
+ this->tabBar()->setTabButton(tab_index,QTabBar::RightSide,p_close_button);
+ }
+
+ return tab_index;
+}
+
+void TabWidget::SlotCloseButtonClicked() {
+ // Find index of tab to close. The trolls do it by iterating over all tabs
+ // and comparing their widget with QObject::sender().
+ QPushButton *p_close_button=(QPushButton*)(QObject::sender());
+ int index=this->tabBar()->tabAt(QPoint(p_close_button->x(),
+ p_close_button->y()));
+ // Emit tabCloseRequested
+ emit(this->tabCloseRequested(index));
+}
diff --git a/tags/fred-0.2.0/tabwidget.h b/tags/fred-0.2.0/tabwidget.h
new file mode 100644
index 0000000..15adca4
--- /dev/null
+++ b/tags/fred-0.2.0/tabwidget.h
@@ -0,0 +1,41 @@
+/*******************************************************************************
+* fred Copyright (c) 2011-2020 by Gillen Daniel <gillen.dan@pinguin.lu> *
+* *
+* Forensic Registry EDitor (fred) is a cross-platform M$ registry hive editor *
+* with special feautures useful during forensic analysis. *
+* *
+* This program is free software: you can redistribute it and/or modify it *
+* under the terms of the GNU General Public License as published by the Free *
+* Software Foundation, either version 3 of the License, or (at your option) *
+* any later version. *
+* *
+* This program is distributed in the hope that it will be useful, but WITHOUT *
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or *
+* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for *
+* more details. *
+* *
+* You should have received a copy of the GNU General Public License along with *
+* this program. If not, see <http://www.gnu.org/licenses/>. *
+*******************************************************************************/
+
+#ifndef TABWIDGET_H
+#define TABWIDGET_H
+
+#include <QTabWidget>
+#include <QString>
+
+class TabWidget : public QTabWidget {
+ Q_OBJECT
+
+ public:
+ TabWidget(QWidget *p_parent);
+
+ int addTab(QWidget *p_widget,
+ const QString &title,
+ bool close_button=false);
+
+ private slots:
+ void SlotCloseButtonClicked();
+};
+
+#endif // TABWIDGET_H
diff --git a/tags/fred-0.2.0/threadsearch.cpp b/tags/fred-0.2.0/threadsearch.cpp
new file mode 100644
index 0000000..39e6efc
--- /dev/null
+++ b/tags/fred-0.2.0/threadsearch.cpp
@@ -0,0 +1,195 @@
+/*******************************************************************************
+* fred Copyright (c) 2011-2020 by Gillen Daniel <gillen.dan@pinguin.lu> *
+* *
+* Forensic Registry EDitor (fred) is a cross-platform M$ registry hive editor *
+* with special feautures useful during forensic analysis. *
+* *
+* This program is free software: you can redistribute it and/or modify it *
+* under the terms of the GNU General Public License as published by the Free *
+* Software Foundation, either version 3 of the License, or (at your option) *
+* any later version. *
+* *
+* This program is distributed in the hope that it will be useful, but WITHOUT *
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or *
+* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for *
+* more details. *
+* *
+* You should have received a copy of the GNU General Public License along with *
+* this program. If not, see <http://www.gnu.org/licenses/>. *
+*******************************************************************************/
+
+#include <QStringList>
+#include <QMetaType>
+
+#include "threadsearch.h"
+#include "registryhive.h"
+
+ThreadSearch::ThreadSearch(QObject *p_parent) : QThread(p_parent) {
+ this->hive_file="";
+ this->h_hive=NULL;
+ this->keywords=QList<QByteArray>();
+ this->search_nodes=false;
+ this->search_keys=false;
+ this->search_values=false;
+ this->root_node=0;
+
+ // Register meta types to be used in signals
+ qRegisterMetaType<ThreadSearch::eMatchType>("ThreadSearch::eMatchType");
+}
+
+bool ThreadSearch::Search(QString registry_hive,
+ QList<QByteArray> search_keywords,
+ bool search_node_names,
+ bool search_key_names,
+ bool search_key_values,
+ QString search_path)
+{
+ this->hive_file=registry_hive;
+ this->keywords=search_keywords;
+ this->search_nodes=search_node_names;
+ this->search_keys=search_key_names;
+ this->search_values=search_key_values;
+ this->root_path=search_path=="\\" ? "" : search_path;
+
+ // Try to open hive
+ this->h_hive=hivex_open(this->hive_file.toLatin1().constData(),0);
+ if(this->h_hive==NULL) return false;
+
+ // Get root node
+ this->root_node=hivex_root(this->h_hive);
+ if(this->root_node==0) {
+ hivex_close(this->h_hive);
+ return false;
+ }
+
+ // If a root path was specified, iterate to it
+ if(this->root_path!="") {
+ QStringList path_nodes=search_path.split("\\",QString::SkipEmptyParts);
+ int i;
+ for(i=0;i<path_nodes.count();i++) {
+ this->root_node=hivex_node_get_child(this->h_hive,
+ this->root_node,
+ path_nodes.at(i).toLatin1().constData());
+ if(this->root_node==0) {
+ hivex_close(this->h_hive);
+ return false;
+ }
+ }
+ }
+
+ this->start();
+ return true;
+}
+
+void ThreadSearch::run() {
+ this->Match();
+ hivex_close(this->h_hive);
+}
+
+void ThreadSearch::Match(QString path, hive_node_h node) {
+ char *p_node_name;
+ int i,ii;
+ hive_node_h *p_node_childs;
+ QByteArray *p_byte_array;
+
+ if(node!=0) {
+
+ p_node_name=hivex_node_name(this->h_hive,node);
+ if(p_node_name==NULL) return;
+
+ if(this->search_nodes) {
+ // Compare node name to keywords
+ p_byte_array=new QByteArray(p_node_name);
+ for(i=0;i<this->keywords.count();i++) {
+ if(p_byte_array->indexOf(this->keywords.at(i))!=-1) {
+ emit(SignalFoundMatch(ThreadSearch::eMatchType_NodeName,
+ path,
+ QString(p_node_name),
+ QString()));
+ break;
+ }
+ }
+ delete p_byte_array;
+ }
+
+ if(this->search_keys || this->search_values) {
+ // Get key,value pairs for current node
+ hive_value_h *p_keys=hivex_node_values(this->h_hive,node);
+ if(p_keys==NULL) {
+ delete p_node_name;
+ return;
+ }
+
+ if(this->search_keys) {
+ // Compare key names to keywords
+ char *p_keyname;
+ for(i=0;p_keys[i];i++) {
+ p_keyname=hivex_value_key(this->h_hive,p_keys[i]);
+ if(p_keyname==NULL) continue;
+ p_byte_array=new QByteArray(p_keyname);
+ for(ii=0;ii<this->keywords.count();ii++) {
+ if(p_byte_array->indexOf(this->keywords.at(ii))!=-1) {
+ emit(SignalFoundMatch(ThreadSearch::eMatchType_KeyName,
+ path+"\\"+p_node_name,
+ strlen(p_keyname)==0 ? QString("(default)") : QString(p_keyname),
+ QString()));
+ break;
+ }
+ }
+ delete p_byte_array;
+ delete p_keyname;
+ }
+ }
+ if(this->search_values) {
+ // Compare key values to keywords
+ char *p_value;
+ hive_type val_type;
+ size_t val_len;
+
+ for(i=0;p_keys[i];i++) {
+ p_value=hivex_value_value(this->h_hive,p_keys[i],&val_type,&val_len);
+ if(p_value==NULL) continue;
+ p_byte_array=new QByteArray(p_value,val_len);
+ for(ii=0;ii<this->keywords.count();ii++) {
+ if(p_byte_array->indexOf(this->keywords.at(ii))!=-1) {
+ char *p_keyname=hivex_value_key(this->h_hive,p_keys[i]);
+ if(p_keyname==NULL) continue;
+ emit(SignalFoundMatch(ThreadSearch::eMatchType_KeyValue,
+ path+"\\"+p_node_name,
+ strlen(p_keyname)==0 ? QString("(default)") : QString(p_keyname),
+ RegistryHive::KeyValueToString(*p_byte_array,val_type)));
+ delete p_keyname;
+ break;
+ }
+ }
+ delete p_byte_array;
+ delete p_value;
+ }
+
+ }
+ delete p_keys;
+ }
+
+ // Search in subnodes
+ p_node_childs=hivex_node_children(this->h_hive,node);
+ if(p_node_childs!=NULL) {
+ i=0;
+ while(p_node_childs[i]) {
+ this->Match(path+"\\"+p_node_name,p_node_childs[i]);
+ i++;
+ }
+ delete p_node_childs;
+ }
+ delete p_node_name;
+ } else {
+ p_node_childs=hivex_node_children(this->h_hive,this->root_node);
+ if(p_node_childs!=NULL) {
+ i=0;
+ while(p_node_childs[i]) {
+ this->Match(this->root_path,p_node_childs[i]);
+ i++;
+ }
+ delete p_node_childs;
+ }
+ }
+}
diff --git a/tags/fred-0.2.0/threadsearch.h b/tags/fred-0.2.0/threadsearch.h
new file mode 100644
index 0000000..1c39938
--- /dev/null
+++ b/tags/fred-0.2.0/threadsearch.h
@@ -0,0 +1,77 @@
+/*******************************************************************************
+* fred Copyright (c) 2011-2020 by Gillen Daniel <gillen.dan@pinguin.lu> *
+* *
+* Forensic Registry EDitor (fred) is a cross-platform M$ registry hive editor *
+* with special feautures useful during forensic analysis. *
+* *
+* This program is free software: you can redistribute it and/or modify it *
+* under the terms of the GNU General Public License as published by the Free *
+* Software Foundation, either version 3 of the License, or (at your option) *
+* any later version. *
+* *
+* This program is distributed in the hope that it will be useful, but WITHOUT *
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or *
+* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for *
+* more details. *
+* *
+* You should have received a copy of the GNU General Public License along with *
+* this program. If not, see <http://www.gnu.org/licenses/>. *
+*******************************************************************************/
+
+#ifndef THREADSEARCH_H
+#define THREADSEARCH_H
+
+#include <QThread>
+#include <QObject>
+#include <QString>
+#include <QList>
+#include <QByteArray>
+
+#ifndef HIVEX_STATIC
+ #include <hivex.h>
+#else
+ #include "hivex/lib/hivex.h"
+#endif
+
+class ThreadSearch : public QThread {
+ Q_OBJECT
+
+ public:
+ enum eMatchType {
+ eMatchType_NodeName=0,
+ eMatchType_KeyName,
+ eMatchType_KeyValue
+ };
+
+ ThreadSearch(QObject *p_parent=0);
+
+ bool Search(QString registry_hive,
+ QList<QByteArray> search_keywords,
+ bool search_node_names,
+ bool search_key_names,
+ bool search_key_values,
+ QString search_path="\\");
+
+ signals:
+ void SignalFoundMatch(ThreadSearch::eMatchType match_type,
+ QString path,
+ QString key,
+ QString value);
+
+ protected:
+ void run();
+
+ private:
+ QString hive_file;
+ hive_h *h_hive;
+ QList<QByteArray> keywords;
+ bool search_nodes;
+ bool search_keys;
+ bool search_values;
+ QString root_path;
+ hive_node_h root_node;
+
+ void Match(QString path="", hive_node_h node=0);
+};
+
+#endif // THREADSEARCH_H

File Metadata

Mime Type
text/x-diff
Expires
Sat, Nov 23, 4:43 PM (1 d, 11 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1162990
Default Alt Text
(771 KB)

Event Timeline