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));
        }
Example #2
0
    /// <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&lt;VCard&gt;</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);
        }
    }