ModernKeePassLib custom PCL version

This commit is contained in:
2017-09-22 15:40:24 +02:00
parent baba70e56d
commit a43bc20eb3
98 changed files with 6049 additions and 3038 deletions

View File

@@ -1,6 +1,6 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 Dominik Reichl <dominik.reichl@t-online.de>
Copyright (C) 2003-2014 Dominik Reichl <dominik.reichl@t-online.de>
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
@@ -49,9 +49,9 @@ namespace ModernKeePassLib.Utility
try
{
string strDirSep = string.Empty;
strDirSep += Path.DirectorySeparatorChar;
strDirSep += UrlUtil.LocalDirSepChar;
string strTemp = Path.GetTempPath();
string strTemp = UrlUtil.GetTempPath();
if(!strTemp.EndsWith(strDirSep))
strTemp += strDirSep;
@@ -64,7 +64,7 @@ namespace ModernKeePassLib.Utility
strTime = strTime.Replace(':', '-');
strPath += strTime + "-" + Environment.TickCount.ToString(
CultureInfo.InvariantCulture) + ".log.gz";
NumberFormatInfo.InvariantInfo) + ".log.gz";
FileStream fsOut = new FileStream(strPath, FileMode.Create,
FileAccess.Write, FileShare.None);
@@ -81,12 +81,8 @@ namespace ModernKeePassLib.Utility
{
if(m_swOut == null) return;
Debug.Assert(false, "not yet implemented");
return;
#if TODO
m_swOut.Close();
m_swOut.Dispose();
m_swOut = null;
#endif
}
public static void Log(string strText)

View File

@@ -0,0 +1,57 @@
using System;
using System.Drawing;
using System.Globalization;
using System.Text.RegularExpressions;
namespace KeePass2PCL.Utility
{
/// <summary>
/// Replacement for System.Drawing.ColorTranslator.
/// </summary>
/// <remarks>
/// Colors are stored in the kdbx database file in HTML format (#XXXXXX).
/// </remarks>
public static class ColorTranslator
{
static Regex longForm = new Regex("^#([0-9A-Fa-f]{2})([0-9A-Fa-f]{2})([0-9A-Fa-f]{2})$");
/// <summary>
/// Converts an HTML color value to a Color.
/// </summary>
/// <returns>The Color.</returns>
/// <param name="htmlColor">HTML color code.</param>
/// <exception cref="ArgumentNullException">If htmlColor is null.</exception>
/// <exception cref="ArgumentException">If htmlColor did not match the pattern "#XXXXXX".</exception>
/// <remarks>
/// Currently only understands "#XXXXXX". "#XXX" or named colors will
/// throw and exception.
/// </remarks>
public static Color FromHtml(string htmlColor)
{
if (htmlColor == null)
throw new ArgumentNullException("htmlColor");
Match match = longForm.Match(htmlColor);
if (match.Success) {
var r = int.Parse(match.Groups[1].Value, NumberStyles.HexNumber);
var g = int.Parse(match.Groups[2].Value, NumberStyles.HexNumber);
var b = int.Parse(match.Groups[3].Value, NumberStyles.HexNumber);
return Color.FromArgb(r, g, b);
}
throw new ArgumentException(string.Format("Could not parse HTML color '{0}'.", htmlColor), "htmlColor");
}
/// <summary>
/// Converts a color to an HTML color code.
/// </summary>
/// <returns>String containing the color code.</returns>
/// <param name="htmlColor">The Color to convert</param>
/// <remarks>
/// The string is in the format "#XXXXXX"
/// </remarks>
public static string ToHtml(Color htmlColor)
{
return string.Format("#{0:x2}{1:x2}{2:x2}", htmlColor.R, htmlColor.G, htmlColor.B);
}
}
}

View File

@@ -0,0 +1,115 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2014 Dominik Reichl <dominik.reichl@t-online.de>
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 2 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, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
#if KeePass2PCL
using Splat;
#else
using System.Drawing;
using System.Drawing.Imaging;
#endif
using System.Diagnostics;
namespace KeePass2PCL.Utility
{
public static class GfxUtil
{
#if KeePassRT
public static Image LoadImage(byte[] pb)
{
MemoryStream ms = new MemoryStream(pb, false);
try { return Image.FromStream(ms); }
finally { ms.Close(); }
}
#elif KeePass2PCL
public static IBitmap LoadImage(byte[] pb)
{
using (var ms = new MemoryStream(pb, false)) {
return BitmapLoader.Current.Load(ms, null, null).Result;
}
}
#else
public static Image LoadImage(byte[] pb)
{
if(pb == null) throw new ArgumentNullException("pb");
MemoryStream ms = new MemoryStream(pb, false);
try { return LoadImagePriv(ms); }
catch(Exception)
{
Image imgIco = TryLoadIco(pb);
if(imgIco != null) return imgIco;
throw;
}
finally { ms.Close(); }
}
private static Image LoadImagePriv(Stream s)
{
// Image.FromStream wants the stream to be open during
// the whole lifetime of the image; as we can't guarantee
// this, we make a copy of the image
Image imgSrc = null;
try
{
#if !KeePassLibSD
imgSrc = Image.FromStream(s);
Bitmap bmp = new Bitmap(imgSrc.Width, imgSrc.Height,
PixelFormat.Format32bppArgb);
try
{
bmp.SetResolution(imgSrc.HorizontalResolution,
imgSrc.VerticalResolution);
Debug.Assert(bmp.Size == imgSrc.Size);
}
catch(Exception) { Debug.Assert(false); }
#else
imgSrc = new Bitmap(s);
Bitmap bmp = new Bitmap(imgSrc.Width, imgSrc.Height);
#endif
using(Graphics g = Graphics.FromImage(bmp))
{
g.Clear(Color.Transparent);
g.DrawImage(imgSrc, 0, 0);
}
return bmp;
}
finally { if(imgSrc != null) imgSrc.Dispose(); }
}
private static Image TryLoadIco(byte[] pb)
{
#if !KeePassLibSD
MemoryStream ms = new MemoryStream(pb, false);
try { return (new Icon(ms)).ToBitmap(); }
catch(Exception) { }
finally { ms.Close(); }
#endif
return null;
}
#endif
}
}

View File

