public void VcfOptionsHelperTest() { VcfOptions tp = VcfOptions.None; Assert.IsFalse(tp.IsSet(VcfOptions.WriteGroups)); Assert.IsTrue(tp.IsSet(VcfOptions.None)); tp = tp.Set(VcfOptions.WriteGroups); Assert.IsTrue(tp.IsSet(VcfOptions.WriteGroups)); Assert.IsFalse(tp.IsSet(VcfOptions.None)); // Set doppelt aufrufen tp = tp.Set(VcfOptions.WriteGroups); Assert.IsTrue(tp.IsSet(VcfOptions.WriteGroups)); Assert.IsFalse(tp.IsSet(VcfOptions.None)); tp = tp.Set(VcfOptions.WriteEmptyProperties); Assert.IsTrue(tp.IsSet(VcfOptions.WriteEmptyProperties)); Assert.IsTrue(tp.IsSet(VcfOptions.WriteGroups)); Assert.IsFalse(tp.IsSet(VcfOptions.None)); tp = tp.Unset(VcfOptions.WriteEmptyProperties); Assert.IsFalse(tp.IsSet(VcfOptions.WriteEmptyProperties)); Assert.IsTrue(tp.IsSet(VcfOptions.WriteGroups)); Assert.IsFalse(tp.IsSet(VcfOptions.None)); // Unset doppelt aufrufen: tp = tp.Unset(VcfOptions.WriteEmptyProperties); Assert.IsFalse(tp.IsSet(VcfOptions.WriteEmptyProperties)); Assert.IsTrue(tp.IsSet(VcfOptions.WriteGroups)); Assert.IsFalse(tp.IsSet(VcfOptions.None)); // letztes Flag löschen tp = tp.Unset(VcfOptions.WriteGroups); Assert.IsFalse(tp.IsSet(VcfOptions.WriteGroups)); Assert.IsTrue(tp.IsSet(VcfOptions.None)); // Unset auf None aufrufen: tp = tp.Unset(VcfOptions.WriteGroups); Assert.IsFalse(tp.IsSet(VcfOptions.WriteGroups)); Assert.IsTrue(tp.IsSet(VcfOptions.None)); }
/// <summary> /// Serialisiert eine Sammlung von <see cref="VCard"/>-Objekten unter Verwendung des VCF-Formats in einen <see cref="Stream"/>. /// </summary> /// /// <param name="vCards">Die zu serialisierenden <see cref="VCard"/>-Objekte. Die Sammlung darf leer sein und <c>null</c>-Werte /// enthalten.</param> /// <param name="stream">Ein <see cref="Stream"/>, in den die serialisierten <see cref="VCard"/>-Objekte geschrieben werden.</param> /// <param name="version">Die vCard-Version, die für die Serialisierung verwendet wird.</param> /// <param name="options">Optionen für das Serialisieren. Die Flags können /// kombiniert werden.</param> /// <param name="leaveStreamOpen">Mit <c>true</c> wird bewirkt, dass die Methode <paramref name="stream"/> nicht schließt. Der Standardwert /// ist <c>false</c>.</param> /// <param name="tzConverter">Ein Objekt, das <see cref="ITimeZoneIDConverter"/> implementiert, um beim Schreiben von vCard 2.1 oder /// vCard 3.0 Zeitzonennamen aus der "IANA time zone database" in UTC-Offsets umwandeln zu können, oder <c>null</c>, um /// auf eine Umwandlung zu verzichten.</param> /// /// <remarks> /// <note type="caution"> /// Obwohl die Methode selbst threadsafe ist, sind es die an die Methode übergebenen /// <see cref="VCard"/>-Objekte nicht. Sperren Sie den lesenden und schreibenden Zugriff auf diese /// <see cref="VCard"/>-Objekte während der Ausführung dieser Methode! /// </note> /// <note type="tip"> /// Sie können der Methode auch ein einzelnes <see cref="VCard"/>-Objekt übergeben, da die <see cref="VCard"/>-Klasse /// <see cref="IEnumerable{T}">IEnumerable<VCard></see> explizit implementiert. /// </note> /// /// <para>Die Methode serialisiert möglicherweise mehr /// vCards, als die Anzahl der Elemente in der Sammlung, die an den Parameter <paramref name="vCards"/> übergeben wird. /// Dies geschieht, wenn eine /// vCard 4.0 serialisiert wird und sich /// in den Eigenschaften <see cref="VCard.Members"/> oder <see cref="VCard.Relations"/> eines <see cref="VCard"/>-Objekts /// weitere <see cref="VCard"/>-Objekte in Form von <see cref="RelationVCardProperty"/>-Objekten befanden. /// Diese <see cref="VCard"/>-Objekte werden von der Methode an <paramref name="vCards"/> angefügt. /// </para> /// /// <para>Ebenso verhält sich die Methode, wenn eine vCard 2.1 oder 3.0 mit der Option <see cref="VcfOptions.IncludeAgentAsSeparateVCard"/> /// serialisiert wird und wenn sich in der Eigenschaft <see cref="VCard.Relations"/> eines <see cref="VCard"/>-Objekts ein /// <see cref="RelationVCardProperty"/>-Objekt befindet, auf dessen <see cref="ParameterSection"/> in der Eigenschaft <see cref="ParameterSection.RelationType"/> /// das Flag <see cref="RelationTypes.Agent"/> gesetzt ist. /// </para> /// /// </remarks> /// /// /// <seealso cref="ITimeZoneIDConverter"/> /// /// <exception cref="ArgumentNullException"><paramref name="stream"/> oder <paramref name="vCards"/> ist <c>null</c>.</exception> /// <exception cref="ArgumentException"><paramref name="stream"/> unterstützt keine Schreibvorgänge oder <paramref name="version"/> hat einen nichtdefinierten Wert.</exception> /// <exception cref="IOException">E/A-Fehler.</exception> /// <exception cref="ObjectDisposedException"><paramref name="stream"/> war bereits geschlossen.</exception> public static void SerializeVcf(Stream stream, IEnumerable <VCard?> vCards, VCdVersion version = DEFAULT_VERSION, ITimeZoneIDConverter?tzConverter = null, VcfOptions options = VcfOptions.Default, bool leaveStreamOpen = false) { DebugWriter.WriteMethodHeader($"{nameof(VCard)}.{nameof(SerializeVcf)}({nameof(Stream)}, IEnumerable<{nameof(VCard)}?>, {nameof(VCdVersion)}, {nameof(VcfOptions)}"); if (stream is null) { throw new ArgumentNullException(nameof(stream)); } if (!stream.CanWrite) { if (!leaveStreamOpen) { stream.Close(); } throw new ArgumentException(Res.StreamNotWritable, nameof(stream)); } if (vCards is null) { if (!leaveStreamOpen) { stream.Close(); } throw new ArgumentNullException(nameof(vCards)); } if (version < VCdVersion.V4_0) { if (options.IsSet(VcfOptions.IncludeAgentAsSeparateVCard)) { List <VCard?> list = vCards.ToList(); vCards = list; for (int i = 0; i < list.Count; i++) { VCard?vCard = list[i]; if (vCard?.Relations is null) { continue; } RelationVCardProperty?agent = vCard.Relations .Select(x => x as RelationVCardProperty) .Where(x => x != null && !x.IsEmpty && x.Parameters.RelationType.IsSet(RelationTypes.Agent)) .OrderBy(x => x !.Parameters.Preference) .FirstOrDefault(); if (agent != null) { if (!list.Contains(agent.Value)) { list.Add(agent.Value); } } } //for } //if } else { vCards = Reference(vCards); } // UTF-8 muss ohne BOM geschrieben werden, da sonst nicht lesbar // (vCard 2.1 kann UTF-8 verwenden, da nur ASCII-Zeichen geschrieben werden) var encoding = new UTF8Encoding(false); using StreamWriter? writer = leaveStreamOpen #if NET40 ? new StreamWriter(new Net40LeaveOpenStream(stream), encoding) #else ? new StreamWriter(stream, encoding, 1024, true) #endif : new StreamWriter(stream, encoding); var serializer = VcfSerializer.GetSerializer(writer, version, options, tzConverter); foreach (VCard?vCard in vCards) { if (vCard is null) { continue; } vCard.Version = version; serializer.Serialize(vCard); } }