/**
         * Parse and serialize methods.
         * @throws XmpException Forwards exceptions
         */
        private static void CoverParsing()
        {
            writeMajorLabel("Test parsing with multiple buffers and various options");

            var meta = XmpMetaFactory.ParseFromString(TestData.SIMPLE_RDF);

            printXmpMeta(meta, "Parse from String");

            meta = XmpMetaFactory.ParseFromString(TestData.SIMPLE_RDF, new ParseOptions {
                RequireXmpMeta = true
            });
            printXmpMeta(meta, "Parse and require xmpmeta element, which is missing");

            meta = XmpMetaFactory.ParseFromString(TestData.NAMESPACE_RDF);
            printXmpMeta(meta, "Parse RDF with multiple nested namespaces");

            meta = XmpMetaFactory.ParseFromString(TestData.XMPMETA_RDF, new ParseOptions {
                RequireXmpMeta = true
            });
            printXmpMeta(meta, "Parse and require xmpmeta element, which is present");

            meta = XmpMetaFactory.ParseFromString(TestData.INCONSISTENT_RDF);
            printXmpMeta(meta, "Parse and reconcile inconsistent aliases");

            try
            {
                XmpMetaFactory.ParseFromString(TestData.INCONSISTENT_RDF, new ParseOptions {
                    StrictAliasing = true
                });
            }
            catch (XmpException e)
            {
                log.WriteLine("Parse and do not reconcile inconsistent aliases - threw XmpException #{0} :   {1}", e.GetErrorCode(), e.Message);
            }
        }
        /**
         * Test CR and LF in values.
         * @throws XmpException Forwards exceptions
         */
        private static void CoverLinefeedValues()
        {
            writeMajorLabel("Test CR and LF in values");

            string valueWithCR   = "ASCII \r CR";
            string valueWithLF   = "ASCII \n LF";
            string valueWithCRLF = "ASCII \r\n CRLF";

            var meta = XmpMetaFactory.ParseFromString(TestData.NEWLINE_RDF);

            meta.SetProperty(TestData.NS2, "HasCR", valueWithCR);
            meta.SetProperty(TestData.NS2, "HasLF", valueWithLF);
            meta.SetProperty(TestData.NS2, "HasCRLF", valueWithCRLF);

            string result = XmpMetaFactory.SerializeToString(meta, new SerializeOptions {
                OmitPacketWrapper = true
            });

            log.WriteLine(result);

            var hasCR    = meta.GetPropertyString(TestData.NS1, "HasCR");
            var hasCR2   = meta.GetPropertyString(TestData.NS2, "HasCR");
            var hasLF    = meta.GetPropertyString(TestData.NS1, "HasLF");
            var hasLF2   = meta.GetPropertyString(TestData.NS2, "HasLF");
            var hasCRLF  = meta.GetPropertyString(TestData.NS1, "HasCRLF");
            var hasCRLF2 = meta.GetPropertyString(TestData.NS2, "HasCRLF");

            if (hasCR == valueWithCR && hasCR2 == valueWithCR &&
                hasLF == valueWithLF && hasLF2 == valueWithLF &&
                hasCRLF == valueWithCRLF && hasCRLF2 == valueWithCRLF)
            {
                log.WriteLine();
                log.WriteLine("\n## HasCR and HasLF and HasCRLF correctly retrieved\n");
            }
        }
        /**
         * Test simple constructors and parsing, setting the instance ID
         * @throws XmpException Forwards exceptions
         */
        private static void CoverCreatingXmp()
        {
            writeMajorLabel("Test simple constructors and parsing, setting the instance ID");

            var meta1 = XmpMetaFactory.Create();

            printXmpMeta(meta1, "Empty XMP object");

            var meta2 = XmpMetaFactory.Create();

            meta2.SetObjectName("New object name");
            printXmpMeta(meta2, "XMP object with name");

            var meta3 = XmpMetaFactory.ParseFromString(TestData.RDF_COVERAGE);

            printXmpMeta(meta3, "Construct and parse from buffer");

            meta3.SetProperty(XmpConstants.NsXmpMm, "InstanceID", "meta2:Original");
            printXmpMeta(meta3, "Add instance ID");

            XmpMeta meta4 = (XmpMeta)meta3.Clone();

            meta4.SetProperty(XmpConstants.NsXmpMm, "InstanceID", "meta2:Clone");
            printXmpMeta(meta3, "Clone and add instance ID");
        }
