Exemplo n.º 1
0
        /// <summary>
        /// Serializes the <see cref="ITsString"/> to XML.
        /// </summary>
        public static string SerializeTsStringToXml(ITsString tss, ILgWritingSystemFactory lgwsf, int ws = 0, bool writeObjData = true, bool indent = false)
        {
            // We export only the NFSC form (NFC with exceptions for the parallel style information)
            ITsString normalizedTss = tss.get_NormalizedForm(FwNormalizationMode.knmNFSC);

            var xml      = new StringBuilder();
            var settings = new XmlWriterSettings
            {
                OmitXmlDeclaration = true,
                Indent             = true,
                IndentChars        = indent ? "  " : string.Empty,
                NewLineChars       = Environment.NewLine
            };

            using (var writer = XmlWriter.Create(xml, settings))
            {
                if (ws > 0)
                {
                    string id = lgwsf.GetStrFromWs(ws);
                    writer.WriteStartElement("AStr");
                    writer.WriteAttributeString("ws", Icu.Normalize(id, Icu.UNormalizationMode.UNORM_NFC));
                }
                else
                {
                    writer.WriteStartElement("Str");
                }

                // Write the properties and text for each run
                string fieldName = null;
                for (int i = 0; i < normalizedTss.RunCount; i++)
                {
                    TsRunInfo    tri;
                    ITsTextProps textProps = normalizedTss.FetchRunInfo(i, out tri);
                    string       objDataStr;
                    if (textProps.TryGetStringValue(FwTextPropType.ktptObjData, out objDataStr) && !writeObjData)
                    {
                        var chType = (FwObjDataTypes)objDataStr[0];
                        if (chType == FwObjDataTypes.kodtPictEvenHot || chType == FwObjDataTypes.kodtPictOddHot ||
                            chType == FwObjDataTypes.kodtNameGuidHot || chType == FwObjDataTypes.kodtOwnNameGuidHot)
                        {
                            continue;
                        }
                    }

                    string runFieldName;
                    if (textProps.TryGetStringValue(FwTextPropType.ktptFieldName, out runFieldName) && fieldName != runFieldName)
                    {
                        if (!string.IsNullOrEmpty(fieldName))
                        {
                            writer.WriteEndElement();
                        }
                        if (!string.IsNullOrEmpty(runFieldName))
                        {
                            writer.WriteStartElement("Field");
                            writer.WriteAttributeString("name", runFieldName);
                        }
                        fieldName = runFieldName;
                    }

                    bool          markItem;
                    FwTextPropVar var;
                    int           markItemValue;
                    if (textProps.TryGetIntValue(FwTextPropType.ktptMarkItem, out var, out markItemValue) &&
                        var == FwTextPropVar.ktpvEnum && markItemValue == (int)FwTextToggleVal.kttvForceOn)
                    {
                        writer.WriteStartElement("Item");
                        writer.WriteStartElement("Run");
                        markItem = true;
                    }
                    else
                    {
                        writer.WriteStartElement("Run");
                        markItem = false;
                    }

                    for (int j = 0; j < textProps.IntPropCount; j++)
                    {
                        FwTextPropType tpt;
                        int            value = textProps.GetIntProperty(j, out tpt, out var);
                        if (tpt != FwTextPropType.ktptMarkItem)
                        {
                            TsPropsSerializer.WriteIntProperty(writer, lgwsf, tpt, var, value);
                        }
                    }

                    byte[] pict    = null;
                    bool   hotGuid = false;
                    for (int j = 0; j < textProps.StrPropCount; j++)
                    {
                        FwTextPropType tpt;
                        string         value = textProps.GetStringProperty(j, out tpt);
                        TsPropsSerializer.WriteStringProperty(writer, tpt, value);
                        if (tpt == FwTextPropType.ktptObjData && !string.IsNullOrEmpty(value))
                        {
                            switch ((FwObjDataTypes)value[0])
                            {
                            // The element data associated with a picture is the actual picture data
                            // since it is much too large to want embedded as an XML attribute value.
                            // (This is an antique kludge that isn't really used in practice, but some
                            // of our test data still exercises it.)
                            case FwObjDataTypes.kodtPictEvenHot:
                            case FwObjDataTypes.kodtPictOddHot:
                                pict = Encoding.Unicode.GetBytes(value.Substring(1));
                                break;

                            // The generated XML contains both the link value as an attribute and the
                            // (possibly edited) display string as the run's element data.
                            case FwObjDataTypes.kodtExternalPathName:
                                break;

                            // used ONLY in the clipboard...contains XML representation of (currently) a footnote.
                            case FwObjDataTypes.kodtEmbeddedObjectData:
                                break;

                            // The string data associated with this run is assumed to be a dummy magic
                            // character that flags (redundantly for XML) that the actual data to
                            // display is based on the ktptObjData attribute.
                            case FwObjDataTypes.kodtNameGuidHot:
                            case FwObjDataTypes.kodtOwnNameGuidHot:
                            case FwObjDataTypes.kodtContextString:
                            case FwObjDataTypes.kodtGuidMoveableObjDisp:
                                hotGuid = true;
                                break;
                            }
                        }
                    }

                    if (pict != null)
                    {
                        // Write the bytes of the picture data
                        var sb = new StringBuilder();
                        for (int j = 0; j < pict.Length; j++)
                        {
                            sb.Append(pict[j].ToString("X2"));
                            if (j % 32 == 31)
                            {
                                sb.AppendLine();
                            }
                        }
                        writer.WriteString(sb.ToString());
                    }
                    else if (hotGuid)
                    {
                        writer.WriteString(string.Empty);
                    }
                    else
                    {
                        string runText = normalizedTss.get_RunText(i) ?? string.Empty;
                        if (runText != string.Empty && runText.All(char.IsWhiteSpace))
                        {
                            writer.WriteAttributeString("xml", "space", "", "preserve");
                        }
                        // TODO: should we escape quotation marks? this is not necessary but different than the behavior of the C++ implementation
                        writer.WriteString(Icu.Normalize(runText, Icu.UNormalizationMode.UNORM_NFC));
                    }

                    writer.WriteEndElement();
                    if (markItem)
                    {
                        writer.WriteEndElement();
                    }
                }
                if (!string.IsNullOrEmpty(fieldName))
                {
                    writer.WriteEndElement();
                }
                writer.WriteEndElement();
            }
            return(xml.ToString());
        }