@@ -1,6 +1,6 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 Dominik Reichl <dominik.reichl@t-online.de>
Copyright (C) 2003-2014 Dominik Reichl <dominik.reichl@t-online.de>
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
@@ -18,21 +18,91 @@
*/
using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
using System.IO;
#if !KeePassLibSD
using System.IO.Compression;
#else
using ModernKeePassLibSD;
using KeePassLibSD;
#endif
namespace ModernKeePassLib.Utility
{
/// <summary>
/// Contains static buffer manipulation and string conversion routines.
/// </summary>
public static class MemUtil
/// <summary>
/// Contains static buffer manipulation and string conversion routines.
/// </summary>
public static class MemUtil
{
private static readonly uint[] m_vSBox = new uint[256] {
0xCD2FACB3, 0xE78A7F5C, 0x6F0803FC, 0xBCF6E230,
0x3A321712, 0x06403DB1, 0xD2F84B95, 0xDF22A6E4,
0x07CE9E5B, 0x31788A0C, 0xF683F6F4, 0xEA061F49,
0xFA5C2ACA, 0x4B9E494E, 0xB0AB25BA, 0x767731FC,
0x261893A7, 0x2B09F2CE, 0x046261E4, 0x41367B4B,
0x18A7F225, 0x8F923C0E, 0x5EF3A325, 0x28D0435E,
0x84C22919, 0xED66873C, 0x8CEDE444, 0x7FC47C24,
0xFCFC6BA3, 0x676F928D, 0xB4147187, 0xD8FB126E,
0x7D798D17, 0xFF82E424, 0x1712FA5B, 0xABB09DD5,
0x8156BA63, 0x84E4D969, 0xC937FB9A, 0x2F1E5BFC,
0x178ECA11, 0x0E71CD5F, 0x52AAC6F4, 0x71EEFC8F,
0x7090D749, 0x21CACA31, 0x92996378, 0x0939A8A8,
0xE9EE1934, 0xD2718616, 0xF2500543, 0xB911873C,
0xD3CB3EEC, 0x2BA0DBEB, 0xB42D0A27, 0xECE67C0F,
0x302925F0, 0x6114F839, 0xD39E6307, 0xE28970D6,
0xEB982F99, 0x941B4CDF, 0xC540E550, 0x8124FC45,
0x98B025C7, 0xE2BF90EA, 0x4F57C976, 0xCF546FE4,
0x59566DC8, 0xE3F4360D, 0xF5F9D231, 0xD6180B22,
0xB54E088A, 0xB5DFE6A6, 0x3637A36F, 0x056E9284,
0xAFF8FBC5, 0x19E01648, 0x8611F043, 0xDAE44337,
0xF61B6A1C, 0x257ACD9E, 0xDD35F507, 0xEF05CAFA,
0x05EB4A83, 0xFC25CA92, 0x0A4728E6, 0x9CF150EF,
0xAEEF67DE, 0xA9472337, 0x57C81EFE, 0x3E5E009F,
0x02CB03BB, 0x2BA85674, 0xF21DC251, 0x78C34A34,
0xABB1F5BF, 0xB95A2FBD, 0x1FB47777, 0x9A96E8AC,
0x5D2D2838, 0x55AAC92A, 0x99EE324E, 0x10F6214B,
0x58ABDFB1, 0x2008794D, 0xBEC880F0, 0xE75E5341,
0x88015C34, 0x352D8FBF, 0x622B7F6C, 0xF5C59EA2,
0x1F759D8E, 0xADE56159, 0xCC7B4C25, 0x5B8BC48C,
0xB6BD15AF, 0x3C5B5110, 0xE74A7C3D, 0xEE613161,
0x156A1C67, 0x72C06817, 0xEA0A6F69, 0x4CECF993,
0xCA9D554C, 0x8E20361F, 0x42D396B9, 0x595DE578,
0x749D7955, 0xFD1BA5FD, 0x81FC160E, 0xDB97E28C,
0x7CF148F7, 0x0B0B3CF5, 0x534DE605, 0x46421066,
0xD4B68DD1, 0x9E479CE6, 0xAE667A9D, 0xBC082082,
0xB06DD6EF, 0x20F0F23F, 0xB99E1551, 0xF47A2E3A,
0x71DA50C6, 0x67B65779, 0x2A8CB376, 0x1EA71EEE,
0x29ABCD50, 0xB6EB0C6B, 0x23C10511, 0x6F3F2144,
0x6AF23012, 0xF696BD9E, 0xB94099D8, 0xAD5A9C81,
0x7A0794FA, 0x7EDF59D6, 0x1E72E574, 0x8561913C,
0x4E4D568F, 0xEECB9928, 0x9C124D2E, 0x0848B82C,
0xF1CA395F, 0x9DAF43DC, 0xF77EC323, 0x394E9B59,
0x7E200946, 0x8B811D68, 0x16DA3305, 0xAB8DE2C3,
0xE6C53B64, 0x98C2D321, 0x88A97D81, 0xA7106419,
0x8E52F7BF, 0x8ED262AF, 0x7CCA974E, 0xF0933241,
0x040DD437, 0xE143B3D4, 0x3019F56F, 0xB741521D,
0xF1745362, 0x4C435F9F, 0xB4214D0D, 0x0B0C348B,
0x5051D189, 0x4C30447E, 0x7393D722, 0x95CEDD0B,
0xDD994E80, 0xC3D22ED9, 0x739CD900, 0x131EB9C4,
0xEF1062B2, 0x4F0DE436, 0x52920073, 0x9A7F3D80,
0x896E7B1B, 0x2C8BBE5A, 0xBD304F8A, 0xA993E22C,
0x134C41A0, 0xFA989E00, 0x39CE9726, 0xFB89FCCF,
0xE8FBAC97, 0xD4063FFC, 0x935A2B5A, 0x44C8EE83,
0xCB2BC7B6, 0x02989E92, 0x75478BEA, 0x144378D0,
0xD853C087, 0x8897A34E, 0xDD23629D, 0xBDE2A2A2,
0x581D8ECC, 0x5DA8AEE8, 0xFF8AAFD0, 0xBA2BCF6E,
0x4BD98DAC, 0xF2EDB9E4, 0xFA2DC868, 0x47E84661,
0xECEB1C7D, 0x41705CA4, 0x5982E4D4, 0xEB5204A1,
0xD196CAFB, 0x6414804D, 0x3ABD4B46, 0x8B494C26,
0xB432D52B, 0x39C5356B, 0x6EC80BF7, 0x71BE5483,
0xCEC4A509, 0xE9411D61, 0x52F341E5, 0xD2E6197B,
0x4F02826C, 0xA9E48838, 0xD1F8F247, 0xE4957FB3,
0x586CCA99, 0x9A8B6A5B, 0x4998FBEA, 0xF762BE4C,
0x90DFE33C, 0x9731511E, 0x88C6A82F, 0xDD65A4D4
};
/// <summary>
/// Convert a hexadecimal string to a byte array. The input string must be
/// even (i.e. its length is a multiple of 2).
@@ -116,6 +186,63 @@ namespace ModernKeePassLib.Utility
return sb.ToString();
}
/// <summary>
/// Decode Base32 strings according to RFC 4648.
/// </summary>
public static byte[] ParseBase32(string str)
{
if((str == null) || ((str.Length % 8) != 0))
{
Debug.Assert(false);
return null;
}
ulong uMaxBits = (ulong)str.Length * 5UL;
List<byte> l = new List<byte>((int)(uMaxBits / 8UL) + 1);
Debug.Assert(l.Count == 0);
for(int i = 0; i < str.Length; i += 8)
{
ulong u = 0;
int nBits = 0;
for(int j = 0; j < 8; ++j)
{
char ch = str[i + j];
if(ch == '=') break;
ulong uValue;
if((ch >= 'A') && (ch <= 'Z'))
uValue = (ulong)(ch - 'A');
else if((ch >= 'a') && (ch <= 'z'))
uValue = (ulong)(ch - 'a');
else if((ch >= '2') && (ch <= '7'))
uValue = (ulong)(ch - '2') + 26UL;
else { Debug.Assert(false); return null; }
u <<= 5;
u += uValue;
nBits += 5;
}
int nBitsTooMany = (nBits % 8);
u >>= nBitsTooMany;
nBits -= nBitsTooMany;
Debug.Assert((nBits % 8) == 0);
int idxNewBytes = l.Count;
while(nBits > 0)
{
l.Add((byte)(u & 0xFF));
u >>= 8;
nBits -= 8;
}
l.Reverse(idxNewBytes, l.Count - idxNewBytes);
}
return l.ToArray();
}
/// <summary>
/// Set all bytes in a byte array to zero.
/// </summary>
@@ -123,7 +250,8 @@ namespace ModernKeePassLib.Utility
/// to zero.</param>
public static void ZeroByteArray(byte[] pbArray)
{
Debug.Assert(pbArray != null); if(pbArray == null) throw new ArgumentNullException("pbArray");
Debug.Assert(pbArray != null);
if(pbArray == null) throw new ArgumentNullException("pbArray");
// for(int i = 0; i < pbArray.Length; ++i)
// pbArray[i] = 0;
@@ -274,6 +402,31 @@ namespace ModernKeePassLib.Utility
pbBuffer[nBufferOffset + i] ^= pbSource[nSourceOffset + i];
}
/// <summary>
/// Fast hash that can be used e.g. for hash tables.
/// The algorithm might change in the future; do not store
/// the hashes for later use.
/// </summary>
public static uint Hash32(byte[] v, int iStart, int iLength)
{
uint u = 0x326F637B;
if(v == null) { Debug.Assert(false); return u; }
if(iStart < 0) { Debug.Assert(false); return u; }
if(iLength < 0) { Debug.Assert(false); return u; }
int m = iStart + iLength;
if(m > v.Length) { Debug.Assert(false); return u; }
for(int i = iStart; i < m; ++i)
{
u ^= m_vSBox[v[i]];
u *= 3;
}
return u;
}
public static void CopyStream(Stream sSource, Stream sTarget)
{
Debug.Assert((sSource != null) && (sTarget != null));
@@ -282,19 +435,54 @@ namespace ModernKeePassLib.Utility
const int nBufSize = 4096;
byte[] pbBuf = new byte[nBufSize];
int nRead;
while((nRead = sSource.Read(pbBuf, 0, nBufSize)) > 0)
while(true)
{
int nRead = sSource.Read(pbBuf, 0, nBufSize);
if(nRead == 0) break;
sTarget.Write(pbBuf, 0, nRead);
}
// Do not close any of the streams
}
public static byte[] Read(Stream s, int nCount)
{
if(s == null) throw new ArgumentNullException("s");
if(nCount < 0) throw new ArgumentOutOfRangeException("nCount");
byte[] pb = new byte[nCount];
int iOffset = 0;
while(nCount > 0)
{
int iRead = s.Read(pb, iOffset, nCount);
if(iRead == 0) break;
iOffset += iRead;
nCount -= iRead;
}
if(iOffset != pb.Length)
{
byte[] pbPart = new byte[iOffset];
Array.Copy(pb, pbPart, iOffset);
return pbPart;
}
return pb;
}
public static void Write(Stream s, byte[] pbData)
{
if(s == null) { Debug.Assert(false); return; }
if(pbData == null) { Debug.Assert(false); return; }
s.Write(pbData, 0, pbData.Length);
}
public static byte[] Compress(byte[] pbData)
{
Debug.Assert(false, "not yet implemented");
return null;
#if TODO
if(pbData == null) throw new ArgumentNullException("pbData");
if(pbData.Length == 0) return pbData;
@@ -302,20 +490,16 @@ namespace ModernKeePassLib.Utility
GZipStream gz = new GZipStream(msCompressed, CompressionMode.Compress);
MemoryStream msSource = new MemoryStream(pbData, false);
MemUtil.CopyStream(msSource, gz);
gz.Close();
msSource.Close();
gz.Dispose();
msSource.Dispose();
byte[] pbCompressed = msCompressed.ToArray();
msCompressed.Close();
msCompressed.Dispose();
return pbCompressed;
#endif
}
public static byte[] Decompress(byte[] pbCompressed)
{
Debug.Assert(false, "not yet implemented");
return null;
#if TODO
if(pbCompressed == null) throw new ArgumentNullException("pbCompressed");
if(pbCompressed.Length == 0) return pbCompressed;
@@ -323,13 +507,12 @@ namespace ModernKeePassLib.Utility
GZipStream gz = new GZipStream(msCompressed, CompressionMode.Decompress);
MemoryStream msData = new MemoryStream();
MemUtil.CopyStream(gz, msData);
gz.Close();
msCompressed.Close();
gz.Dispose();
msCompressed.Dispose();
byte[] pbData = msData.ToArray();
msData.Close();
msData.Dispose();
return pbData;
#endif
}
public static int IndexOf<T>(T[] vHaystack, T[] vNeedle)
@@ -361,11 +544,81 @@ namespace ModernKeePassLib.Utility
if(v == null) throw new ArgumentNullException("v");
if(iOffset < 0) throw new ArgumentOutOfRangeException("iOffset");
if(iLength < 0) throw new ArgumentOutOfRangeException("iLength");
if(iOffset + iLength > v.Length) throw new ArgumentException();
if((iOffset + iLength) > v.Length) throw new ArgumentException();
T[] r = new T[iLength];
Array.Copy(v, iOffset, r, 0, iLength);
return r;
}
public static IEnumerable<T> Union<T>(IEnumerable<T> a, IEnumerable<T> b,
IEqualityComparer<T> cmp)
{
if(a == null) throw new ArgumentNullException("a");
if(b == null) throw new ArgumentNullException("b");
Dictionary<T, bool> d = ((cmp != null) ?
(new Dictionary<T, bool>(cmp)) : (new Dictionary<T, bool>()));
foreach(T ta in a)
{
if(d.ContainsKey(ta)) continue; // Prevent duplicates
d[ta] = true;
yield return ta;
}
foreach(T tb in b)
{
if(d.ContainsKey(tb)) continue; // Prevent duplicates
d[tb] = true;
yield return tb;
}
yield break;
}
public static IEnumerable<T> Intersect<T>(IEnumerable<T> a, IEnumerable<T> b,
IEqualityComparer<T> cmp)
{
if(a == null) throw new ArgumentNullException("a");
if(b == null) throw new ArgumentNullException("b");
Dictionary<T, bool> d = ((cmp != null) ?
(new Dictionary<T, bool>(cmp)) : (new Dictionary<T, bool>()));
foreach(T tb in b) { d[tb] = true; }
foreach(T ta in a)
{
if(d.Remove(ta)) // Prevent duplicates
yield return ta;
}
yield break;
}
public static IEnumerable<T> Except<T>(IEnumerable<T> a, IEnumerable<T> b,
IEqualityComparer<T> cmp)
{
if(a == null) throw new ArgumentNullException("a");
if(b == null) throw new ArgumentNullException("b");
Dictionary<T, bool> d = ((cmp != null) ?
(new Dictionary<T, bool>(cmp)) : (new Dictionary<T, bool>()));
foreach(T tb in b) { d[tb] = true; }
foreach(T ta in a)
{
if(d.ContainsKey(ta)) continue;
d[ta] = true; // Prevent duplicates
yield return ta;
}
yield break;
}
}
}