Exemple #4
0
        public void BillionLaughs_DoctypeDisabled()
        {
            var testdata = @"<?xml version=""1.0""?>
                <!DOCTYPE lolz [
                <!ENTITY lol ""lol"">
                <!ENTITY lol2 ""&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;"">
                <!ENTITY lol3 ""&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;"">
                <!ENTITY lol4 ""&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;"">
                <!ENTITY lol5 ""&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;"">
                <!ENTITY lol6 ""&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;"">
                <!ENTITY lol7 ""&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;"">
                <!ENTITY lol8 ""&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;"">
                <!ENTITY lol9 ""&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;"">
                ]>
                <lolz>&lol9;</lolz>";

            XmpException e = null;

            try
            {
                // doctype not allowed by default
                XmpMetaFactory.ParseFromString(testdata);
            }
            catch (XmpException ex)
            {
                e = ex;
            }

            Assert.NotNull(e);
            Assert.True(e.InnerException.Message.StartsWith("For security reasons DTD is prohibited"));
        }
Exemple #5
0
        public void BillionLaughs_DoctypeEnabled()
        {
            var testdata = @"<?xml version=""1.0""?>
                <!DOCTYPE lolz [
                <!ENTITY lol ""lol"">
                <!ENTITY lol2 ""&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;"">
                <!ENTITY lol3 ""&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;"">
                <!ENTITY lol4 ""&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;"">
                <!ENTITY lol5 ""&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;"">
                <!ENTITY lol6 ""&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;"">
                <!ENTITY lol7 ""&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;"">
                <!ENTITY lol8 ""&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;"">
                <!ENTITY lol9 ""&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;"">
                ]>
                <lolz>&lol9;</lolz>";

            var options = new Options.ParseOptions();

            // enable doctype
            options.DisallowDoctype = false;

            XmpException e = null;

            try
            {
                XmpMetaFactory.ParseFromString(testdata, options);
            }
            catch (XmpException ex)
            {
                e = ex;
            }

            Assert.NotNull(e);
            Assert.True(e.InnerException.Message.StartsWith("The input document has exceeded a limit set by MaxCharactersFromEntities"));
        }
Exemple #6
0
        public void XXE_DoctypeDisabled()
        {
            string testdata = @"<!DOCTYPE doc [<!ENTITY win SYSTEM ""c:\windows\win.ini"">]><doc></doc>";

            // doctype not allowed by default
            Assert.Throws <XmpException>(() => XmpMetaFactory.ParseFromString(testdata));
        }
