private static void CheckIdRange(PackageXmlEnum id) { if (id <= PackageXmlEnum.NotDefined || id >= (PackageXmlEnum)27) { throw new ArgumentOutOfRangeException("id"); } }
private static void CheckIdRange(PackageXmlEnum id) { if ((id <= PackageXmlEnum.NotDefined) || (id >= (PackageXmlEnum.LastPrinted | PackageXmlEnum.XmlSchemaInstanceNamespace))) { throw new ArgumentOutOfRangeException(nameof(id)); } }
private static void CheckIdRange(PackageXmlEnum id) { if ((id <= PackageXmlEnum.NotDefined) || (id >= (PackageXmlEnum.LastPrinted | PackageXmlEnum.XmlSchemaInstanceNamespace))) { throw new ArgumentOutOfRangeException("id"); } }
// Set new property value. // Null value is passed for deleting a property. // While initializing, we are not assigning new values, and so the dirty flag should // stay untouched. private void RecordNewBinding(PackageXmlEnum propertyenum, object value, bool initializing, XmlTextReader reader) { // If we are reading values from the package, reader cannot be null Debug.Assert(!initializing || reader != null); if (!initializing) { _package.ThrowIfReadOnly(); } // Case of an existing property. if (_propertyDictionary.ContainsKey(propertyenum)) { // Parsing should detect redundant entries. if (initializing) { throw new XmlException(SR.Get(SRID.DuplicateCorePropertyName, reader.Name), null, reader.LineNumber, reader.LinePosition); } // No edit of existing properties in streaming production. if (_package.InStreamingCreation) { throw new InvalidOperationException(SR.Get(SRID.OperationViolatesWriteOnceSemantics)); } // Nullable<DateTime> values can be checked against null if (value == null) // a deletion { _propertyDictionary.Remove(propertyenum); } else // an update { _propertyDictionary[propertyenum] = value; } // If the binding is an assignment rather than an initialization, set the dirty flag. _dirty = !initializing; } // Case of a null value in the absence of an existing property. else if (value == null) { // Even thinking about setting a property to null in streaming production is a no-no. if (_package.InStreamingCreation) { throw new InvalidOperationException(SR.Get(SRID.OperationViolatesWriteOnceSemantics)); } // Outside of streaming production, deleting a non-existing property is a no-op. } // Case of an initial value being set for a property. else { _propertyDictionary.Add(propertyenum, value); // If the binding is an assignment rather than an initialization, set the dirty flag. _dirty = !initializing; } }
// The property store is implemented as a hash table of objects. // Keys are taken from the set of string constants defined in this // class and compared by their references rather than their values. private object GetPropertyValue(PackageXmlEnum propertyName) { _package.ThrowIfWriteOnly(); if (!_propertyDictionary.ContainsKey(propertyName)) { return(null); } return(_propertyDictionary[propertyName]); }
// Shim function to adequately cast the result of GetPropertyValue. private Nullable <DateTime> GetDateTimePropertyValue(PackageXmlEnum propertyName) { object valueObject = GetPropertyValue(propertyName); if (valueObject == null) { return(null); } // If an object is there, it will be a DateTime (not a Nullable<DateTime>). return((Nullable <DateTime>)valueObject); }
// Write the property elements and clear _dirty. private void SerializeDirtyProperties() { Debug.Assert(_xmlWriter != null); // Create a property element for each non-null entry. foreach (KeyValuePair <PackageXmlEnum, object> entry in _propertyDictionary) { Debug.Assert(entry.Value != null); PackageXmlEnum propertyNamespace = PackageXmlStringTable.GetXmlNamespace(entry.Key); _xmlWriter.WriteStartElement(PackageXmlStringTable.GetXmlString(entry.Key), PackageXmlStringTable.GetXmlString(propertyNamespace)); if (entry.Value is Nullable <DateTime> ) { if (propertyNamespace == PackageXmlEnum.DublinCoreTermsNamespace) { // xsi:type= _xmlWriter.WriteStartAttribute(PackageXmlStringTable.GetXmlString(PackageXmlEnum.Type), PackageXmlStringTable.GetXmlString(PackageXmlEnum.XmlSchemaInstanceNamespace)); // "dcterms:W3CDTF" _xmlWriter.WriteQualifiedName(W3cdtf, PackageXmlStringTable.GetXmlString(PackageXmlEnum.DublinCoreTermsNamespace)); _xmlWriter.WriteEndAttribute(); } // Use sortable ISO 8601 date/time pattern. Include second fractions down to the 100-nanosecond interval, // which is the definition of a "tick" for the DateTime type. _xmlWriter.WriteString(XmlConvert.ToString(((Nullable <DateTime>)entry.Value).Value.ToUniversalTime(), "yyyy-MM-ddTHH:mm:ss.fffffffZ")); } else { // The following uses the fact that ToString is virtual. _xmlWriter.WriteString(entry.Value.ToString()); } _xmlWriter.WriteEndElement(); } // Mark properties as saved. _dirty = false; }
// Set new property value. // Null value is passed for deleting a property. // While initializing, we are not assigning new values, and so the dirty flag should // stay untouched. private void RecordNewBinding(PackageXmlEnum propertyenum, object value, bool initializing, XmlReader reader) { // If we are reading values from the package, reader cannot be null Debug.Assert(!initializing || reader != null); if (!initializing) { _package.ThrowIfReadOnly(); } // Case of an existing property. if (_propertyDictionary.ContainsKey(propertyenum)) { // Parsing should detect redundant entries. if (initializing) { throw new XmlException(SR.Format(SR.DuplicateCorePropertyName, reader.Name), null, ((IXmlLineInfo)reader).LineNumber, ((IXmlLineInfo)reader).LinePosition); } // Nullable<DateTime> values can be checked against null if (value == null) // a deletion { _propertyDictionary.Remove(propertyenum); } else // an update { _propertyDictionary[propertyenum] = value; } // If the binding is an assignment rather than an initialization, set the dirty flag. _dirty = !initializing; } // Case of an initial value being set for a property. If value is null, no need to do anything else if (value != null) { _propertyDictionary.Add(propertyenum, value); // If the binding is an assignment rather than an initialization, set the dirty flag. _dirty = !initializing; } }
internal static PackageXmlEnum GetXmlNamespace(PackageXmlEnum id) { PackageXmlStringTable.CheckIdRange(id); return(PackageXmlStringTable._xmlstringtable[(int)id].Namespace); }
internal static string GetXmlString(PackageXmlEnum id) { PackageXmlStringTable.CheckIdRange(id); return((string)PackageXmlStringTable._xmlstringtable[(int)id].Name); }
internal static object GetXmlStringAsObject(PackageXmlEnum id) { PackageXmlStringTable.CheckIdRange(id); return(PackageXmlStringTable._xmlstringtable[(int)id].Name); }
// Set new property value. // Null value is passed for deleting a property. // While initializing, we are not assigning new values, and so the dirty flag should // stay untouched. private void RecordNewBinding(PackageXmlEnum propertyenum, object value, bool initializing, XmlTextReader reader) { // If we are reading values from the package, reader cannot be null Debug.Assert(!initializing || reader != null); if (!initializing) _package.ThrowIfReadOnly(); // Case of an existing property. if (_propertyDictionary.ContainsKey(propertyenum)) { // Parsing should detect redundant entries. if (initializing) { throw new XmlException(SR.Get(SRID.DuplicateCorePropertyName, reader.Name), null, reader.LineNumber, reader.LinePosition); } // No edit of existing properties in streaming production. if (_package.InStreamingCreation) throw new InvalidOperationException(SR.Get(SRID.OperationViolatesWriteOnceSemantics)); // Nullable<DateTime> values can be checked against null if (value == null) // a deletion { _propertyDictionary.Remove(propertyenum); } else // an update { _propertyDictionary[propertyenum] = value; } // If the binding is an assignment rather than an initialization, set the dirty flag. _dirty = !initializing; } // Case of a null value in the absence of an existing property. else if (value == null) { // Even thinking about setting a property to null in streaming production is a no-no. if (_package.InStreamingCreation) throw new InvalidOperationException(SR.Get(SRID.OperationViolatesWriteOnceSemantics)); // Outside of streaming production, deleting a non-existing property is a no-op. } // Case of an initial value being set for a property. else { _propertyDictionary.Add(propertyenum, value); // If the binding is an assignment rather than an initialization, set the dirty flag. _dirty = !initializing; } }
internal XmlStringTableStruct(object nameString, PackageXmlEnum ns, string valueType) { this._nameString = nameString; this._namespace = ns; this._valueType = valueType; }
//------------------------------------------------------ // // Internal Properties // //------------------------------------------------------ //------------------------------------------------------ // // Private Methods // //------------------------------------------------------ #region Private Methods // The property store is implemented as a hash table of objects. // Keys are taken from the set of string constants defined in this // class and compared by their references rather than their values. private object GetPropertyValue(PackageXmlEnum propertyName) { _package.ThrowIfWriteOnly(); if (!_propertyDictionary.ContainsKey(propertyName)) return null; return _propertyDictionary[propertyName]; }
// Write the property elements and clear _dirty. private void SerializeDirtyProperties() { // In streaming mode, nullify dictionary values. // As no property can be set to null through the API, this makes it possible to keep // track of all properties that have been set since the CoreProperties object was created. KeyValuePair <PackageXmlEnum, Object>[] entriesToNullify = null; int numEntriesToNullify = 0; if (_package.InStreamingCreation) { entriesToNullify = new KeyValuePair <PackageXmlEnum, Object> [_propertyDictionary.Count]; } // Create a property element for each non-null entry. foreach (KeyValuePair <PackageXmlEnum, Object> entry in _propertyDictionary) { // If we are NOT in streaming mode, the property value should NOT be null Debug.Assert(entry.Value != null || _package.InStreamingCreation); if (_package.InStreamingCreation && entry.Value == null) // already saved { continue; } PackageXmlEnum propertyNamespace = PackageXmlStringTable.GetXmlNamespace(entry.Key); _xmlWriter.WriteStartElement(PackageXmlStringTable.GetXmlString(entry.Key), PackageXmlStringTable.GetXmlString(propertyNamespace)); if (entry.Value is Nullable <DateTime> ) { if (propertyNamespace == PackageXmlEnum.DublinCoreTermsNamespace) { // xsi:type= _xmlWriter.WriteStartAttribute(PackageXmlStringTable.GetXmlString(PackageXmlEnum.Type), PackageXmlStringTable.GetXmlString(PackageXmlEnum.XmlSchemaInstanceNamespace)); // "dcterms:W3CDTF" _xmlWriter.WriteQualifiedName(_w3cdtf, PackageXmlStringTable.GetXmlString(PackageXmlEnum.DublinCoreTermsNamespace)); _xmlWriter.WriteEndAttribute(); } // Use sortable ISO 8601 date/time pattern. Include second fractions down to the 100-nanosecond interval, // which is the definition of a "tick" for the DateTime type. _xmlWriter.WriteString(XmlConvert.ToString(((Nullable <DateTime>)entry.Value).Value.ToUniversalTime(), "yyyy-MM-ddTHH:mm:ss.fffffffZ")); } else { // The following uses the fact that ToString is virtual. _xmlWriter.WriteString(entry.Value.ToString()); } _xmlWriter.WriteEndElement(); if (_package.InStreamingCreation) { entriesToNullify[numEntriesToNullify++] = entry; } } // Mark properties as saved. _dirty = false; // Detailed marking of saved properties for the streaming mode. if (_package.InStreamingCreation) { for (int i = 0; i < numEntriesToNullify; ++i) { _propertyDictionary[entriesToNullify[i].Key] = null; } } }
internal static string GetValueType(PackageXmlEnum id) { PackageXmlStringTable.CheckIdRange(id); return(PackageXmlStringTable._xmlstringtable[(int)id].ValueType); }
// Set new property value. // Override that sets the initializing flag to false to reflect the default // situation: recording a binding to implement a value assignment. private void RecordNewBinding(PackageXmlEnum propertyenum, object value) { RecordNewBinding(propertyenum, value, false /* not invoked at construction */, null); }
// Set new property value. // Null value is passed for deleting a property. // While initializing, we are not assigning new values, and so the dirty flag should // stay untouched. private void RecordNewBinding(PackageXmlEnum propertyenum, object value, bool initializing, XmlReader reader) { // If we are reading values from the package, reader cannot be null Debug.Assert(!initializing || reader != null); if (!initializing) _package.ThrowIfReadOnly(); // Case of an existing property. if (_propertyDictionary.ContainsKey(propertyenum)) { // Parsing should detect redundant entries. if (initializing) { throw new XmlException(SR.Format(SR.DuplicateCorePropertyName, reader.Name), null, ((IXmlLineInfo)reader).LineNumber, ((IXmlLineInfo)reader).LinePosition); } // Nullable<DateTime> values can be checked against null if (value == null) // a deletion { _propertyDictionary.Remove(propertyenum); } else // an update { _propertyDictionary[propertyenum] = value; } // If the binding is an assignment rather than an initialization, set the dirty flag. _dirty = !initializing; } // Case of an initial value being set for a property. else { _propertyDictionary.Add(propertyenum, value); // If the binding is an assignment rather than an initialization, set the dirty flag. _dirty = !initializing; } }
internal XmlStringTableStruct(object nameString, PackageXmlEnum ns, string valueType) { _nameString = nameString; _namespace = ns; _valueType = valueType; }
internal static object GetXmlStringAsObject(PackageXmlEnum id) { CheckIdRange(id); return s_xmlstringtable[(int)id].Name; }
internal static string GetXmlString(PackageXmlEnum id) { CheckIdRange(id); return (string)s_xmlstringtable[(int)id].Name; }
internal static PackageXmlEnum GetXmlNamespace(PackageXmlEnum id) { CheckIdRange(id); return s_xmlstringtable[(int)id].Namespace; }
internal static string?GetValueType(PackageXmlEnum id) { CheckIdRange(id); return(s_xmlstringtable[(int)id].ValueType); }
// Shim function to adequately cast the result of GetPropertyValue. private Nullable<DateTime> GetDateTimePropertyValue(PackageXmlEnum propertyName) { object valueObject = GetPropertyValue(propertyName); if (valueObject == null) return null; // If an object is there, it will be a DateTime (not a Nullable<DateTime>). return (Nullable<DateTime>)valueObject; }
internal static string GetValueType(PackageXmlEnum id) { CheckIdRange(id); return s_xmlstringtable[(int)id].ValueType; }
// Deserialize properties part. private void ParseCorePropertyPart(PackagePart part) { XmlReaderSettings xrs = new XmlReaderSettings(); xrs.NameTable = _nameTable; using (Stream stream = part.GetStream(FileMode.Open, FileAccess.Read)) // Create a reader that uses _nameTable so as to use the set of tag literals // in effect as a set of atomic identifiers. using (XmlReader reader = XmlReader.Create(stream, xrs)) { //This method expects the reader to be in ReadState.Initial. //It will make the first read call. PackagingUtilities.PerformInitialReadAndVerifyEncoding(reader); //Note: After the previous method call the reader should be at the first tag in the markup. //MoveToContent - Skips over the following - ProcessingInstruction, DocumentType, Comment, Whitespace, or SignificantWhitespace //If the reader is currently at a content node then this function call is a no-op if (reader.MoveToContent() != XmlNodeType.Element || (object)reader.NamespaceURI != PackageXmlStringTable.GetXmlStringAsObject(PackageXmlEnum.PackageCorePropertiesNamespace) || (object)reader.LocalName != PackageXmlStringTable.GetXmlStringAsObject(PackageXmlEnum.CoreProperties)) { throw new XmlException(SR.CorePropertiesElementExpected, null, ((IXmlLineInfo)reader).LineNumber, ((IXmlLineInfo)reader).LinePosition); } // The schema is closed and defines no attributes on the root element. if (PackagingUtilities.GetNonXmlnsAttributeCount(reader) != 0) { throw new XmlException(SR.Format(SR.PropertyWrongNumbOfAttribsDefinedOn, reader.Name), null, ((IXmlLineInfo)reader).LineNumber, ((IXmlLineInfo)reader).LinePosition); } // Iterate through property elements until EOF. Note the proper closing of all // open tags is checked by the reader itself. // This loop deals only with depth-1 start tags. Handling of element content // is delegated to dedicated functions. int attributesCount; while (reader.Read() && reader.MoveToContent() != XmlNodeType.None) { // Ignore end-tags. We check element errors on opening tags. if (reader.NodeType == XmlNodeType.EndElement) { continue; } // Any content markup that is not an element here is unexpected. if (reader.NodeType != XmlNodeType.Element) { throw new XmlException(SR.PropertyStartTagExpected, null, ((IXmlLineInfo)reader).LineNumber, ((IXmlLineInfo)reader).LinePosition); } // Any element below the root should open at level 1 exclusively. if (reader.Depth != 1) { throw new XmlException(SR.NoStructuredContentInsideProperties, null, ((IXmlLineInfo)reader).LineNumber, ((IXmlLineInfo)reader).LinePosition); } attributesCount = PackagingUtilities.GetNonXmlnsAttributeCount(reader); // Property elements can occur in any order (xsd:all). object localName = reader.LocalName; PackageXmlEnum xmlStringIndex = PackageXmlStringTable.GetEnumOf(localName); string valueType = PackageXmlStringTable.GetValueType(xmlStringIndex); if (Array.IndexOf(s_validProperties, xmlStringIndex) == -1) // An unexpected element is an error. { throw new XmlException( SR.Format(SR.InvalidPropertyNameInCorePropertiesPart, reader.LocalName), null, ((IXmlLineInfo)reader).LineNumber, ((IXmlLineInfo)reader).LinePosition); } // Any element not in the valid core properties namespace is unexpected. // The following is an object comparison, not a string comparison. if ((object)reader.NamespaceURI != PackageXmlStringTable.GetXmlStringAsObject(PackageXmlStringTable.GetXmlNamespace(xmlStringIndex))) { throw new XmlException(SR.UnknownNamespaceInCorePropertiesPart, null, ((IXmlLineInfo)reader).LineNumber, ((IXmlLineInfo)reader).LinePosition); } if (string.CompareOrdinal(valueType, "String") == 0) { // The schema is closed and defines no attributes on this type of element. if (attributesCount != 0) { throw new XmlException(SR.Format(SR.PropertyWrongNumbOfAttribsDefinedOn, reader.Name), null, ((IXmlLineInfo)reader).LineNumber, ((IXmlLineInfo)reader).LinePosition); } RecordNewBinding(xmlStringIndex, GetStringData(reader), true /*initializing*/, reader); } else if (string.CompareOrdinal(valueType, "DateTime") == 0) { int allowedAttributeCount = (object)reader.NamespaceURI == PackageXmlStringTable.GetXmlStringAsObject(PackageXmlEnum.DublinCoreTermsNamespace) ? 1 : 0; // The schema is closed and defines no attributes on this type of element. if (attributesCount != allowedAttributeCount) { throw new XmlException(SR.Format(SR.PropertyWrongNumbOfAttribsDefinedOn, reader.Name), null, ((IXmlLineInfo)reader).LineNumber, ((IXmlLineInfo)reader).LinePosition); } if (allowedAttributeCount != 0) { ValidateXsiType(reader, PackageXmlStringTable.GetXmlStringAsObject(PackageXmlEnum.DublinCoreTermsNamespace), W3cdtf); } RecordNewBinding(xmlStringIndex, GetDateData(reader), true /*initializing*/, reader); } else // An unexpected element is an error. { Debug.Fail("Unknown value type for properties"); } } } }
internal XmlStringTableStruct(object nameString, PackageXmlEnum ns, string?valueType) { _nameString = nameString; _namespace = ns; _valueType = valueType; }