View File

@@ -1,6 +1,6 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 Dominik Reichl <dominik.reichl@t-online.de>
Copyright (C) 2003-2014 Dominik Reichl <dominik.reichl@t-online.de>
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
@@ -17,9 +17,6 @@
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
/* BERT TODO: All removed for the time being */
#if false
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
@@ -121,7 +118,7 @@ namespace ModernKeePassLib.Utility
Exception exObj = (obj as Exception);
string strObj = (obj as string);
#if !KeePassLibSD
#if (!KeePassLibSD && !KeePassRT)
StringCollection scObj = (obj as StringCollection);
#endif
@@ -132,7 +129,7 @@ namespace ModernKeePassLib.Utility
else if((exObj.Message != null) && (exObj.Message.Length > 0))
strAppend = exObj.Message;
}
#if !KeePassLibSD
#if (!KeePassLibSD && !KeePassRT)
else if(scObj != null)
{
StringBuilder sb = new StringBuilder();
@@ -161,24 +158,30 @@ namespace ModernKeePassLib.Utility
return sbText.ToString();
}
private static DialogResult SafeShowMessageBox(string strText, string strTitle,
#if (!KeePassLibSD && !KeePassRT)
internal static Form GetTopForm()
{
FormCollection fc = Application.OpenForms;
if((fc == null) || (fc.Count == 0)) return null;
return fc[fc.Count - 1];
}
#endif
internal static DialogResult SafeShowMessageBox(string strText, string strTitle,
MessageBoxButtons mb, MessageBoxIcon mi, MessageBoxDefaultButton mdb)
{
#if KeePassLibSD
#if (KeePassLibSD || KeePassRT)
return MessageBox.Show(strText, strTitle, mb, mi, mdb);
#else
IWin32Window wnd = null;
try
{
FormCollection fc = Application.OpenForms;
if((fc != null) && (fc.Count > 0))
{
Form f = fc[fc.Count - 1];
if((f != null) && f.InvokeRequired)
return (DialogResult)f.Invoke(new SafeShowMessageBoxInternalDelegate(
SafeShowMessageBoxInternal), f, strText, strTitle, mb, mi, mdb);
else wnd = f;
}
Form f = GetTopForm();
if((f != null) && f.InvokeRequired)
return (DialogResult)f.Invoke(new SafeShowMessageBoxInternalDelegate(
SafeShowMessageBoxInternal), f, strText, strTitle, mb, mi, mdb);
else wnd = f;
}
catch(Exception) { Debug.Assert(false); }
@@ -203,7 +206,7 @@ namespace ModernKeePassLib.Utility
#endif
}
#if !KeePassLibSD
#if (!KeePassLibSD && !KeePassRT)
internal delegate DialogResult SafeShowMessageBoxInternalDelegate(IWin32Window iParent,
string strText, string strTitle, MessageBoxButtons mb, MessageBoxIcon mi,
MessageBoxDefaultButton mdb);
@@ -318,7 +321,8 @@ namespace ModernKeePassLib.Utility
return dr;
}
public static bool AskYesNo(string strText, string strTitle, bool bDefaultToYes)
public static bool AskYesNo(string strText, string strTitle, bool bDefaultToYes,
MessageBoxIcon mbi)
{
++m_uCurrentMessageCount;
@@ -327,24 +331,29 @@ namespace ModernKeePassLib.Utility
if(MessageService.MessageShowing != null)
MessageService.MessageShowing(null, new MessageServiceEventArgs(
strTitleEx, strTextEx, MessageBoxButtons.YesNo, m_mbiQuestion));
strTitleEx, strTextEx, MessageBoxButtons.YesNo, mbi));
DialogResult dr = SafeShowMessageBox(strTextEx, strTitleEx,
MessageBoxButtons.YesNo, m_mbiQuestion, bDefaultToYes ?
MessageBoxButtons.YesNo, mbi, bDefaultToYes ?
MessageBoxDefaultButton.Button1 : MessageBoxDefaultButton.Button2);
--m_uCurrentMessageCount;
return (dr == DialogResult.Yes);
}
public static bool AskYesNo(string strText, string strTitle, bool bDefaultToYes)
{
return AskYesNo(strText, strTitle, bDefaultToYes, m_mbiQuestion);
}
public static bool AskYesNo(string strText, string strTitle)
{
return AskYesNo(strText, strTitle, true);
return AskYesNo(strText, strTitle, true, m_mbiQuestion);
}
public static bool AskYesNo(string strText)
{
return AskYesNo(strText, null, true);
return AskYesNo(strText, null, true, m_mbiQuestion);
}
public static void ShowLoadWarning(string strFilePath, Exception ex)
@@ -423,5 +432,3 @@ namespace ModernKeePassLib.Utility
}
}
}
#endif // false

View File