Exemple #7
0
        public FileIndexItem GetDataFromString(string xmpDataAsString, FileIndexItem databaseItem = null)
        {
            // Does not require appSettings

            if (databaseItem == null)
            {
                databaseItem = new FileIndexItem();
            }

            try
            {
                var xmp = XmpMetaFactory.ParseFromString(xmpDataAsString);
                // ContentNameSpace is for example : Namespace=http://...
                databaseItem = GetDataContentNameSpaceTypes(xmp, databaseItem);
                // NullNameSpace is for example : string.Empty
                databaseItem = GetDataNullNameSpaceTypes(xmp, databaseItem);
            }
            catch (XmpException e)
            {
                Console.WriteLine($"XmpException {databaseItem.FilePath} >>\n{e}\n <<XmpException");
                databaseItem.Tags       = "XmpException";
                databaseItem.ColorClass = ColorClassParser.Color.None;
            }


            return(databaseItem);
        }
        /**
         * Adds information about the PDF/A conformance level to the XMP metadata.
         *
         * @param conformanceLevel
         * @throws IOException
         */
        private void AddRdfDescription(PdfAConformanceLevel conformanceLevel)
        {
            switch (conformanceLevel)
            {
            case PdfAConformanceLevel.PDF_A_1A:
                xmpMeta.SetProperty(XmpConst.NS_PDFA_ID, PdfAProperties.PART, "1");
                xmpMeta.SetProperty(XmpConst.NS_PDFA_ID, PdfAProperties.CONFORMANCE, "A");
                break;

            case PdfAConformanceLevel.PDF_A_1B:
                xmpMeta.SetProperty(XmpConst.NS_PDFA_ID, PdfAProperties.PART, "1");
                xmpMeta.SetProperty(XmpConst.NS_PDFA_ID, PdfAProperties.CONFORMANCE, "B");
                break;

            case PdfAConformanceLevel.PDF_A_2A:
                xmpMeta.SetProperty(XmpConst.NS_PDFA_ID, PdfAProperties.PART, "2");
                xmpMeta.SetProperty(XmpConst.NS_PDFA_ID, PdfAProperties.CONFORMANCE, "A");
                break;

            case PdfAConformanceLevel.PDF_A_2B:
                xmpMeta.SetProperty(XmpConst.NS_PDFA_ID, PdfAProperties.PART, "2");
                xmpMeta.SetProperty(XmpConst.NS_PDFA_ID, PdfAProperties.CONFORMANCE, "B");
                break;

            case PdfAConformanceLevel.PDF_A_2U:
                xmpMeta.SetProperty(XmpConst.NS_PDFA_ID, PdfAProperties.PART, "2");
                xmpMeta.SetProperty(XmpConst.NS_PDFA_ID, PdfAProperties.CONFORMANCE, "U");
                break;

            case PdfAConformanceLevel.PDF_A_3A:
                xmpMeta.SetProperty(XmpConst.NS_PDFA_ID, PdfAProperties.PART, "3");
                xmpMeta.SetProperty(XmpConst.NS_PDFA_ID, PdfAProperties.CONFORMANCE, "A");
                break;

            case PdfAConformanceLevel.PDF_A_3B:
                xmpMeta.SetProperty(XmpConst.NS_PDFA_ID, PdfAProperties.PART, "3");
                xmpMeta.SetProperty(XmpConst.NS_PDFA_ID, PdfAProperties.CONFORMANCE, "B");
                break;

            case PdfAConformanceLevel.PDF_A_3U:
                xmpMeta.SetProperty(XmpConst.NS_PDFA_ID, PdfAProperties.PART, "3");
                xmpMeta.SetProperty(XmpConst.NS_PDFA_ID, PdfAProperties.CONFORMANCE, "U");
                break;

            case PdfAConformanceLevel.ZUGFeRD:
                xmpMeta.SetProperty(XmpConst.NS_PDFA_ID, PdfAProperties.PART, "3");
                xmpMeta.SetProperty(XmpConst.NS_PDFA_ID, PdfAProperties.CONFORMANCE, "B");
                IXmpMeta taggedExtensionMeta = XmpMetaFactory.ParseFromString(zugferdExtension);
                XmpUtils.AppendProperties(taggedExtensionMeta, xmpMeta, true, false);
                break;

            default:
                break;
            }
            if (writer.IsTagged())
            {
                IXmpMeta taggedExtensionMeta = XmpMetaFactory.ParseFromString(pdfUaExtension);
                XmpUtils.AppendProperties(taggedExtensionMeta, xmpMeta, true, false);
            }
        }
        /**
         * Literal value set/get methods
         * @throws XmpException
         */
        private static void CoverLiteralProperties()
        {
            writeMajorLabel("Test SetProperty... and getProperty... methods " +
                            "(set/get with literal values)");

            var meta      = XmpMetaFactory.ParseFromString(TestData.DATETIME_RDF);
            var dateValue = XmpDateTimeFactory.Create(2000, 1, 2, 3, 4, 5, 0);

            meta.SetPropertyBoolean(TestData.NS1, "Bool0", false);
            meta.SetPropertyBoolean(TestData.NS1, "Bool1", true);
            meta.SetPropertyInteger(TestData.NS1, "Int", 42);
            meta.SetPropertyDouble(TestData.NS1, "Double", 4.2);

            meta.SetPropertyDate(TestData.NS1, "Date10", dateValue);

/*
 *          TODO reinstate this code
 *
 *          int offset = (/* hour #1# 06 * 3600 * 1000 + /* minute #1# 07 * 60 * 1000) * /* sign #1# 1;
 *          dateValue.SetTimeZone(new SimpleTimeZone(offset, "test"));
 *          meta.SetPropertyDate (NS1, "Date11", dateValue);
 *          offset *= -1;
 *          dateValue.SetTimeZone(new SimpleTimeZone(offset, "test"));
 *          meta.SetPropertyDate (NS1, "Date12", dateValue);
 *          dateValue.SetNanosecond(9);
 *          meta.SetPropertyDate (NS1, "Date13", dateValue);
 */

            printXmpMeta(meta, "A few basic binary Set... calls");
            log.WriteLine();

            bool b = meta.GetPropertyBoolean(TestData.NS1, "Bool0");

            log.WriteLine("getPropertyBoolean ns1:Bool0 =   " + b);

            b = meta.GetPropertyBoolean(TestData.NS1, "Bool1");
            log.WriteLine("getPropertyBoolean ns1:Bool1 =   " + b);

            int integer = meta.GetPropertyInteger(TestData.NS1, "Int");

            log.WriteLine("getPropertyBoolean ns1:Int =   " + integer);

            double d = meta.GetPropertyDouble(TestData.NS1, "Double");

            log.WriteLine("getPropertyBoolean ns1:Int =   " + d);
            log.WriteLine();

            for (int i = 1; i <= 13; i++)
            {
                var dateName = "Date" + i;
                var dt       = meta.GetPropertyDate(TestData.NS1, dateName);
                log.WriteLine("getPropertyDate (" + i + ") =   " + dt);
                meta.SetPropertyDate(TestData.NS2, dateName, dateValue);
            }

            printXmpMeta(meta, "Get and re-set the dates in NS2");
        }
