using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace Perforce.P4 { /// /// Describes fields and comments in a Perforce specification. /// public class FormBase :Dictionary { public Dictionary IsFieldMultiLine { get; internal set; } public String Comments { get; set; } public FormBase() { IsFieldMultiLine = new Dictionary(); } #region Tagged Form Data /// /// Set the Values Dictionary from tagged output of a Perforce command. /// /// /// Needed when the object's data dictionary is set after the object /// is created using the default constructer. /// /// Object data internal void SetValues(TaggedObject data) { //if (data.ContainsKey("specdef")) //{ // specDescription = new SpecificationMetaData(data["specdef"]); //} // map of base key names to max index (so far) Dictionary baseKeys = new Dictionary(); foreach (String key in data.Keys) { try { if (char.IsNumber(key, key.Length - 1)) { // value is part of a list string baseKey = key.TrimEnd('0', '1', '2', '3', '4', '5', '6', '7', '8', '9'); string idxStr = key.Substring(baseKey.Length); int idx = -1; int.TryParse(idxStr, out idx); IsFieldMultiLine[baseKey] = false; if (ContainsKey(baseKey) == false) { this[baseKey] = new List(idx + 1); } List strList = this[baseKey] as List; while (strList.Count <= idx) { strList.Add(null); } strList[idx] = data[key]; } else { if (data[key].Contains("\r") || data[key].Contains("\n")) { IsFieldMultiLine[key] = true; } this[key] = data[key]; } } catch { }; //Extra tag included with TaggedInfoItem data can be ignored } } #endregion #region From string data (a spec form) /// /// Parse a string specification in the server format into an object. /// /// /// The base implementation parses the generic specification tag::value /// format into the underlying dictionary /// /// String specification /// Success/Failure virtual public bool Parse(String spec) { String currentTag = String.Empty; IList currentValueList = null; String[] lines = spec.Split(new char[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries); for (int idx = 0; idx < lines.Length; idx++) { if (lines[idx][0] == '#') // # comment { if (Comments == null) { Comments = lines[idx]; } else { Comments += "\r\n"; Comments += lines[idx]; } continue; } else if (lines[idx][0] == '\t') // tab char so this is part of a value field { currentValueList.Add(lines[idx].TrimStart('\t')); } else { //new tag line String line = lines[idx].Trim(); int colonPos = line.IndexOf(':'); if (colonPos <= 0) //bad line continue; // start of a tag currentValueList = null; currentTag = line.Substring(0, colonPos); if (colonPos < line.Length - 1) { // right of colon is the value this[currentTag] = line.Substring(colonPos + 1).Trim(); IsFieldMultiLine[currentTag] = false; } else { IsFieldMultiLine[currentTag] = true; currentValueList = new List(); this[currentTag] = currentValueList; } } } return true; } #endregion /// /// Create a form specification from the fields that make up a form /// /// public override string ToString() { StringBuilder buff = new StringBuilder(2048); if (Comments != null) { buff.AppendLine(Comments); } foreach (string key in Keys) { // ignore values that do not go into the spec form if (key == "specdef" || key == "specFormatted" || key == "func") { continue; } if ((IsFieldMultiLine.ContainsKey(key)) && (IsFieldMultiLine[key])) { buff.AppendFormat("{0}:\n", key); if (this[key] is string) { string multilineString = this[key] as string; multilineString= multilineString.TrimEnd('\n', '\r'); if (multilineString.Contains("\n")) { multilineString = multilineString.Replace("\r", ""); multilineString = multilineString.Replace("\n", "\n\t"); } else if (multilineString.Contains("\r")) { multilineString = multilineString.Replace("\r", "\n\t"); } buff.AppendFormat("\t{0}\n", (multilineString)); } else { IList lines = this[key] as IList; for (int idx = 0; idx < lines.Count; idx++) { buff.AppendFormat("\t{0}\n", lines[idx]); } } } else { buff.AppendFormat("{0}:\t{1}\n", key, this[key] as string); } } return buff.ToString(); } /// /// Utility function to format a DateTime in the format expected in a spec /// /// /// public static String FormatDateTime(DateTime dt) { if ((dt != null) && (DateTime.MinValue != dt)) return dt.ToString("yyyy|MM|dd HH:mm:ss").Replace('|','/'); return string.Empty; } /// /// Utility to convert a Unix time (Seconds past midnight 1/1/1970) to a DateTime /// /// /// public static DateTime ConvertUnixTime(long unixTime) { return new DateTime(1970, 1, 1, 0, 0, 0, 0).AddSeconds(unixTime); } /// /// Utility to convert a Unix time (Seconds past midnight 1/1/1970) to a DateTime /// /// Unix time as a string /// public static DateTime ConvertUnixTime(string unixTimeStr) { long unixTime = 0; if (long.TryParse(unixTimeStr, out unixTime)) { return new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc).AddSeconds(unixTime); } return new DateTime(1970, 1, 1, 0, 0, 0, 0); } public static bool DSTMismatch(ServerMetaData smd) { DateTime serverDate = smd.Date; bool UTC_dst = TimeZoneInfo.FindSystemTimeZoneById("GMT Standard Time").IsDaylightSavingTime(serverDate); bool server_dst = serverDate.IsDaylightSavingTime(); if (server_dst && !UTC_dst) { return true; } return false; } public static DateTime ConvertFromUTC(DateTime dt, string offset, bool DST_mistmatch) { int idx = offset.IndexOf(" "); if (idx >= 0) { offset = offset.Remove(offset.IndexOf(" ")); } offset = offset.TrimEnd('0'); int timeDiff; bool num = int.TryParse(offset, out timeDiff); dt = dt.AddHours(timeDiff); bool timestampDST = dt.IsDaylightSavingTime(); if (!timestampDST&&DST_mistmatch) { dt = dt.AddHours(-1); } return dt; } /// /// Utility to properly format multi-line fields in forms /// /// Multi-line field /// public static string FormatMultilineField(string multiline) { String tmpMultilineStr = String.Empty; if (!String.IsNullOrEmpty(multiline)) { tmpMultilineStr = multiline.Replace("\r", "").Trim('\r', '\n'); tmpMultilineStr = tmpMultilineStr.Replace("\n", "\n\t").Trim(); } return tmpMultilineStr; } } }