@@ -0,0 +1,324 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2014 Dominik Reichl <dominik.reichl@t-online.de>
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 2 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, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.ComponentModel;
using System.Reflection;
using System.Diagnostics;
using KeePass2PCL.Native;
namespace KeePass2PCL.Utility
{
public static class MonoWorkarounds
{
private static bool? m_bReq = null;
public static bool IsRequired()
{
if(!m_bReq.HasValue) m_bReq = NativeLib.IsUnix();
return m_bReq.Value;
}
// 1245:
// Key events not raised while Alt is down, and nav keys out of order.
// https://sourceforge.net/p/keepass/bugs/1245/
// 1254:
// NumericUpDown bug: text is drawn below up/down buttons.
// https://sourceforge.net/p/keepass/bugs/1254/
// 5795:
// Text in input field is incomplete.
// https://bugzilla.xamarin.com/show_bug.cgi?id=5795
// https://sourceforge.net/p/keepass/discussion/329220/thread/d23dc88b/
// 10163:
// WebRequest GetResponse call missing, breaks WebDAV due to no PUT.
// https://bugzilla.xamarin.com/show_bug.cgi?id=10163
// https://sourceforge.net/p/keepass/bugs/1117/
// https://sourceforge.net/p/keepass/discussion/329221/thread/9422258c/
// https://github.com/mono/mono/commit/8e67b8c2fc7cb66bff7816ebf7c1039fb8cfc43b
// https://bugzilla.xamarin.com/show_bug.cgi?id=1512
// https://sourceforge.net/p/keepass/patches/89/
// 12525:
// PictureBox not rendered when bitmap height >= control height.
// https://bugzilla.xamarin.com/show_bug.cgi?id=12525
// https://sourceforge.net/p/keepass/discussion/329220/thread/54f61e9a/
// 586901:
// RichTextBox doesn't handle Unicode string correctly.
// https://bugzilla.novell.com/show_bug.cgi?id=586901
// 620618:
// ListView column headers not drawn.
// https://bugzilla.novell.com/show_bug.cgi?id=620618
// 649266:
// Calling Control.Hide doesn't remove the application from taskbar.
// https://bugzilla.novell.com/show_bug.cgi?id=649266
// 686017:
// Minimum sizes must be enforced.
// http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=686017
// 801414:
// Mono recreates the main window incorrectly.
// https://bugs.launchpad.net/ubuntu/+source/keepass2/+bug/801414
// 891029:
// Increase tab control height, otherwise Mono throws exceptions.
// https://sourceforge.net/projects/keepass/forums/forum/329221/topic/4519750
// https://bugs.launchpad.net/ubuntu/+source/keepass2/+bug/891029
// 836428016:
// ListView group header selection unsupported.
// https://sourceforge.net/p/keepass/discussion/329221/thread/31dae0f0/
// 3574233558:
// Problems with minimizing windows, no content rendered.
// https://sourceforge.net/p/keepass/discussion/329220/thread/d50a79d6/
public static bool IsRequired(uint uBugID)
{
if(!MonoWorkarounds.IsRequired()) return false;
ulong v = NativeLib.MonoVersion;
if(v != 0)
{
if(uBugID == 10163)
return (v >= 0x0002000B00000000UL); // >= 2.11
}
return true;
}
public static void ApplyTo(Form f)
{
if(!MonoWorkarounds.IsRequired()) return;
if(f == null) { Debug.Assert(false); return; }
#if (!KeePassLibSD && !KeePassRT)
f.HandleCreated += MonoWorkarounds.OnFormHandleCreated;
SetWmClass(f);
ApplyToControlsRec(f.Controls, f, MonoWorkarounds.ApplyToControl);
#endif
}
public static void Release(Form f)
{
if(!MonoWorkarounds.IsRequired()) return;
if(f == null) { Debug.Assert(false); return; }
#if (!KeePassLibSD && !KeePassRT)
f.HandleCreated -= MonoWorkarounds.OnFormHandleCreated;
ApplyToControlsRec(f.Controls, f, MonoWorkarounds.ReleaseControl);
#endif
}
#if (!KeePassLibSD && !KeePassRT)
private delegate void MwaControlHandler(Control c, Form fContext);
private static void ApplyToControlsRec(Control.ControlCollection cc,
Form fContext, MwaControlHandler fn)
{
if(cc == null) { Debug.Assert(false); return; }
foreach(Control c in cc)
{
fn(c, fContext);
ApplyToControlsRec(c.Controls, fContext, fn);
}
}
private static void ApplyToControl(Control c, Form fContext)
{
Button btn = (c as Button);
if(btn != null) ApplyToButton(btn, fContext);
NumericUpDown nc = (c as NumericUpDown);
if((nc != null) && MonoWorkarounds.IsRequired(1254))
{
if(nc.TextAlign == HorizontalAlignment.Right)
nc.TextAlign = HorizontalAlignment.Left;
}
}
private sealed class MwaHandlerInfo
{
private readonly Delegate m_fnOrg; // May be null
public Delegate FunctionOriginal
{
get { return m_fnOrg; }
}
private readonly Delegate m_fnOvr;
public Delegate FunctionOverride
{
get { return m_fnOvr; }
}
private readonly DialogResult m_dr;
public DialogResult Result
{
get { return m_dr; }
}
private readonly Form m_fContext;
public Form FormContext
{
get { return m_fContext; }
}
public MwaHandlerInfo(Delegate fnOrg, Delegate fnOvr, DialogResult dr,
Form fContext)
{
m_fnOrg = fnOrg;
m_fnOvr = fnOvr;
m_dr = dr;
m_fContext = fContext;
}
}
private static EventHandlerList GetEventHandlers(Component c,
out object objClickEvent)
{
FieldInfo fi = typeof(Control).GetField("ClickEvent", // Mono
BindingFlags.Static | BindingFlags.NonPublic);
if(fi == null)
fi = typeof(Control).GetField("EventClick", // .NET
BindingFlags.Static | BindingFlags.NonPublic);
if(fi == null) { Debug.Assert(false); objClickEvent = null; return null; }
objClickEvent = fi.GetValue(null);
if(objClickEvent == null) { Debug.Assert(false); return null; }
PropertyInfo pi = typeof(Component).GetProperty("Events",
BindingFlags.Instance | BindingFlags.NonPublic);
return (pi.GetValue(c, null) as EventHandlerList);
}
private static Dictionary<object, MwaHandlerInfo> m_dictHandlers =
new Dictionary<object, MwaHandlerInfo>();
private static void ApplyToButton(Button btn, Form fContext)
{
DialogResult dr = btn.DialogResult;
if(dr == DialogResult.None) return; // No workaround required
object objClickEvent;
EventHandlerList ehl = GetEventHandlers(btn, out objClickEvent);
if(ehl == null) { Debug.Assert(false); return; }
Delegate fnClick = ehl[objClickEvent]; // May be null
EventHandler fnOvr = new EventHandler(MonoWorkarounds.OnButtonClick);
m_dictHandlers[btn] = new MwaHandlerInfo(fnClick, fnOvr, dr, fContext);
btn.DialogResult = DialogResult.None;
if(fnClick != null) ehl.RemoveHandler(objClickEvent, fnClick);
ehl[objClickEvent] = fnOvr;
}
private static void ReleaseControl(Control c, Form fContext)
{
Button btn = (c as Button);
if(btn != null) ReleaseButton(btn, fContext);
}
private static void ReleaseButton(Button btn, Form fContext)
{
MwaHandlerInfo hi;
m_dictHandlers.TryGetValue(btn, out hi);
if(hi == null) return;
object objClickEvent;
EventHandlerList ehl = GetEventHandlers(btn, out objClickEvent);
if(ehl == null) { Debug.Assert(false); return; }
ehl.RemoveHandler(objClickEvent, hi.FunctionOverride);
if(hi.FunctionOriginal != null)
ehl[objClickEvent] = hi.FunctionOriginal;
btn.DialogResult = hi.Result;
m_dictHandlers.Remove(btn);
}
private static void OnButtonClick(object sender, EventArgs e)
{
Button btn = (sender as Button);
if(btn == null) { Debug.Assert(false); return; }
MwaHandlerInfo hi;
m_dictHandlers.TryGetValue(btn, out hi);
if(hi == null) { Debug.Assert(false); return; }
Form f = hi.FormContext;
// Set current dialog result by setting the form's private
// variable; the DialogResult property can't be used,
// because it raises close events
FieldInfo fiRes = typeof(Form).GetField("dialog_result",
BindingFlags.Instance | BindingFlags.NonPublic);
if(fiRes == null) { Debug.Assert(false); return; }
if(f != null) fiRes.SetValue(f, hi.Result);
if(hi.FunctionOriginal != null)
hi.FunctionOriginal.Method.Invoke(hi.FunctionOriginal.Target,
new object[] { btn, e });
// Raise close events, if the click event handler hasn't
// reset the dialog result
if((f != null) && (f.DialogResult == hi.Result))
f.DialogResult = hi.Result; // Raises close events
}
private static void SetWmClass(Form f)
{
NativeMethods.SetWmClass(f, PwDefs.UnixName, PwDefs.ResClass);
}
private static void OnFormHandleCreated(object sender, EventArgs e)
{
Form f = (sender as Form);
if(f == null) { Debug.Assert(false); return; }
if(!f.IsHandleCreated) return; // Prevent infinite loop
SetWmClass(f);
}
/// <summary>
/// Set the value of the private <c>shown_raised</c> member
/// variable of a form.
/// </summary>
/// <returns>Previous <c>shown_raised</c> value.</returns>
internal static bool ExchangeFormShownRaised(Form f, bool bNewValue)
{
if(f == null) { Debug.Assert(false); return true; }
try
{
FieldInfo fi = typeof(Form).GetField("shown_raised",
BindingFlags.Instance | BindingFlags.NonPublic);
if(fi == null) { Debug.Assert(false); return true; }
bool bPrevious = (bool)fi.GetValue(f);
fi.SetValue(f, bNewValue);
return bPrevious;
}
catch(Exception) { Debug.Assert(false); }
return true;
}
#endif
}
}

View File