Exemple #10
0
 virtual public void AddRdfDescription(XmpSchema s)
 {
     try {
         String str = "<rdf:RDF xmlns:rdf=\"" + XmpConst.NS_RDF + "\">" +
                      "<rdf:Description rdf:about=\"" + xmpMeta.ObjectName +
                      "\" " +
                      s.Xmlns +
                      ">" +
                      s.ToString() +
                      "</rdf:Description></rdf:RDF>\n";
         IXmpMeta extMeta = XmpMetaFactory.ParseFromString(str);
         XmpUtils.AppendProperties(extMeta, xmpMeta, true, true);
     }
     catch (XmpException xmpExc) {
         throw new IOException(xmpExc.Message);
     }
 }
 public void AddRdfDescription(String xmlns, String content)
 {
     try {
         String str = "<rdf:RDF xmlns:rdf=\"" + XmpConst.NS_RDF + "\">" +
                      "<rdf:Description rdf:about=\"" + xmpMeta.ObjectName +
                      "\" " +
                      xmlns +
                      ">" +
                      content +
                      "</rdf:Description></rdf:RDF>\n";
         byte[]   bytes   = Encoding.Convert(Encoding.UTF8, Encoding.ASCII, Encoding.UTF8.GetBytes(str));
         IXmpMeta extMeta = XmpMetaFactory.ParseFromString(str);
         XmpUtils.AppendProperties(extMeta, xmpMeta, true, true);
     }
     catch (XmpException xmpExc) {
         throw new IOException(xmpExc.Message);
     }
 }
Exemple #12
0
        public void XXE_DoctypeEnabled()
        {
            string testdata = @"<!DOCTYPE doc [<!ENTITY win SYSTEM ""c:\windows\win.ini"">]><doc></doc>";

            var options = new Options.ParseOptions();

            // enable doctype
            options.DisallowDoctype = false;
            Exception e = null;

            try
            {
                XmpMetaFactory.ParseFromString(testdata, options);
            }
            catch (Exception ex)
            {
                e = ex;
            }
            Assert.Null(e);
        }