@@ -1,6 +1,6 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 Dominik Reichl <dominik.reichl@t-online.de>
Copyright (C) 2003-2014 Dominik Reichl <dominik.reichl@t-online.de>
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
@@ -18,22 +18,34 @@
*/
using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
//using System.Drawing;
using ModernKeePassLib.WinRTAdaptors;
using System.IO;
using System.Text.RegularExpressions;
#if PCL
using Windows.Security.Cryptography;
#else
using System.Security.Cryptography;
#endif
using System.Globalization;
using System.Diagnostics;
using System.Runtime.InteropServices.WindowsRuntime;
using Windows.Security.Cryptography.DataProtection;
using Windows.Storage.Streams;
using Windows.UI;
using ModernKeePassLib.Collections;
using ModernKeePassLib.Cryptography.PasswordGenerator;
using ModernKeePassLib.Security;
using ModernKeePassLib.Resources;
using UnicodeEncoding = System.Text.UnicodeEncoding;
namespace ModernKeePassLib.Utility
{
/// <summary>
/// Character stream class.
/// </summary>
public sealed class CharStream
/// <summary>
/// Character stream class.
/// </summary>
public sealed class CharStream
{
private string m_strString = string.Empty;
private int m_nPos = 0;
@@ -208,53 +220,47 @@ namespace ModernKeePassLib.Utility
{
get
{
if(m_lEncs == null)
{
m_lEncs = new List<StrEncodingInfo>();
#if !KeePassWinRT
m_lEncs.Add(new StrEncodingInfo(StrEncodingType.Default,
if(m_lEncs != null) return m_lEncs;
List<StrEncodingInfo> l = new List<StrEncodingInfo>();
#if !KeePassLibSD
Encoding.Default.EncodingName,
l.Add(new StrEncodingInfo(StrEncodingType.Default,
#if PCL || KeePassRT
StrUtil.Utf8.WebName, StrUtil.Utf8, 1, null));
#else
Encoding.Default.WebName,
#endif
Encoding.Default,
(uint)Encoding.Default.GetBytes("a").Length, null));
m_lEncs.Add(new StrEncodingInfo(StrEncodingType.Ascii,
"ASCII", Encoding.ASCII, 1, null));
m_lEncs.Add(new StrEncodingInfo(StrEncodingType.Utf7,
"Unicode (UTF-7)", Encoding.UTF7, 1, null));
m_lEncs.Add(new StrEncodingInfo(StrEncodingType.Utf8,
"Unicode (UTF-8)", StrUtil.Utf8, 1, new byte[] { 0xEF, 0xBB, 0xBF }));
m_lEncs.Add(new StrEncodingInfo(StrEncodingType.Utf16LE,
"Unicode (UTF-16 LE)", new UnicodeEncoding(false, false),
2, new byte[] { 0xFF, 0xFE }));
m_lEncs.Add(new StrEncodingInfo(StrEncodingType.Utf16BE,
"Unicode (UTF-16 BE)", new UnicodeEncoding(true, false),
2, new byte[] { 0xFE, 0xFF }));
#if !KeePassLibSD
m_lEncs.Add(new StrEncodingInfo(StrEncodingType.Utf32LE,
"Unicode (UTF-32 LE)", new UTF32Encoding(false, false),
4, new byte[] { 0xFF, 0xFE, 0x0, 0x0 }));
m_lEncs.Add(new StrEncodingInfo(StrEncodingType.Utf32BE,
"Unicode (UTF-32 BE)", new UTF32Encoding(true, false),
4, new byte[] { 0x0, 0x0, 0xFE, 0xFF }));
Encoding.Default.EncodingName,
#else
Encoding.Default.WebName,
#endif
#else // KeePassWinRT
m_lEncs.Add(new StrEncodingInfo(StrEncodingType.Utf8,
"Unicode (UTF-8)", StrUtil.Utf8, 1, new byte[] { 0xEF, 0xBB, 0xBF }));
m_lEncs.Add(new StrEncodingInfo(StrEncodingType.Utf16LE,
"Unicode (UTF-16 LE)", new UnicodeEncoding(false, false),
2, new byte[] { 0xFF, 0xFE }));
m_lEncs.Add(new StrEncodingInfo(StrEncodingType.Utf16BE,
"Unicode (UTF-16 BE)", new UnicodeEncoding(true, false),
2, new byte[] { 0xFE, 0xFF }));
Encoding.Default,
(uint)Encoding.Default.GetBytes("a").Length, null));
#endif
#if !PCL && !KeePassRT
l.Add(new StrEncodingInfo(StrEncodingType.Ascii,
"ASCII", Encoding.ASCII, 1, null));
l.Add(new StrEncodingInfo(StrEncodingType.Utf7,
"Unicode (UTF-7)", Encoding.UTF7, 1, null));
#endif
l.Add(new StrEncodingInfo(StrEncodingType.Utf8,
"Unicode (UTF-8)", StrUtil.Utf8, 1, new byte[] { 0xEF, 0xBB, 0xBF }));
l.Add(new StrEncodingInfo(StrEncodingType.Utf16LE,
"Unicode (UTF-16 LE)", new UnicodeEncoding(false, false),
2, new byte[] { 0xFF, 0xFE }));
l.Add(new StrEncodingInfo(StrEncodingType.Utf16BE,
"Unicode (UTF-16 BE)", new UnicodeEncoding(true, false),
2, new byte[] { 0xFE, 0xFF }));
#if (!PCL && !KeePassLibSD && !KeePassRT)
l.Add(new StrEncodingInfo(StrEncodingType.Utf32LE,
"Unicode (UTF-32 LE)", new UTF32Encoding(false, false),
4, new byte[] { 0xFF, 0xFE, 0x0, 0x0 }));
l.Add(new StrEncodingInfo(StrEncodingType.Utf32BE,
"Unicode (UTF-32 BE)", new UTF32Encoding(true, false),
4, new byte[] { 0x0, 0x0, 0xFE, 0xFF }));
#endif
}
return m_lEncs;
m_lEncs = l;
return l;
}
}
@@ -282,16 +288,21 @@ namespace ModernKeePassLib.Utility
// {
// char ch = str[i];
// if((int)ch >= 256)
// {
// sbEncoded.Append("\\u");
// sbEncoded.Append((int)ch);
// sbEncoded.Append('?');
// }
// sbEncoded.Append(StrUtil.RtfEncodeChar(ch));
// else sbEncoded.Append(ch);
// }
// return sbEncoded.ToString();
// }
public static string RtfEncodeChar(char ch)
{
// Unicode character values must be encoded using
// 16-bit numbers (decimal); Unicode values greater
// than 32767 must be expressed as negative numbers
short sh = (short)ch;
return ("\\u" + sh.ToString(NumberFormatInfo.InvariantInfo) + "?");
}
/// <summary>
/// Convert a string into a valid HTML sequence representing that string.
/// </summary>
@@ -308,7 +319,7 @@ namespace ModernKeePassLib.Utility
str = str.Replace("\'", @"&#39;");
str = NormalizeNewLines(str, false);
str = str.Replace("\n", @"<br />");
str = str.Replace("\n", @"<br />" + Environment.NewLine);
return str;
}
@@ -479,59 +490,59 @@ namespace ModernKeePassLib.Utility
/// <returns>String representing the exception.</returns>
public static string FormatException(Exception excp)
{
Debug.Assert(false, "not yet implemented");
return "";
#if TODO
string strText = string.Empty;
if(excp.Message != null)
strText += excp.Message + MessageService.NewLine;
strText += excp.Message + Environment.NewLine;
#if !KeePassLibSD
if(excp.Source != null)
strText += excp.Source + MessageService.NewLine;
strText += excp.Source + Environment.NewLine;
#endif
if(excp.StackTrace != null)
strText += excp.StackTrace + MessageService.NewLine;
strText += excp.StackTrace + Environment.NewLine;
#if !KeePassLibSD
#if !PCL && !KeePassRT
if(excp.TargetSite != null)
strText += excp.TargetSite.ToString() + MessageService.NewLine;
#endif
if(excp.Data != null)
{
strText += MessageService.NewLine;
strText += Environment.NewLine;
foreach(DictionaryEntry de in excp.Data)
strText += @"'" + de.Key + @"' -> '" + de.Value + @"'" +
MessageService.NewLine;
Environment.NewLine;
}
#endif
if(excp.InnerException != null)
{
strText += MessageService.NewLine + "Inner:" + MessageService.NewLine;
strText += Environment.NewLine + "Inner:" + Environment.NewLine;
if(excp.InnerException.Message != null)
strText += excp.InnerException.Message + MessageService.NewLine;
strText += excp.InnerException.Message + Environment.NewLine;
#if !KeePassLibSD
if(excp.InnerException.Source != null)
strText += excp.InnerException.Source + MessageService.NewLine;
strText += excp.InnerException.Source + Environment.NewLine;
#endif
if(excp.InnerException.StackTrace != null)
strText += excp.InnerException.StackTrace + MessageService.NewLine;
strText += excp.InnerException.StackTrace + Environment.NewLine;
#if !KeePassLibSD
#if !PCL && !KeePassRT
if(excp.InnerException.TargetSite != null)
strText += excp.InnerException.TargetSite.ToString();
#endif
if(excp.InnerException.Data != null)
{
strText += MessageService.NewLine;
strText += Environment.NewLine;
foreach(DictionaryEntry de in excp.InnerException.Data)
strText += @"'" + de.Key + @"' -> '" + de.Value + @"'" +
MessageService.NewLine;
Environment.NewLine;
}
#endif
}
return strText;
#endif
}
public static bool TryParseUShort(string str, out ushort u)
@@ -550,7 +561,25 @@ namespace ModernKeePassLib.Utility
return int.TryParse(str, out n);
#else
try { n = int.Parse(str); return true; }
catch(Exception) { n = 0; return false; }
catch(Exception) { n = 0; }
return false;
#endif
}
public static bool TryParseIntInvariant(string str, out int n)
{
#if !KeePassLibSD
return int.TryParse(str, NumberStyles.Integer,
NumberFormatInfo.InvariantInfo, out n);
#else
try
{
n = int.Parse(str, NumberStyles.Integer,
NumberFormatInfo.InvariantInfo);
return true;
}
catch(Exception) { n = 0; }
return false;
#endif
}
@@ -560,7 +589,25 @@ namespace ModernKeePassLib.Utility
return uint.TryParse(str, out u);
#else
try { u = uint.Parse(str); return true; }
catch(Exception) { u = 0; return false; }
catch(Exception) { u = 0; }
return false;
#endif
}
public static bool TryParseUIntInvariant(string str, out uint u)
{
#if !KeePassLibSD
return uint.TryParse(str, NumberStyles.Integer,
NumberFormatInfo.InvariantInfo, out u);
#else
try
{
u = uint.Parse(str, NumberStyles.Integer,
NumberFormatInfo.InvariantInfo);
return true;
}
catch(Exception) { u = 0; }
return false;
#endif
}
@@ -570,7 +617,25 @@ namespace ModernKeePassLib.Utility
return long.TryParse(str, out n);
#else
try { n = long.Parse(str); return true; }
catch(Exception) { n = 0; return false; }
catch(Exception) { n = 0; }
return false;
#endif
}
public static bool TryParseLongInvariant(string str, out long n)
{
#if !KeePassLibSD
return long.TryParse(str, NumberStyles.Integer,
NumberFormatInfo.InvariantInfo, out n);
#else
try
{
n = long.Parse(str, NumberStyles.Integer,
NumberFormatInfo.InvariantInfo);
return true;
}
catch(Exception) { n = 0; }
return false;
#endif
}
@@ -580,7 +645,25 @@ namespace ModernKeePassLib.Utility
return ulong.TryParse(str, out u);
#else
try { u = ulong.Parse(str); return true; }
catch(Exception) { u = 0; return false; }
catch(Exception) { u = 0; }
return false;
#endif
}
public static bool TryParseULongInvariant(string str, out ulong u)
{
#if !KeePassLibSD
return ulong.TryParse(str, NumberStyles.Integer,
NumberFormatInfo.InvariantInfo, out u);
#else
try
{
u = ulong.Parse(str, NumberStyles.Integer,
NumberFormatInfo.InvariantInfo);
return true;
}
catch(Exception) { u = 0; }
return false;
#endif
}
@@ -648,19 +731,34 @@ namespace ModernKeePassLib.Utility
Debug.Assert(strText != null); // No throw
if(string.IsNullOrEmpty(strText)) return strText;
char[] vChars = strText.ToCharArray();
StringBuilder sb = new StringBuilder(strText.Length, strText.Length);
char ch;
int nLength = strText.Length;
StringBuilder sb = new StringBuilder(nLength);
for(int i = 0; i < vChars.Length; ++i)
for(int i = 0; i < nLength; ++i)
{
ch = vChars[i];
char ch = strText[i];
if(((ch >= 0x20) && (ch <= 0xD7FF)) ||
(ch == 0x9) || (ch == 0xA) || (ch == 0xD) ||
((ch >= 0xE000) && (ch <= 0xFFFD)))
if(((ch >= '\u0020') && (ch <= '\uD7FF')) ||
(ch == '\u0009') || (ch == '\u000A') || (ch == '\u000D') ||
((ch >= '\uE000') && (ch <= '\uFFFD')))
sb.Append(ch);
// Range ((ch >= 0x10000) && (ch <= 0x10FFFF)) excluded
else if((ch >= '\uD800') && (ch <= '\uDBFF')) // High surrogate
{
if((i + 1) < nLength)
{
char chLow = strText[i + 1];
if((chLow >= '\uDC00') && (chLow <= '\uDFFF')) // Low sur.
{
sb.Append(ch);
sb.Append(chLow);
++i;
}
else { Debug.Assert(false); } // Low sur. invalid
}
else { Debug.Assert(false); } // Low sur. missing
}
Debug.Assert((ch < '\uDC00') || (ch > '\uDFFF')); // Lonely low sur.
}
return sb.ToString();
@@ -669,22 +767,24 @@ namespace ModernKeePassLib.Utility
private static Regex m_rxNaturalSplit = null;
public static int CompareNaturally(string strX, string strY)
{
Debug.Assert(false, "not yet implemented");
return 0;
#if TODO
Debug.Assert(strX != null);
if(strX == null) throw new ArgumentNullException("strX");
Debug.Assert(strY != null);
if(strY == null) throw new ArgumentNullException("strY");
if(NativeMethods.SupportsStrCmpNaturally)
return NativeMethods.StrCmpNaturally(strX, strY);
/*if(NativeMethods.SupportsStrCmpNaturally)
return NativeMethods.StrCmpNaturally(strX, strY);*/
strX = strX.ToLower(); // Case-insensitive comparison
strY = strY.ToLower();
if(m_rxNaturalSplit == null)
m_rxNaturalSplit = new Regex(@"([0-9]+)", RegexOptions.Compiled);
m_rxNaturalSplit = new Regex(@"([0-9]+)",
#if PCL || KeePassRT
RegexOptions.None);
#else
RegexOptions.Compiled);
#endif
string[] vPartsX = m_rxNaturalSplit.Split(strX);
string[] vPartsY = m_rxNaturalSplit.Split(strY);
@@ -716,7 +816,6 @@ namespace ModernKeePassLib.Utility
if(vPartsX.Length == vPartsY.Length) return 0;
if(vPartsX.Length < vPartsY.Length) return -1;
return 1;
#endif
}
public static string RemoveAccelerator(string strMenuText)
@@ -740,6 +839,54 @@ namespace ModernKeePassLib.Utility
return str;
}
public static string AddAccelerator(string strMenuText,
List<char> lAvailKeys)
{
if(strMenuText == null) { Debug.Assert(false); return null; }
if(lAvailKeys == null) { Debug.Assert(false); return strMenuText; }
int xa = -1, xs = 0;
for(int i = 0; i < strMenuText.Length; ++i)
{
char ch = strMenuText[i];
#if KeePassLibSD
char chUpper = char.ToUpper(ch);
#else
char chUpper = char.ToUpperInvariant(ch);
#endif
xa = lAvailKeys.IndexOf(chUpper);
if(xa >= 0) { xs = i; break; }
#if KeePassLibSD
char chLower = char.ToLower(ch);
#else
char chLower = char.ToLowerInvariant(ch);
#endif
xa = lAvailKeys.IndexOf(chLower);
if(xa >= 0) { xs = i; break; }
}
if(xa < 0) return strMenuText;
lAvailKeys.RemoveAt(xa);
return strMenuText.Insert(xs, @"&");
}
public static string EncodeMenuText(string strText)
{
if(strText == null) throw new ArgumentNullException("strText");
return strText.Replace(@"&", @"&&");
}
public static string EncodeToolTipText(string strText)
{
if(strText == null) throw new ArgumentNullException("strText");
return strText.Replace(@"&", @"&&&");
}
public static bool IsHexString(string str, bool bStrict)
{
if(str == null) throw new ArgumentNullException("str");
@@ -888,6 +1035,36 @@ namespace ModernKeePassLib.Utility
}
}
public static string GetNewLineSeq(string str)
{
if(str == null) { Debug.Assert(false); return Environment.NewLine; }
int n = str.Length, nLf = 0, nCr = 0, nCrLf = 0;
char chLast = char.MinValue;
for(int i = 0; i < n; ++i)
{
char ch = str[i];
if(ch == '\r') ++nCr;
else if(ch == '\n')
{
++nLf;
if(chLast == '\r') ++nCrLf;
}
chLast = ch;
}
nCr -= nCrLf;
nLf -= nCrLf;
int nMax = Math.Max(nCrLf, Math.Max(nCr, nLf));
if(nMax == 0) return Environment.NewLine;
if(nCrLf == nMax) return "\r\n";
return ((nLf == nMax) ? "\n" : "\r");
}
public static string AlphaNumericOnly(string str)
{
if(string.IsNullOrEmpty(str)) return str;
@@ -965,85 +1142,85 @@ namespace ModernKeePassLib.Utility
public static string VersionToString(ulong uVersion)
{
return VersionToString(uVersion, false);
return VersionToString(uVersion, 1U);
}
[Obsolete]
public static string VersionToString(ulong uVersion,
bool bEnsureAtLeastTwoComp)
{
string str = string.Empty;
bool bMultiComp = false;
return VersionToString(uVersion, (bEnsureAtLeastTwoComp ? 2U : 1U));
}
public static string VersionToString(ulong uVersion, uint uMinComp)
{
StringBuilder sb = new StringBuilder();
uint uComp = 0;
for(int i = 0; i < 4; ++i)
{
ushort us = (ushort)(uVersion & 0xFFFFUL);
if(uVersion == 0UL) break;
if((us != 0) || (str.Length > 0))
{
if(str.Length > 0)
{
str = "." + str;
bMultiComp = true;
}
ushort us = (ushort)(uVersion >> 48);
str = us.ToString() + str;
}
if(sb.Length > 0) sb.Append('.');
uVersion >>= 16;
sb.Append(us.ToString(NumberFormatInfo.InvariantInfo));
++uComp;
uVersion <<= 16;
}
if(bEnsureAtLeastTwoComp && !bMultiComp && (str.Length > 0))
str += ".0";
while(uComp < uMinComp)
{
if(sb.Length > 0) sb.Append('.');
return str;
sb.Append('0');
++uComp;
}
return sb.ToString();
}
private static readonly byte[] m_pbOptEnt = { 0xA5, 0x74, 0x2E, 0xEC };
public static string EncryptString(string strPlainText)
{
Debug.Assert(false, "not yet implemented");
return null;
#if TODO
if(string.IsNullOrEmpty(strPlainText)) return string.Empty;
try
{
byte[] pbPlain = StrUtil.Utf8.GetBytes(strPlainText);
byte[] pbEnc = ProtectedData.Protect(pbPlain, m_pbOptEnt,
DataProtectionScope.CurrentUser);
#if !KeePassLibSD
var provider = new DataProtectionProvider("Local=user");
var pbEnc = provider.ProtectAsync(pbPlain.AsBuffer()).GetResults();
#if (!PCL && !KeePassLibSD && !KeePassRT)
return Convert.ToBase64String(pbEnc, Base64FormattingOptions.None);
#else
return Convert.ToBase64String(pbEnc);
return Convert.ToBase64String(pbEnc.ToArray());
#endif
}
catch(Exception) { Debug.Assert(false); }
return strPlainText;
#endif
}
public static string DecryptString(string strCipherText)
{
Debug.Assert(false, "not yet implemented");
return null;
#if TODO
if(string.IsNullOrEmpty(strCipherText)) return string.Empty;
try
{
byte[] pbEnc = Convert.FromBase64String(strCipherText);
byte[] pbPlain = ProtectedData.Unprotect(pbEnc, m_pbOptEnt,
DataProtectionScope.CurrentUser);
var provider = new DataProtectionProvider("Local=user");
var pbPlain = provider.UnprotectAsync(pbEnc.AsBuffer()).GetResults().ToArray();
return StrUtil.Utf8.GetString(pbPlain, 0, pbPlain.Length);
}
catch(Exception) { Debug.Assert(false); }
return strCipherText;
#endif
}
public static string SerializeIntArray(int[] vNumbers)
@@ -1054,7 +1231,7 @@ namespace ModernKeePassLib.Utility
for(int i = 0; i < vNumbers.Length; ++i)
{
if(i > 0) sb.Append(' ');
sb.Append(vNumbers[i]);
sb.Append(vNumbers[i].ToString(NumberFormatInfo.InvariantInfo));
}
return sb.ToString();
@@ -1071,7 +1248,7 @@ namespace ModernKeePassLib.Utility
for(int i = 0; i < vParts.Length; ++i)
{
int n;
if(!TryParseInt(vParts[i], out n)) { Debug.Assert(false); }
if(!TryParseIntInvariant(vParts[i], out n)) { Debug.Assert(false); }
v[i] = n;
}
@@ -1131,7 +1308,7 @@ namespace ModernKeePassLib.Utility
Array.Reverse(pb);
for(int i = 0; i < pb.Length; ++i) pb[i] = (byte)(pb[i] ^ 0x65);
#if !KeePassLibSD && TODO
#if (!PCL && !KeePassLibSD && !KeePassRT)
return Convert.ToBase64String(pb, Base64FormattingOptions.None);
#else
return Convert.ToBase64String(pb);
@@ -1249,9 +1426,33 @@ namespace ModernKeePassLib.Utility
public static bool IsDataUri(string strUri)
{
if(strUri == null) { Debug.Assert(false); return false; }
return IsDataUri(strUri, null);
}
return strUri.StartsWith("data:", StrUtil.CaseIgnoreCmp);
public static bool IsDataUri(string strUri, string strReqMimeType)
{
if(strUri == null) { Debug.Assert(false); return false; }
// strReqMimeType may be null
const string strPrefix = "data:";
if(!strUri.StartsWith(strPrefix, StrUtil.CaseIgnoreCmp))
return false;
int iC = strUri.IndexOf(',');
if(iC < 0) return false;
if(!string.IsNullOrEmpty(strReqMimeType))
{
int iS = strUri.IndexOf(';', 0, iC);
int iTerm = ((iS >= 0) ? iS : iC);
string strMime = strUri.Substring(strPrefix.Length,
iTerm - strPrefix.Length);
if(!strMime.Equals(strReqMimeType, StrUtil.CaseIgnoreCmp))
return false;
}
return true;
}
/// <summary>
@@ -1267,7 +1468,7 @@ namespace ModernKeePassLib.Utility
if(strMimeType == null) strMimeType = "application/octet-stream";
#if !KeePassLibSD && TODO
#if (!PCL && !KeePassLibSD && !KeePassRT)
return ("data:" + strMimeType + ";base64," + Convert.ToBase64String(
pbData, Base64FormattingOptions.None));
#else
@@ -1283,9 +1484,6 @@ namespace ModernKeePassLib.Utility
/// <returns>Decoded binary data.</returns>
public static byte[] DataUriToData(string strDataUri)
{
Debug.Assert(false, "not yet implemented");
return null;
#if TODO
if(strDataUri == null) throw new ArgumentNullException("strDataUri");
if(!strDataUri.StartsWith("data:", StrUtil.CaseIgnoreCmp)) return null;
@@ -1301,20 +1499,25 @@ namespace ModernKeePassLib.Utility
MemoryStream ms = new MemoryStream();
#if PCL || KeePassRT
Encoding enc = StrUtil.Utf8;
#else
Encoding enc = Encoding.ASCII;
#endif
string[] v = strData.Split('%');
byte[] pb = Encoding.ASCII.GetBytes(v[0]);
byte[] pb = enc.GetBytes(v[0]);
ms.Write(pb, 0, pb.Length);
for(int i = 1; i < v.Length; ++i)
{
ms.WriteByte(Convert.ToByte(v[i].Substring(0, 2), 16));
pb = Encoding.ASCII.GetBytes(v[i].Substring(2));
pb = enc.GetBytes(v[i].Substring(2));
ms.Write(pb, 0, pb.Length);
}
pb = ms.ToArray();
ms.Close();
ms.Dispose();
return pb;
#endif
}
/// <summary>
@@ -1358,5 +1561,72 @@ namespace ModernKeePassLib.Utility
return null;
}
private static string[] m_vPrefSepChars = null;
/// <summary>
/// Find a character that does not occur within a given text.
/// </summary>
public static char GetUnusedChar(string strText)
{
if(strText == null) { Debug.Assert(false); return '@'; }
if(m_vPrefSepChars == null)
m_vPrefSepChars = new string[5] {
"@!$%#/\\:;,.*-_?",
PwCharSet.UpperCase, PwCharSet.LowerCase,
PwCharSet.Digits, PwCharSet.PrintableAsciiSpecial
};
for(int i = 0; i < m_vPrefSepChars.Length; ++i)
{
foreach(char ch in m_vPrefSepChars[i])
{
if(strText.IndexOf(ch) < 0) return ch;
}
}
for(char ch = '\u00C0'; ch < char.MaxValue; ++ch)
{
if(strText.IndexOf(ch) < 0) return ch;
}
return char.MinValue;
}
public static char ByteToSafeChar(byte bt)
{
const char chDefault = '.';
// 00-1F are C0 control chars
if(bt < 0x20) return chDefault;
// 20-7F are basic Latin; 7F is DEL
if(bt < 0x7F) return (char)bt;
// 80-9F are C1 control chars
if(bt < 0xA0) return chDefault;
// A0-FF are Latin-1 supplement; AD is soft hyphen
if(bt == 0xAD) return '-';
return (char)bt;
}
public static int Count(string str, string strNeedle)
{
if(str == null) { Debug.Assert(false); return 0; }
if(string.IsNullOrEmpty(strNeedle)) { Debug.Assert(false); return 0; }
int iOffset = 0, iCount = 0;
while(iOffset < str.Length)
{
int p = str.IndexOf(strNeedle, iOffset);
if(p < 0) break;
++iCount;
iOffset = p + 1;
}
return iCount;
}
}
}

View File

@@ -1,6 +1,6 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 Dominik Reichl <dominik.reichl@t-online.de>
Copyright (C) 2003-2014 Dominik Reichl <dominik.reichl@t-online.de>
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
@@ -18,8 +18,13 @@
*/
using System;
using System.Collections.Generic;
using System.Text;
using System.Globalization;
using System.Diagnostics;
using ModernKeePassLib.Interfaces;
namespace ModernKeePassLib.Utility
{
/// <summary>
@@ -33,6 +38,11 @@ namespace ModernKeePassLib.Utility
/// </summary>
public const int PwTimeLength = 7;
#if !KeePassLibSD
private static string m_strDtfStd = null;
private static string m_strDtfDate = null;
#endif
/// <summary>
/// Pack a <c>DateTime</c> object into 5 bytes. Layout: 2 zero bits,
/// year 12 bits, month 4 bits, day 5 bits, hour 5 bits, minute 6
@@ -138,17 +148,118 @@ namespace ModernKeePassLib.Utility
{
DateTime dt;
#if !KeePassLibSD
if(DateTime.TryParse(strDisplay, out dt)) return dt;
#else
#if KeePassLibSD
try { dt = DateTime.Parse(strDisplay); return dt; }
catch(Exception) { }
#else
if(DateTime.TryParse(strDisplay, out dt)) return dt;
// For some custom formats specified using the Control Panel,
// DateTime.ToString returns the correct string, but
// DateTime.TryParse fails (e.g. for "//dd/MMM/yyyy");
// https://sourceforge.net/p/keepass/discussion/329221/thread/3a225b29/?limit=25&page=1#c6ae
if((m_strDtfStd == null) || (m_strDtfDate == null))
{
DateTime dtUni = new DateTime(2111, 3, 4, 5, 6, 7);
m_strDtfStd = DeriveCustomFormat(ToDisplayString(dtUni), dtUni);
m_strDtfDate = DeriveCustomFormat(ToDisplayStringDateOnly(dtUni), dtUni);
}
const DateTimeStyles dts = DateTimeStyles.AllowWhiteSpaces;
if(DateTime.TryParseExact(strDisplay, m_strDtfStd, null, dts, out dt))
return dt;
if(DateTime.TryParseExact(strDisplay, m_strDtfDate, null, dts, out dt))
return dt;
#endif
Debug.Assert(false);
return DateTime.Now;
}
#if !KeePassLibSD
private static string DeriveCustomFormat(string strDT, DateTime dt)
{
string[] vPlh = new string[] {
// Names, sorted by length
"MMMM", "dddd",
"MMM", "ddd",
"gg", "g",
// Numbers, the ones with prefix '0' first
"yyyy", "yyy", "yy", "y",
"MM", "M",
"dd", "d",
"HH", "hh", "H", "h",
"mm", "m",
"ss", "s",
"tt", "t"
};
List<string> lValues = new List<string>();
foreach(string strPlh in vPlh)
{
string strEval = strPlh;
if(strEval.Length == 1) strEval = @"%" + strPlh; // Make custom
lValues.Add(dt.ToString(strEval));
}
StringBuilder sbAll = new StringBuilder();
sbAll.Append("dfFghHKmMstyz:/\"\'\\%");
sbAll.Append(strDT);
foreach(string strVEnum in lValues) { sbAll.Append(strVEnum); }
List<char> lCodes = new List<char>();
for(int i = 0; i < vPlh.Length; ++i)
{
char ch = StrUtil.GetUnusedChar(sbAll.ToString());
lCodes.Add(ch);
sbAll.Append(ch);
}
string str = strDT;
for(int i = 0; i < vPlh.Length; ++i)
{
string strValue = lValues[i];
if(string.IsNullOrEmpty(strValue)) continue;
str = str.Replace(strValue, new string(lCodes[i], 1));
}
StringBuilder sbFmt = new StringBuilder();
bool bInLiteral = false;
foreach(char ch in str)
{
int iCode = lCodes.IndexOf(ch);
// The escape character doesn't work correctly (e.g.
// "dd\\.MM\\.yyyy\\ HH\\:mm\\:ss" doesn't work, but
// "dd'.'MM'.'yyyy' 'HH':'mm':'ss" does); use '' instead
// if(iCode >= 0) sbFmt.Append(vPlh[iCode]);
// else // Literal
// {
// sbFmt.Append('\\');
// sbFmt.Append(ch);
// }
if(iCode >= 0)
{
if(bInLiteral) { sbFmt.Append('\''); bInLiteral = false; }
sbFmt.Append(vPlh[iCode]);
}
else // Literal
{
if(!bInLiteral) { sbFmt.Append('\''); bInLiteral = true; }
sbFmt.Append(ch);
}
}
if(bInLiteral) sbFmt.Append('\'');
return sbFmt.ToString();
}
#endif
public static string SerializeUtc(DateTime dt)
{
string str = dt.ToUniversalTime().ToString("s");
@@ -218,5 +329,44 @@ namespace ModernKeePassLib.Utility
return null;
}
#endif
private static readonly DateTime m_dtInvMin =
new DateTime(2999, 12, 27, 23, 59, 59);
private static readonly DateTime m_dtInvMax =
new DateTime(2999, 12, 29, 23, 59, 59);
public static int Compare(DateTime dtA, DateTime dtB, bool bUnkIsPast)
{
if(bUnkIsPast)
{
// 2999-12-28 23:59:59 in KeePass 1.x means 'unknown';
// expect time zone corruption (twice)
// bool bInvA = ((dtA.Year == 2999) && (dtA.Month == 12) &&
// (dtA.Day >= 27) && (dtA.Day <= 29) && (dtA.Minute == 59) &&
// (dtA.Second == 59));
// bool bInvB = ((dtB.Year == 2999) && (dtB.Month == 12) &&
// (dtB.Day >= 27) && (dtB.Day <= 29) && (dtB.Minute == 59) &&
// (dtB.Second == 59));
// Faster due to internal implementation of DateTime:
bool bInvA = ((dtA >= m_dtInvMin) && (dtA <= m_dtInvMax) &&
(dtA.Minute == 59) && (dtA.Second == 59));
bool bInvB = ((dtB >= m_dtInvMin) && (dtB <= m_dtInvMax) &&
(dtB.Minute == 59) && (dtB.Second == 59));
if(bInvA) return (bInvB ? 0 : -1);
if(bInvB) return 1;
}
return dtA.CompareTo(dtB);
}
internal static int CompareLastMod(ITimeLogger tlA, ITimeLogger tlB,
bool bUnkIsPast)
{
if(tlA == null) { Debug.Assert(false); return ((tlB == null) ? 0 : -1); }
if(tlB == null) { Debug.Assert(false); return 1; }
return Compare(tlA.LastModificationTime, tlB.LastModificationTime,
bUnkIsPast);
}
}
}