Exemple #13
0
        public void Sample1()
        {
            // https://github.com/drewnoakes/metadata-extractor-dotnet/issues/66

            const string xmpPacket = @"<?xpacket begin='' id='W5M0MpCehiHzreSzNTczkc9d'?>
<x:xmpmeta xmlns:x=""adobe:ns:meta/"">
  <rdf:RDF xmlns:rdf=""http://www.w3.org/1999/02/22-rdf-syntax-ns#"">
    <rdf:Description rdf:about=""uuid:faf5bdd5-ba3d-11da-ad31-d33d75182f1b"" xmlns:dc=""http://purl.org/dc/elements/1.1/""/>
    <rdf:Description rdf:about=""uuid:faf5bdd5-ba3d-11da-ad31-d33d75182f1b"" xmlns:xmp=""http://ns.adobe.com/xap/1.0/"">
      <xmp:CreateDate>2016-06-15T08:38:12.946</xmp:CreateDate>
    </rdf:Description>
    <rdf:Description rdf:about=""uuid:faf5bdd5-ba3d-11da-ad31-d33d75182f1b"" xmlns:dc=""http://purl.org/dc/elements/1.1/"">
      <dc:creator>
        <rdf:Seq xmlns:rdf=""http://www.w3.org/1999/02/22-rdf-syntax-ns#"">
          <rdf:li>xxx</rdf:li>
        </rdf:Seq>
      </dc:creator>
    </rdf:Description>
  </rdf:RDF>
</x:xmpmeta>";

            XmpMetaFactory.ParseFromString(xmpPacket);
        }
        /**
         * Cover different use cases of the <code>XmpIterator</code>.
         * @throws XmpException Forwards exceptions
         */
        private static void CoverIterator()
        {
            writeMajorLabel("Test iteration methods");

            var meta = XmpMetaFactory.ParseFromString(TestData.RDF_COVERAGE);

            meta.SetProperty(TestData.NS2, "Prop", "Prop value");
            meta.AppendArrayItem(TestData.NS2, "Bag", new PropertyOptions {
                IsArray = true
            }, "BagItem 2", null);
            meta.AppendArrayItem(TestData.NS2, "Bag", "BagItem 1");
            meta.AppendArrayItem(TestData.NS2, "Bag", "BagItem 3");

            printXmpMeta(meta, "Parse \"coverage\" RDF, add Bag items out of order");

/*
 *          TODO reinstate this code
 *
 *          writeMinorLabel ("Default iteration");
 *          for (XmpIterator it = meta.Iterator(); it.hasNext();)
 *          {
 *              XmpPropertyInfo prop = (XmpPropertyInfo) it.next();
 *              printPropertyInfo(prop);
 *          }
 *
 *          writeMinorLabel ("Iterate omitting qualifiers");
 *          for (XmpIterator it = meta.iterator(new IteratorOptions().setOmitQualifiers(true)); it
 *                  .hasNext();)
 *          {
 *              XmpPropertyInfo prop = (XmpPropertyInfo) it.next();
 *              printPropertyInfo(prop);
 *          }
 *
 *          writeMinorLabel("Iterate with just leaf names");
 *          for (XmpIterator it = meta.iterator(new IteratorOptions().setJustLeafname(true)); it
 *                  .hasNext();)
 *          {
 *              XmpPropertyInfo prop = (XmpPropertyInfo) it.next();
 *              printPropertyInfo(prop);
 *          }
 *
 *          writeMinorLabel("Iterate with just leaf nodes");
 *          for (XmpIterator it = meta.iterator(new IteratorOptions().setJustLeafnodes(true)); it
 *                  .hasNext();)
 *          {
 *              XmpPropertyInfo prop = (XmpPropertyInfo) it.next();
 *              printPropertyInfo(prop);
 *          }
 *
 *          writeMinorLabel("Iterate just the schema nodes");
 *          for (XmpIterator it = meta.iterator(new IteratorOptions().setJustChildren(true)); it
 *                  .hasNext();)
 *          {
 *              XmpPropertyInfo prop = (XmpPropertyInfo) it.next();
 *              printPropertyInfo(prop);
 *          }
 *
 *          writeMinorLabel("Iterate the ns2: namespace");
 *          for (XmpIterator it = meta.iterator(NS2, null, null); it.hasNext();)
 *          {
 *              XmpPropertyInfo prop = (XmpPropertyInfo) it.next();
 *              printPropertyInfo(prop);
 *          }
 *
 *          writeMinorLabel("Start at ns2:Bag");
 *          for (XmpIterator it = meta.iterator(NS2, "Bag", null); it.hasNext();)
 *          {
 *              XmpPropertyInfo prop = (XmpPropertyInfo) it.next();
 *              printPropertyInfo(prop);
 *          }
 *
 *          writeMinorLabel("Start at ns2:NestedStructProp/ns1:Outer");
 *          for (XmpIterator it = meta.iterator(NS2, "NestedStructProp/ns1:Outer", null); it.hasNext();)
 *          {
 *              XmpPropertyInfo prop = (XmpPropertyInfo) it.next();
 *              printPropertyInfo(prop);
 *          }
 *
 *          writeMinorLabel("Iterate an empty namespace");
 *          for (XmpIterator it = meta.iterator("ns:Empty", null, null); it.hasNext();)
 *          {
 *              XmpPropertyInfo prop = (XmpPropertyInfo) it.next();
 *              printPropertyInfo(prop);
 *          }
 *
 *          writeMinorLabel("Iterate the top of the ns2: namespace with just leaf names");
 *          for (XmpIterator it = meta.iterator(NS2, null, new IteratorOptions().setJustChildren(true)
 *                  .setJustLeafname(true)); it.hasNext();)
 *          {
 *              XmpPropertyInfo prop = (XmpPropertyInfo) it.next();
 *              printPropertyInfo(prop);
 *          }
 *
 *          writeMinorLabel("Iterate the top of the ns2: namespace with just leaf nodes");
 *          for (XmpIterator it = meta.iterator(NS2, null, new IteratorOptions().setJustChildren(true)
 *                  .setJustLeafnodes(true)); it.hasNext();)
 *          {
 *              XmpPropertyInfo prop = (XmpPropertyInfo) it.next();
 *              printPropertyInfo(prop);
 *          }
 */
        }
        /**
         * Covers the serialization of an <code>XmpMeta</code> object with different options.
         * @throws Exception Forwards exceptions
         */
        private static void CoverSerialization()
        {
            writeMajorLabel("Test serialization with various options");

            var meta = XmpMetaFactory.ParseFromString(TestData.SIMPLE_RDF);

            meta.SetProperty(TestData.NS2, "Another", "Something in another schema");
            meta.SetProperty(TestData.NS2, "Yet/pdf:More", "Yet more in another schema");

            printXmpMeta(meta, "Parse simple RDF, serialize with various options");

            writeMinorLabel("Default serialize");
            log.WriteLine(XmpMetaFactory.SerializeToString(meta, null));

            writeMinorLabel("Compact RDF, no packet serialize");
            log.WriteLine(XmpMetaFactory.SerializeToString(meta, new SerializeOptions {
                UseCompactFormat = true, OmitPacketWrapper = true
            }));

            writeMinorLabel("Read-only serialize");
            log.WriteLine(XmpMetaFactory.SerializeToString(meta, new SerializeOptions {
                ReadOnlyPacket = true
            }));

            writeMinorLabel("Alternate newline serialize");
            log.WriteLine(XmpMetaFactory.SerializeToString(meta, new SerializeOptions {
                Newline = "<--newline-->\n", OmitPacketWrapper = true
            }));

            writeMinorLabel("Alternate indent serialize");
            log.WriteLine(XmpMetaFactory.SerializeToString(meta, new SerializeOptions {
                Indent = "-->", BaseIndent = 5, OmitPacketWrapper = true
            }));

            writeMinorLabel("Small padding serialize");
            log.WriteLine(XmpMetaFactory.SerializeToString(meta, new SerializeOptions {
                Padding = 10
            }));

            writeMinorLabel("Serialize with exact packet size");
            int s = XmpMetaFactory.SerializeToBuffer(meta, new SerializeOptions {
                ReadOnlyPacket = true
            }).Length;

            log.WriteLine("Minimum packet size is " + s + " bytes\n");

            // with the flag "exact packet size" the padding becomes the overall length of the packet
            byte[] buffer = XmpMetaFactory.SerializeToBuffer(meta, new SerializeOptions {
                ExactPacketLength = true, Padding = s
            });
            log.WriteLine(Encoding.UTF8.GetString(buffer, 0, buffer.Length));

            try
            {
                XmpMetaFactory.ParseFromString(XmpMetaFactory.SerializeToString(meta, new SerializeOptions {
                    ExactPacketLength = true, Padding = s - 1
                }));
            }
            catch (XmpException e)
            {
                log.WriteLine("\nExact packet size smaller than minimal packet length - threw XmpException #{0} :   {1}", e.GetErrorCode(), e.Message);
            }
        }