View File

@@ -1,6 +1,6 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 Dominik Reichl <dominik.reichl@t-online.de>
Copyright (C) 2003-2014 Dominik Reichl <dominik.reichl@t-online.de>
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
@@ -20,11 +20,13 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Text;
using System.Diagnostics;
using ModernKeePassLib.Native;
#if PCL
using Windows.Storage;
#endif
namespace ModernKeePassLib.Utility
{
@@ -34,16 +36,30 @@ namespace ModernKeePassLib.Utility
/// </summary>
public static class UrlUtil
{
// Bert TODO: Temporary fix, most of this class is not needed in WINRT.
private static readonly char DirectorySeparatorChar = '/';
private static readonly char[] m_vDirSeps = new char[] {
'\\', '/', UrlUtil.LocalDirSepChar };
#if !PCL
private static readonly char[] m_vPathTrimCharsWs = new char[] {
'\"', ' ', '\t', '\r', '\n' };
#endif
private static readonly char[] m_vDirSeps = new char[] { '\\', '/',
DirectorySeparatorChar };
public static char LocalDirSepChar
{
#if KeePassRT
get { return '\\'; }
#elif PCL
//get { return PortablePath.DirectorySeparatorChar; }
get { return '\\'; }
#else
get { return Path.DirectorySeparatorChar; }
#endif
}
/// <summary>
/// Get the directory (path) of a file name. The returned string is
/// Get the directory (path) of a file name. The returned string may be
/// terminated by a directory separator character. Example:
/// passing <c>C:\\My Documents\\My File.kdb</c> in <paramref name="strFile" />
/// and <c>true</c> to <paramref name="bAppendTerminatingChar"/>
/// would produce this string: <c>C:\\My Documents\\</c>.
/// </summary>
/// <param name="strFile">Full path of a file.</param>
@@ -54,8 +70,7 @@ namespace ModernKeePassLib.Utility
/// of <c>X:</c>, overriding <paramref name="bAppendTerminatingChar" />).
/// This should only be set to <c>true</c>, if the returned path is directly
/// passed to some directory API.</param>
/// <returns>Directory of the file. The return value is an empty string
/// (<c>""</c>) if the input parameter is <c>null</c>.</returns>
/// <returns>Directory of the file.</returns>
public static string GetFileDirectory(string strFile, bool bAppendTerminatingChar,
bool bEnsureValidDirSpec)
{
@@ -63,14 +78,15 @@ namespace ModernKeePassLib.Utility
if(strFile == null) throw new ArgumentNullException("strFile");
int nLastSep = strFile.LastIndexOfAny(m_vDirSeps);
if(nLastSep < 0) return strFile; // None
if(nLastSep < 0) return string.Empty; // No directory
if(bEnsureValidDirSpec && (nLastSep == 2) && (strFile[1] == ':') &&
(strFile[2] == '\\')) // Length >= 3 and Windows root directory
bAppendTerminatingChar = true;
if(!bAppendTerminatingChar) return strFile.Substring(0, nLastSep);
return EnsureTerminatingSeparator(strFile.Substring(0, nLastSep), false);
return EnsureTerminatingSeparator(strFile.Substring(0, nLastSep),
(strFile[nLastSep] == '/'));
}
/// <summary>
@@ -151,7 +167,7 @@ namespace ModernKeePassLib.Utility
}
if(bUrl) return (strPath + '/');
return (strPath + DirectorySeparatorChar);
return (strPath + UrlUtil.LocalDirSepChar);
}
/* /// <summary>
@@ -214,13 +230,22 @@ namespace ModernKeePassLib.Utility
public static string GetQuotedAppPath(string strPath)
{
int nFirst = strPath.IndexOf('\"');
int nSecond = strPath.IndexOf('\"', nFirst + 1);
if(strPath == null) { Debug.Assert(false); return string.Empty; }
if((nFirst >= 0) && (nSecond >= 0))
return strPath.Substring(nFirst + 1, nSecond - nFirst - 1);
// int nFirst = strPath.IndexOf('\"');
// int nSecond = strPath.IndexOf('\"', nFirst + 1);
// if((nFirst >= 0) && (nSecond >= 0))
// return strPath.Substring(nFirst + 1, nSecond - nFirst - 1);
// return strPath;
return strPath;
string str = strPath.Trim();
if(str.Length <= 1) return str;
if(str[0] != '\"') return str;
int iSecond = str.IndexOf('\"', 1);
if(iSecond <= 0) return str;
return str.Substring(1, iSecond - 1);
}
public static string FileUrlToPath(string strUrl)
@@ -232,14 +257,14 @@ namespace ModernKeePassLib.Utility
if(str.StartsWith(@"file:///", StrUtil.CaseIgnoreCmp))
str = str.Substring(8, str.Length - 8);
str = str.Replace('/', DirectorySeparatorChar);
str = str.Replace('/', UrlUtil.LocalDirSepChar);
return str;
}
public static bool UnhideFile(string strFile)
{
#if KeePassLibSD || !TODO
#if (PCL || KeePassLibSD || KeePassRT)
return false;
#else
if(strFile == null) throw new ArgumentNullException("strFile");
@@ -259,7 +284,7 @@ namespace ModernKeePassLib.Utility
public static bool HideFile(string strFile, bool bHide)
{
#if KeePassLibSD || !TODO
#if (PCL || KeePassLibSD || KeePassRT)
return false;
#else
if(strFile == null) throw new ArgumentNullException("strFile");
@@ -300,7 +325,9 @@ namespace ModernKeePassLib.Utility
return strTargetFile;
}
#if (!PCL && !KeePassLibSD && !KeePassRT)
if(NativeLib.IsUnix())
#endif
{
bool bBaseUnc = IsUncPath(strBaseFile);
bool bTargetUnc = IsUncPath(strTargetFile);
@@ -319,21 +346,19 @@ namespace ModernKeePassLib.Utility
StringBuilder sbRel = new StringBuilder();
for(int j = i; j < (vBase.Length - 1); ++j)
{
if(sbRel.Length > 0) sbRel.Append(DirectorySeparatorChar);
if(sbRel.Length > 0) sbRel.Append(UrlUtil.LocalDirSepChar);
sbRel.Append("..");
}
for(int k = i; k < vTarget.Length; ++k)
{
if(sbRel.Length > 0) sbRel.Append(DirectorySeparatorChar);
if(sbRel.Length > 0) sbRel.Append(UrlUtil.LocalDirSepChar);
sbRel.Append(vTarget[k]);
}
return sbRel.ToString();
}
#if KeePassLibSD || !TODO
return strTargetFile;
#else
#if (!PCL && !KeePassLibSD && !KeePassRT)
try // Windows
{
const int nMaxPath = NativeMethods.MAX_PATH * 2;
@@ -347,7 +372,8 @@ namespace ModernKeePassLib.Utility
return str;
}
catch(Exception) { Debug.Assert(false); return strTargetFile; }
catch(Exception) { Debug.Assert(false); }
return strTargetFile;
#endif
}
@@ -379,9 +405,6 @@ namespace ModernKeePassLib.Utility
public static string GetShortestAbsolutePath(string strPath)
{
Debug.Assert(false, "not yet implemented");
return null;
#if TODO
if(strPath == null) throw new ArgumentNullException("strPath");
if(strPath.Length == 0) return string.Empty;
@@ -426,7 +449,20 @@ namespace ModernKeePassLib.Utility
}
string str;
try { str = Path.GetFullPath(strPath); }
try
{
#if KeePassRT
var dirT = StorageFolder.GetFolderFromPathAsync(
strPath).GetResults();
str = dirT.Path;
#elif PCL
//var dirT = FileSystem.Current.GetFolderFromPathAsync(strPath).Result;
str = ApplicationData.Current.RoamingFolder.Path;
//str = dirT.Path;
#else
str = Path.GetFullPath(strPath);
#endif
}
catch(Exception) { Debug.Assert(false); return strPath; }
Debug.Assert(str.IndexOf("\\..\\") < 0);
@@ -437,7 +473,6 @@ namespace ModernKeePassLib.Utility
}
return str;
#endif
}
public static int GetUrlLength(string strText, int nOffset)
@@ -483,7 +518,7 @@ namespace ModernKeePassLib.Utility
public static string ConvertSeparators(string strPath)
{
return ConvertSeparators(strPath, DirectorySeparatorChar);
return ConvertSeparators(strPath, UrlUtil.LocalDirSepChar);
}
public static string ConvertSeparators(string strPath, char chSeparator)
@@ -595,5 +630,106 @@ namespace ModernKeePassLib.Utility
return false;
}
#if !PCL
public static string GetTempPath()
{
string strDir;
if(NativeLib.IsUnix())
strDir = NativeMethods.GetUserRuntimeDir();
#if KeePassRT
else strDir = Windows.Storage.ApplicationData.Current.TemporaryFolder.Path;
#else
else strDir = Path.GetTempPath();
#endif
try
{
if(Directory.Exists(strDir) == false)
Directory.CreateDirectory(strDir);
}
catch(Exception) { Debug.Assert(false); }
return strDir;
}
#endif
#if !PCL && !KeePassLibSD
// Structurally mostly equivalent to UrlUtil.GetFileInfos
public static List<string> GetFilePaths(string strDir, string strPattern,
SearchOption opt)
{
List<string> l = new List<string>();
if(strDir == null) { Debug.Assert(false); return l; }
if(strPattern == null) { Debug.Assert(false); return l; }
string[] v = Directory.GetFiles(strDir, strPattern, opt);
if(v == null) { Debug.Assert(false); return l; }
// Only accept files with the correct extension; GetFiles may
// return additional files, see GetFiles documentation
string strExt = GetExtension(strPattern);
if(!string.IsNullOrEmpty(strExt) && (strExt.IndexOf('*') < 0) &&
(strExt.IndexOf('?') < 0))
{
strExt = "." + strExt;
foreach(string strPathRaw in v)
{
if(strPathRaw == null) { Debug.Assert(false); continue; }
string strPath = strPathRaw.Trim(m_vPathTrimCharsWs);
if(strPath.Length == 0) { Debug.Assert(false); continue; }
Debug.Assert(strPath == strPathRaw);
if(!strPath.EndsWith(strExt, StrUtil.CaseIgnoreCmp))
continue;
l.Add(strPathRaw);
}
}
else l.AddRange(v);
return l;
}
// Structurally mostly equivalent to UrlUtil.GetFilePaths
public static List<FileInfo> GetFileInfos(DirectoryInfo di, string strPattern,
SearchOption opt)
{
List<FileInfo> l = new List<FileInfo>();
if(di == null) { Debug.Assert(false); return l; }
if(strPattern == null) { Debug.Assert(false); return l; }
FileInfo[] v = di.GetFiles(strPattern, opt);
if(v == null) { Debug.Assert(false); return l; }
// Only accept files with the correct extension; GetFiles may
// return additional files, see GetFiles documentation
string strExt = GetExtension(strPattern);
if(!string.IsNullOrEmpty(strExt) && (strExt.IndexOf('*') < 0) &&
(strExt.IndexOf('?') < 0))
{
strExt = "." + strExt;
foreach(FileInfo fi in v)
{
if(fi == null) { Debug.Assert(false); continue; }
string strPathRaw = fi.FullName;
if(strPathRaw == null) { Debug.Assert(false); continue; }
string strPath = strPathRaw.Trim(m_vPathTrimCharsWs);
if(strPath.Length == 0) { Debug.Assert(false); continue; }
Debug.Assert(strPath == strPathRaw);
if(!strPath.EndsWith(strExt, StrUtil.CaseIgnoreCmp))
continue;
l.Add(fi);
}
}
else l.AddRange(v);
return l;
}
#endif
}
}