<?xml version="1.0" encoding="UTF-8"?>
<fos:functions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.w3.org/xpath-functions/spec/namespace ../../../xpath-functions-40/src/fos.xsd"
    xmlns:fos="http://www.w3.org/xpath-functions/spec/namespace">
    
    <fos:function name="to-octets" prefix="bin">
        <fos:signatures>
            <fos:proto name="to-octets" return-type="xs:unsignedByte*">
                <fos:arg name="value" type="(xs:hexBinary | xs:base64Binary)"/>
            </fos:proto>
        </fos:signatures>
        <fos:properties>
            <fos:property>deterministic</fos:property>
            <fos:property>context-independent</fos:property>
            <fos:property>focus-independent</fos:property>
        </fos:properties>
        <fos:summary>
            <p>Returns binary data as a sequence of integer octets.</p>
        </fos:summary>
        <fos:rules>
            <p>If <code>$value</code> is a <termref def="dt-zero-length"/> 
                <termref def="dt-binary-value"/> then the empty sequence is
                returned.</p>
            <p>Octets are returned in sequence, as instances of
                <code>xs:unsignedByte</code> (integers ranging from 0 to 255).</p>
        </fos:rules>
        <fos:examples>
            <fos:example>
                <fos:test>
                    <fos:expression>bin:to-octets(bin:hex('1122AAFF')</fos:expression>
                    <fos:result>17, 34, 170, 255</fos:result>
                </fos:test>
            </fos:example>
            <fos:example>
                <fos:test>
                    <fos:expression>bin:to-octets(bin:hex(''))</fos:expression>
                    <fos:result>()</fos:result>
                </fos:test>
            </fos:example>
        </fos:examples>
        <fos:changes>
            <fos:change>
                <p>The result type is changed from <code>xs:integer</code> to
                <code>xs:unsignedByte</code>. This is made possible by the more liberal
                coercion rules defined in XPath 4.0.</p>
            </fos:change>
        </fos:changes>
    </fos:function>

    <fos:function name="from-octets" prefix="bin">
        <fos:signatures>
            <fos:proto name="from-octets" return-type="xs:base64Binary">
                <fos:arg name="values" type="xs:unsignedByte*"/>
            </fos:proto>
        </fos:signatures>
        <fos:properties>
            <fos:property>deterministic</fos:property>
            <fos:property>context-independent</fos:property>
            <fos:property>focus-independent</fos:property>
        </fos:properties>
        <fos:summary>
            <p>Converts a sequence of octets into binary data.</p>
        </fos:summary>
        <fos:rules>
            <p>Octets are integers from 0 to 255.</p>
            <p>If <code>$values</code> is the empty sequence, the function returns a 
                <termref def="dt-zero-length"/> binary value.</p>
        </fos:rules>
 
        <fos:examples>
            <fos:example>
                <fos:test>
                    <fos:expression>bin:from-octets((17, 34, 170, 255))</fos:expression>
                    <fos:result>bin:hex('1122AAFF')</fos:result>
                </fos:test>
            </fos:example>
            <fos:example>
                <fos:test>
                    <fos:expression>bin:from-octets(())</fos:expression>
                    <fos:result>bin:hex('')</fos:result>
                </fos:test>
            </fos:example>
        </fos:examples>
        <fos:changes>
            <fos:change>
                <p>The argument type is changed from <code>xs:integer</code> to
                <code>xs:unsignedByte</code>. This is made possible by the more liberal
                coercion rules defined in XPath 4.0. A consequence of the change
                is that supplying an out-of-range integer value is now a type error
                with the standard error code <code>XPTY0004</code>, rather than the
                custom error code <code role="example">bin:octet-out-of-range</code> previously used.</p>
            </fos:change>
        </fos:changes>
    </fos:function>

    <fos:function name="hex" prefix="bin">
        <fos:signatures>
            <fos:proto name="hex" return-type="xs:base64Binary?">
                <fos:arg name="value" type="xs:string?"/>
            </fos:proto>
        </fos:signatures>
        <fos:properties>
            <fos:property>deterministic</fos:property>
            <fos:property>context-independent</fos:property>
            <fos:property>focus-independent</fos:property>
        </fos:properties>
        <fos:summary>
            <p>Constructs a binary value from a string of hexadecimal digits (<code>[0-9A-Fa-f]*</code>).</p>
        </fos:summary>
        <fos:rules>
            <p>If <code>$value</code> is the empty sequence, the function returns an empty
                sequence.</p>
            <p>Any whitespace and underscore characters are stripped from <code>$value</code>.</p>            
            <p>
                If the length of of the resulting string is an odd number, then 
                a single <code>"0"</code> digit is prepended to the value, so that it contains an 
                even number of hexadecimal digits.</p>
            <p>The resulting string is then cast to type <code>xs:hexBinary</code>,
            which is then cast to <code>xs:base64Binary</code>.</p>
        </fos:rules>
        <fos:equivalent style="xpath-expression" covers-error-cases="false">
$value ! (
  replace(., '[_\s]', '') 
  -> concat(if (string-length(.) mod 2 eq 1) { "0" }, .)
  -> xs:hexBinary(.)
  -> xs:base64Binary(.)
)
        </fos:equivalent>
        <fos:errors>
            <p><errorref spec="BIN40" code="non-numeric-character"/> is raised if <code>$value</code>
                cannot be parsed as a hexadecimal number.</p>
        </fos:errors>
        <fos:notes>
            <p>The order of octets in the result follows the order of characters in the string.</p>
            <p>If <code>$value</code> is an empty string, the result will be a
                <termref def="dt-zero-length"/> <code>xs:base64Binary</code> value.</p>
            <p>When the input string has an even number of characters, this function delivers the same
                result as the expression
                <code>xs:base64Binary(xs:hexBinary(<emph>$string</emph>))</code>.</p>
        </fos:notes>
        <fos:examples>
            <fos:example>
                <fos:test>
                    <fos:expression>bin:hex('1122_3F4E')</fos:expression>
                    <fos:result>xs:base64Binary("ESI/Tg==")</fos:result>
                </fos:test>
            </fos:example>
            <fos:example>
                <fos:test>
                    <fos:expression>bin:hex('122 3F4E')</fos:expression>
                    <fos:result>xs:base64Binary("ASI/Tg==")</fos:result>
                </fos:test>
            </fos:example>
        </fos:examples>
        <fos:changes>
            <fos:change issue="1750" PR="1753" date="2025-02-03">
                <p>The input string is now allowed to include embedded underscores and whitespace.</p>
            </fos:change>
        </fos:changes>
    </fos:function>

    <fos:function name="bin" prefix="bin">
        <fos:signatures>
            <fos:proto name="bin" return-type="xs:base64Binary?">
                <fos:arg name="value" type="xs:string?"/>
            </fos:proto>
        </fos:signatures>
        <fos:properties>
            <fos:property>deterministic</fos:property>
            <fos:property>context-independent</fos:property>
            <fos:property>focus-independent</fos:property>
        </fos:properties>
        <fos:summary>
            <p>Constructs a binary value from a string of zeroes and ones (<code>[01]*</code>)</p>
        </fos:summary>
        <fos:rules>
            <p>If <code>$value</code> is the empty sequence, the function returns an empty
                sequence.</p>
            <p>Any whitespace and underscore characters are stripped from <code>$value</code>.</p>
            <p>As many zero digits (<char>U+0030</char>) as necessary are prepended
                to <code>$value</code> to make its string length a multiple of 8.</p>
            <p>The string is then partitioned into substrings of length 8, and each such
            substring <var>B</var> is converted to an integer in the range 0 to 255
            by applying the function <code>fn:parse-integer(<var>B</var>, 2)</code>.
            The resulting sequence of integers is then converted to a <termref def="dt-binary-value"/>
            by applying the function <function>bin:from-octets</function>.</p>           
        </fos:rules>
        <fos:equivalent style="xpath-expression" covers-error-cases="false">
$value ! ( (: process input if present, otherwise return () :)
     (: strip underscores and whitespace :)
     replace(., '[_\s]', '')
     (: extend to a multiple of 8 binary digits :)
  -> concat(replicate("0", 7 - (string-length(.) - 1) mod 8), .)
     (: insert a separator after every 8 digits :)
  -> replace(., "(.{8})", "$1/")
     (: split into groups of 8 digits :)
  -> tokenize(., "/")[.]
     (: parse each group of 8 binary digits as a radix-2 integer :)
   ! parse-integer(., 2)
     (: construct a binary value from these octets :)
  -> bin:from-octets(.) 
)
        </fos:equivalent>
        <fos:errors>
            <p><errorref spec="BIN40" code="non-numeric-character"/> is raised if <code>$value</code>
                cannot be parsed as a binary number.</p>
        </fos:errors>
        <fos:notes>
            <p>The order of octets in the result follows the order of characters in the string.</p>
            <p>If <code>$value</code> is an empty string, the result will be a
                <termref def="dt-zero-length"/> <code>xs:base64Binary</code> value.</p>
        </fos:notes>
        <fos:examples>
            <fos:example>
                <fos:test>
                    <fos:expression>bin:bin('1101_0001_1101_0101')</fos:expression>
                    <fos:result>bin:hex("D1D5")</fos:result>
                </fos:test>
            </fos:example>
            <fos:example>
                <fos:test>
                    <fos:expression>bin:bin('1 0001 1101 0101')</fos:expression>
                    <fos:result>bin:hex("11D5")</fos:result>
                </fos:test>
            </fos:example>
            <fos:example>
                <fos:test>
                    <fos:expression>bin:bin(' 101 ')</fos:expression>
                    <fos:result>bin:hex("05")</fos:result>
                </fos:test>
            </fos:example>
        </fos:examples>
        <fos:changes>
            <fos:change issue="1750" PR="1753" date="2025-02-03">
                <p>The input string is now allowed to include embedded underscores and whitespace.</p>
            </fos:change>
        </fos:changes>
    </fos:function>

    <fos:function name="octal" prefix="bin">
        <fos:signatures>
            <fos:proto name="octal" return-type="xs:base64Binary?">
                <fos:arg name="value" type="xs:string?"/>
            </fos:proto>
        </fos:signatures>
        <fos:properties>
            <fos:property>deterministic</fos:property>
            <fos:property>context-independent</fos:property>
            <fos:property>focus-independent</fos:property>
        </fos:properties>
        <fos:summary>
            <p>Constructs a binary value from a string of octal digits (<code>[0-7]*</code>)</p>
        </fos:summary>
        <fos:rules>
            <p>If <code>$value</code> is the empty sequence, the function returns an empty
                sequence.</p>
            <p>Otherwise:</p>
            <olist>
                <item><p>Any whitespace and underscore characters are stripped from <code>$value</code>.</p></item>
                <item><p>Each octal digit in <code>$value</code> is replaced by its binary equivalent
                (<code>"0"</code> → <code>"000"</code>, <code>"1"</code> → <code>"001"</code>, 
                    <code>"2"</code> → <code>"010"</code>, <code>"3"</code> → <code>"011"</code>, 
                    <code>"4"</code> → <code>"100"</code>,
                <code>"5"</code> → <code>"101"</code>, <code>"6"</code> → <code>"110"</code>, 
                    <code>"7"</code> → <code>"111"</code>).</p></item>
                <item><p>A maximum of two leading zero digits are stripped.</p>
                </item>
                <item><p>The resulting string
                is converted to a <termref def="dt-binary-value"/> by applying
                the function <function>bin:bin</function> to the result.</p></item>
            </olist>
                
            <p>The order of octets in the result follows the order of characters in the string.</p>
            
            
        </fos:rules>
          <fos:equivalent style="xpath-expression" covers-error-cases="false">
$value ! (
  replace(., '[_\s]', '') 
  =>  characters()
  =!> { "0": "000", "1": "001", "2": "010", "3": "011", 
        "4": "100", "5": "101", "6": "110", "7": "111" }()
  =!> replace("^0?0?", "")     
  =>  string-join()
  =>  bin:bin()
)
        </fos:equivalent>
        <fos:errors>
            <p><errorref spec="BIN40" code="non-numeric-character"/> is raised if <code>$value</code>
                cannot be parsed as an octal number.</p>
        </fos:errors>
        <fos:notes>
            <p>The order of octets in the result follows the order of characters in the string.</p>
            <p>If <code>$value</code> is a zero-length string, the result will be a
                <termref def="dt-zero-length"/> <code>xs:base64Binary</code> value.</p>
            
           
            <p>The rule for padding to a whole number of octets ensures that leading zeroes
            are significant in determining the length of the final binary value, while also
            allowing a value of any length to be constructed. For example (underscores added
            for readability):</p>
                
            <ulist>
                <item><p>An input of <code>"0"</code> translates first to the string <code>"000"</code>; two
                leading zeros are removed producing <code>"0"</code>, which <function>bin:bin</function>
                converts to <code>bin:hex("00")</code>.</p></item>
                <item><p>An input of <code>"155"</code> translates to the 
                    binary string <code>"001_101_101"</code>. The first two zeroes
                    are removed, and <function>bin:bin</function> converts the result to 
                    <code>bin:hex("6D")</code></p></item>
                <item><p>An input of <code>"355"</code> translates to the 
                    binary string <code>"011_101_101"</code>. The first zero is removed,
                    and <function>bin:bin</function> converts the result to 
                    <code>bin:hex("ED")</code>.</p></item>
                <item><p>An input of <code>"555"</code> translates to the 
                    string <code>"101_101_101"</code>, which <function>bin:bin</function> converts to 
                    <code>bin:hex("016D")</code>.</p></item>
                <item><p>An input of <code>"0155"</code> translates to the 
                    string <code>"000_001_101_101"</code>. The first two zeros are
                    stripped giving <code>"0_001_101_101"</code>, which <function>bin:bin</function> converts to 
                    <code>bin:hex("006D")</code>.</p></item>
            </ulist>
            <!--<p>There are <termref def="dt-binary-value">binary values</termref> that cannot
            be constructed using this function. For example, it is not possible to 
            construct the value <code>bin:hex("7F")</code>, because the apparent
            equivalent <code>bin:octal("177")</code> represents a 9-bit value, 
                which is padded to the two-octet value <code>bin:hex("007F")</code>.
            If it is known that octal values will always represent single octets, 
            the required octet can be extracted by an expression such as
            <code>bin:octal($value) => bin:to-octets() => foot() => bin:from-octets()</code></p>-->
            
            <p>The result of the expression <code>bin:octal("177 177 177 177")</code>
            is the 5-octet value <code>bin:hex("03 F9 FC FE 7F")</code> and not (as some
            users might imagine) the 4-octet value <code>bin:hex("7F 7F 7F 7F")</code>.
            To achieve the latter result, the expression <code>$value => tokenize() =>
            bin:octal() => bin:join()</code> can be used.</p>
        </fos:notes>
        <fos:examples>
            <fos:example>
                <fos:test>
                    <fos:expression>bin:octal('')</fos:expression>
                    <fos:result>bin:hex('')</fos:result>
                </fos:test>
                <fos:test>
                    <fos:expression>bin:octal('0')</fos:expression>
                    <fos:result>bin:hex('00')</fos:result>
                </fos:test>
                <fos:test>
                    <fos:expression>bin:octal('377')</fos:expression>
                    <fos:result>bin:hex('FF')</fos:result>
                </fos:test>
                <fos:test>
                    <fos:expression>bin:octal('777')</fos:expression>
                    <fos:result>bin:hex('01FF')</fos:result>
                </fos:test>
                <fos:test>
                    <fos:expression>bin:octal('0377')</fos:expression>
                    <fos:result>bin:hex('00FF')</fos:result>
                </fos:test>
                <fos:test>
                    <fos:expression>bin:octal('11_223_047')</fos:expression>
                    <fos:result>bin:hex('252627')</fos:result>
                </fos:test>
            </fos:example>
        </fos:examples>
        <fos:changes>
            <fos:change issue="1750" PR="1753" date="2025-02-03">
                <p>The input string is now allowed to include embedded underscores and whitespace.</p>
            </fos:change>
            <fos:change issue="1750" PR="1753" date="2025-02-03">
                <p>The way in which the value is adjusted to a whole number of octets has
                    been clarified. The rules have been made more precise, and might not
                    match the interpretation adopted by existing implementations.</p>
            </fos:change>
        </fos:changes>
    </fos:function>

    <fos:function name="part" prefix="bin">
        <fos:signatures>
            <fos:proto name="part" return-type="xs:base64Binary?">
                <fos:arg name="value" type="(xs:hexBinary | xs:base64Binary)?"/>
                <fos:arg name="offset" type="xs:integer"/>
                <fos:arg name="size" type="xs:integer?" default="()"/>
            </fos:proto>
        </fos:signatures>
        <fos:properties>
            <fos:property>deterministic</fos:property>
            <fos:property>context-independent</fos:property>
            <fos:property>focus-independent</fos:property>
        </fos:properties>
        <fos:summary>
            <p>Selects a specified range of octets from a binary value.</p>
        </fos:summary>
        <fos:rules>
            <p>If the value of <code>$value</code> is the empty sequence, the function returns an empty
                sequence.</p>
            <p>Otherwise, the function returns a section of binary data starting 
                at <code>$offset</code>. The offset is zero-based. If
                <code>$size</code> is present and non-empty, the size of the returned binary data is
                <code>$size</code> octets. If <code>$size</code> is absent or empty, 
                all remaining data from <code>$offset</code> is returned.</p>
            <p>The <code>$offset</code> is zero based.</p>
            <p>The values of <code>$offset</code> and <code>$size</code>
                <rfc2119>must</rfc2119> be non-negative integers.</p>
            <p>It is a dynamic error if <code>$offset</code> + <code>$size</code> is larger than the
                size of the binary data in <code>$value</code>.</p>
            
        </fos:rules>
        <fos:equivalent style="xpath-expression" covers-error-cases="false">
$value => bin:to-octets() => subsequence($offset + 1, $size) => bin:from-octets()         
        </fos:equivalent>
        <fos:errors>
            <p><errorref spec="BIN40" code="index-out-of-range"/> is raised if <code>$offset</code> is
                negative or <code>$offset + $size</code> is larger than the size of the binary data
                of <code>$value</code>.</p>
            <p><errorref spec="BIN40" code="negative-size"/> is raised if <code>$size</code> is
                negative.</p>
        </fos:errors>
        <fos:notes>
            <p>The function differs in several ways from <function>fn:subsequence</function> 
                and <function>fn:substring</function>:</p>
            <ulist>
                <item><p>The <code>$offset</code> and <code>$size</code> are supplied
                as integers, not doubles.</p></item>
                <item><p>The <code>$offset</code> is zero-based, not one-based.</p></item>
                <item><p>An error is raised if the selection goes outside the bounds
                of the value.</p></item>
            </ulist>
            
        </fos:notes>
        <fos:examples>
            <fos:example>
                <fos:test>
                    <fos:expression>bin:part(bin:hex('11223344556677'), 0, 4)</fos:expression>
                    <fos:result>bin:hex('11223344')</fos:result>
                </fos:test>
                <fos:test>
                    <fos:expression>bin:part(bin:hex('11223344556677'), 4)</fos:expression>
                    <fos:result>bin:hex('556677')</fos:result>
                </fos:test>
                <fos:test>
                    <fos:expression>bin:part(bin:hex('11223344556677'), 7)</fos:expression>
                    <fos:result>bin:hex('')</fos:result>
                </fos:test>
                <fos:test>
                    <fos:expression>bin:part(bin:hex('11223344556677'), 5, 0)</fos:expression>
                    <fos:result>bin:hex('')</fos:result>
                </fos:test>
            </fos:example>
            <fos:example>
                <p>This example tests whether <code>$data</code> starts with binary content consistent
                    with a PDF file:</p>
                <eg xml:space="preserve">bin:part($data, 0, 4) eq bin:hex("25504446")</eg>
                <p><code>25504446</code> is the magic number for PDF files: it is the hexadecimal 
                    representation of the result of encoding the string <code>"%PDF"</code>
                    in UTF-8 (or US-ASCII). Note that the function
                    <function>bin:encode-string</function> can be used
                    to convert a string to its binary representation.</p>
            </fos:example>
        </fos:examples>
    </fos:function>

    <fos:function name="insert-before" prefix="bin">
        <fos:signatures>
            <fos:proto name="insert-before" return-type="xs:base64Binary?">
                <fos:arg name="value" type="(xs:hexBinary | xs:base64Binary)?"/>
                <fos:arg name="offset" type="xs:integer"/>
                <fos:arg name="extra" type="(xs:hexBinary | xs:base64Binary)?"/>
            </fos:proto>
        </fos:signatures>
        <fos:properties>
            <fos:property>deterministic</fos:property>
            <fos:property>context-independent</fos:property>
            <fos:property>focus-independent</fos:property>
        </fos:properties>
        <fos:summary>
            <p>Inserts octets at a given point in a binary value.</p>
        </fos:summary>
        <fos:rules>
            <p>If the value of <code>$value</code> is the empty sequence, the function returns an empty
                sequence.</p>
            <p>If the value of <code>$extra</code> is the empty sequence, the function returns
                <code>$value</code>.</p>
            <p>Otherwise, the function returns a binary value formed
                by concatenating the <code>bin:part($value, 0, $offset)</code>, then
                <code>$extra</code>, then <code>bin:part($value, $offset)</code>
                <code>$extra</code>, and then the remaining data from <code>$value</code>.</p>
            <p>The <code>$offset</code> is zero based, and 
                <rfc2119>must</rfc2119> be non-negative.</p>

        </fos:rules>
        <fos:equivalent style="xpath-expression" covers-error-cases="false">
$value
=> bin:to-octets() 
=> insert-before($offset + 1, bin:to-octets($extra)) 
=> bin:from-octets()         
        </fos:equivalent>
        <fos:errors>
            <p><errorref spec="BIN40" code="index-out-of-range"/> is raised if <code>$offset</code> is
                negative or <code>$offset</code> is larger than the size of the binary data of
                <code>$value</code>.</p>
        </fos:errors>
        <fos:notes>
            <p>If <code>$offset</code> is zero, the result is the binary concatenation of
                <code>$extra</code> and <code>$value</code>.</p>
        </fos:notes>
        <fos:examples>
            <fos:example>
                <fos:test>
                    <fos:expression>bin:insert-before(bin:hex('FFFF'), 1, bin:hex('00'))</fos:expression>
                    <fos:result>bin:hex('FF00FF')</fos:result>
                </fos:test>
                <fos:test>
                    <fos:expression>bin:insert-before(bin:hex('FFFF'), 0, bin:hex('00'))</fos:expression>
                    <fos:result>bin:hex('00FFFF')</fos:result>
                </fos:test>
                <fos:test>
                    <fos:expression>bin:insert-before(bin:hex('FFFF'), 2, bin:hex('00'))</fos:expression>
                    <fos:result>bin:hex('FFFF00')</fos:result>
                </fos:test>
            </fos:example>
        </fos:examples>
    </fos:function>

    <fos:function name="length" prefix="bin">
        <fos:signatures>
            <fos:proto name="length" return-type="xs:integer">
                <fos:arg name="value" type="(xs:hexBinary | xs:base64Binary)"/>
            </fos:proto>
        </fos:signatures>
        <fos:properties>
            <fos:property>deterministic</fos:property>
            <fos:property>context-independent</fos:property>
            <fos:property>focus-independent</fos:property>
        </fos:properties>
        <fos:summary>
            <p>Returns the size of a binary value, measured in octets.</p>
        </fos:summary>
        <fos:rules>
            <p>Returns the number of octets in the binary value <code>$value</code>.</p>
        </fos:rules>
        <fos:equivalent style="xpath-expression" covers-error-cases="true">
            count(bin:to-octets($value)) 
        </fos:equivalent>
        <fos:examples>
            <fos:example>
                <fos:test>
                    <fos:expression>bin:length(bin:hex('FFFF'))</fos:expression>
                    <fos:result>2</fos:result>
                </fos:test>
                <fos:test>
                    <fos:expression>bin:length(bin:hex(''))</fos:expression>
                    <fos:result>0</fos:result>
                </fos:test>
            </fos:example>
        </fos:examples>
    </fos:function>

    <fos:function name="join" prefix="bin">
        <fos:signatures>
            <fos:proto name="join" return-type="xs:base64Binary">
                <fos:arg name="values" type="(xs:hexBinary | xs:base64Binary)*"/>
            </fos:proto>
        </fos:signatures>
        <fos:properties>
            <fos:property>deterministic</fos:property>
            <fos:property>context-independent</fos:property>
            <fos:property>focus-independent</fos:property>
        </fos:properties>
        <fos:summary>
            <p>Concatenates a sequence of binary values in order.</p>
        </fos:summary>
        <fos:rules>
            <p>The function returns an <code>xs:base64Binary</code> value created by concatenating the
                binary values in the sequence <code>$values</code>, in order.</p>            
        </fos:rules>
        <fos:equivalent style="xpath-expression" covers-error-cases="true"> 
$values =!> bin:to-octets() => bin:from-octets() 
        </fos:equivalent>
        <fos:notes>
            <p>If <code>$values</code> is the empty sequence, the function returns a 
                <termref def="dt-zero-length"/> binary value.</p>
        </fos:notes>
        <fos:examples>
            <fos:example>
                <fos:test>
                    <fos:expression>bin:join((bin:hex('0000'), bin:hex('FFFF'), bin:hex('0000'))</fos:expression>
                    <fos:result>bin:hex('0000FFFF0000')</fos:result>
                </fos:test>
                <fos:test>
                    <fos:expression>bin:join(())</fos:expression>
                    <fos:result>bin:hex('')</fos:result>
                </fos:test>
                <fos:test>
                    <fos:expression>bin:join( (1 to 4) ! bin:hex('F0') )</fos:expression>
                    <fos:result>bin:hex('F0F0F0F0')</fos:result>
                </fos:test>
            </fos:example>
        </fos:examples>
    </fos:function>

    <fos:function name="pad-left" prefix="bin">
        <fos:signatures>
            <fos:proto name="pad-left" return-type="xs:base64Binary?">
                <fos:arg name="value" type="(xs:hexBinary | xs:base64Binary)?"/>
                <fos:arg name="count" type="xs:integer"/>
                <fos:arg name="octet" type="xs:unsigned-byte?" default="0"/>
            </fos:proto>
        </fos:signatures>
        <fos:properties>
            <fos:property>deterministic</fos:property>
            <fos:property>context-independent</fos:property>
            <fos:property>focus-independent</fos:property>
        </fos:properties>
        <fos:summary>
            <p>Returns a binary value created by padding <code>$value</code> on the left with <code>$count</code>
                occurrences of <code>$octet</code>.</p>
        </fos:summary>
        <fos:rules>
            <p>If the value of <code>$value</code> is the empty sequence, the function returns an empty
                sequence.</p>
            <p>Otherwise, the function returns a binary value consisting of
                <code>$count</code> instances of <code>$octet</code>, followed by <code>$value</code>. 
            The default for <code>$octet</code> is zero (0).</p>
            <p><code>$size</code>
                <rfc2119>must</rfc2119> be a non-negative integer.</p>
            
        </fos:rules>
        <fos:equivalent style="xpath-expression" covers-error-cases="false">
(replicate($octet, $count), bin:to-octets($value)) 
=> bin:from-octets()         
        </fos:equivalent>
        <fos:errors>
            <p><errorref spec="BIN40" code="negative-size"/> is raised if <code>$size</code> is
                negative.</p>
 
        </fos:errors>
        <fos:examples>
            <fos:example>
                <fos:test>
                    <fos:expression>bin:pad-left(bin:hex('FFFF'), 3)</fos:expression>
                    <fos:result>bin:hex('000000FFFF')</fos:result>
                </fos:test>
                <fos:test>
                    <fos:expression>bin:pad-left(bin:hex('0000'), 3, 255)</fos:expression>
                    <fos:result>bin:hex('FFFFFF0000')</fos:result>
                </fos:test>
                <fos:test>
                    <fos:expression>bin:pad-left(bin:hex(''), 8)</fos:expression>
                    <fos:result>bin:hex('0000000000000000')</fos:result>
                </fos:test>
            </fos:example>
        </fos:examples>
        <fos:changes>
            <fos:change issue="1750" PR="1753" date="2025-02-03">
                <p>The argument type for <code>$octet</code> is changed from <code>xs:integer</code> to
                <code>xs:unsignedByte</code>. This is made possible by the more liberal
                coercion rules defined in XPath 4.0. A consequence of the change
                is that supplying an out-of-range integer value is now a type error
                with the standard error code <code>XPTY0004</code>, rather than the
                custom error code <code>bin:octet-out-of-range</code> previously used.</p>
            </fos:change>
        </fos:changes>
    </fos:function>
    
    <fos:function name="pad-right" prefix="bin">
        <fos:signatures>
            <fos:proto name="pad-right" return-type="xs:base64Binary?">
                <fos:arg name="value" type="(xs:hexBinary | xs:base64Binary)?"/>
                <fos:arg name="count" type="xs:integer"/>
                <fos:arg name="octet" type="xs:unsignedByte?" default="0"/>
            </fos:proto>
        </fos:signatures>
        <fos:properties>
            <fos:property>deterministic</fos:property>
            <fos:property>context-independent</fos:property>
            <fos:property>focus-independent</fos:property>
        </fos:properties>
        <fos:summary>
            <p>Returns a binary value created by padding <code>$value</code> on the 
                right with <code>$count</code> occurrences of <code>$octet</code>.</p>
        </fos:summary>
        <fos:rules>
            <p>If the value of <code>$value</code> is the empty sequence, the function returns an empty
                sequence.</p>
            <p>Otherwise, the function returns a binary value consisting of
                <code>$value, followed by </code><code>$count</code> instances of <code>$octet</code>. 
            The default for <code>$octet</code> is zero (0).</p>
            <p><code>$size</code>
                <rfc2119>must</rfc2119> be a non-negative integer.</p>
            
        </fos:rules>
        <fos:equivalent style="xpath-expression" covers-error-cases="false">
(bin:to-octets($value), replicate($octet, $count))
=> bin:from-octets()         
        </fos:equivalent>
        <fos:errors>
            <p><errorref spec="BIN40" code="negative-size"/> is raised if <code>$size</code> is
                negative.</p>

        </fos:errors>
        <fos:examples>
            <fos:example>
                <fos:test>
                    <fos:expression>bin:pad-right(bin:hex('FFFF'), 3)</fos:expression>
                    <fos:result>bin:hex('FFFF000000')</fos:result>
                </fos:test>
                <fos:test>
                    <fos:expression>bin:pad-right(bin:hex('0000'), 3, 255)</fos:expression>
                    <fos:result>bin:hex('0000FFFFFF')</fos:result>
                </fos:test>
                <fos:test>
                    <fos:expression>bin:pad-right(bin:hex(''), 8)</fos:expression>
                    <fos:result>bin:hex('0000000000000000')</fos:result>
                </fos:test>
            </fos:example>
        </fos:examples>
        <fos:changes>
            <fos:change issue="1750" PR="1753" date="2025-02-03">
                <p>The argument type for <code>$octet</code> is changed from <code>xs:integer</code> to
                <code>xs:unsignedByte</code>. This is made possible by the more liberal
                coercion rules defined in XPath 4.0. A consequence of the change
                is that supplying an out-of-range integer value is now a type error
                with the standard error code <code>XPTY0004</code>, rather than the
                custom error code <code>bin:octet-out-of-range</code> previously used.</p>
            </fos:change>
        </fos:changes>
    </fos:function>

    <fos:function name="find" prefix="bin">
        <fos:signatures>
            <fos:proto name="find" return-type="xs:integer?">
                <fos:arg name="value" type="(xs:hexBinary | xs:base64Binary)?"/>
                <fos:arg name="offset" type="xs:integer"/>
                <fos:arg name="search" type="(xs:hexBinary | xs:base64Binary)"/>
            </fos:proto>
        </fos:signatures>
        <fos:properties>
            <fos:property>deterministic</fos:property>
            <fos:property>context-independent</fos:property>
            <fos:property>focus-independent</fos:property>
        </fos:properties>
        <fos:summary>
            <p>Returns the position of the first occurrence of <code>$search</code> within
                <code>$value</code>, starting at <code>$offset</code>.</p>
        </fos:summary>
        <fos:rules>
            <p>If the value of <code>$value</code> is the empty sequence, the function returns an empty
                sequence.</p>
            <p>Otherwise, the function returns the lowest value of <var>P</var> that is greater than
                or equal to <code>$offset</code>,
                such that <code>bin:part($value, <var>P</var>, bin:length($search)) eq <var>P</var></code>.
                If there is no such value (that is, if <code>$search</code> is not found), 
                the function returns the empty sequence.</p>
            <p>If <code>$search</code> is <termref def="dt-zero-length"/> 
                then <code>$offset</code> is returned.</p>

            <p>The value of <code>$offset</code>
                <rfc2119>must</rfc2119> be a non-negative integer.</p>
            <p>The <code>$offset</code> is zero based.</p>
            <p>The returned location is zero based.</p>
            
        </fos:rules>
        <fos:equivalent style="xpath-expression" covers-error-cases="false">
($offset to (bin:length($value) - bin:length($search)))
  [bin:part($value, 0, bin:length($search)) eq $search][1] 
        </fos:equivalent>
        <fos:errors>
            <p><errorref spec="BIN40" code="index-out-of-range"/> is raised if <code>$offset</code> is
                negative or <code>$offset</code> is larger than the size of the binary data of
                <code>$value</code>.</p>
        </fos:errors>
        <fos:notes>
            <p>Finding all the matches can be accomplished with simple recursive application:</p>
            <eg xml:space="preserve"><![CDATA[
<xsl:function name="f:find-all" as="xs:integer*">
     <xsl:param name="data" as="xs:base64Binary?"/>
     <xsl:param name="offset" as="xs:integer"/>
     <xsl:param name="pattern" as="xs:base64Binary"/>
     <xsl:sequence
         select="if (bin:length($pattern) eq 0) 
                 then ()
                 else let $found := bin:find($data,$offset,$pattern) 
                      return if ($found) 
                             then ($found,
                                   if ($found + 1 lt bin:length($data)) 
                                   then f:find-all($data, $found + 1, $pattern) 
                                   else ())
                             else ()"/>
</xsl:function>]]></eg>
        </fos:notes>
        <fos:examples>
            <fos:example>
                <fos:test>
                    <fos:expression>bin:find((bin:hex('AABBCCDD'), 0, bin:hex('DD'))</fos:expression>
                    <fos:result>3</fos:result>
                </fos:test>
                <fos:test>
                    <fos:expression>bin:find((bin:hex('AABBCCDD'), 0, bin:hex('FF'))</fos:expression>
                    <fos:result>()</fos:result>
                </fos:test>
                <fos:test>
                    <fos:expression>bin:find((bin:hex('AABBCCDDBBCC'), 2, bin:hex('BBCC'))</fos:expression>
                    <fos:result>4</fos:result>
                </fos:test>
                <fos:test>
                    <fos:expression>bin:find((bin:hex('AABBCCDD'), 2, bin:hex(''))</fos:expression>
                    <fos:result>2</fos:result>
                </fos:test>
            </fos:example>
        </fos:examples>
    </fos:function>
    
    <fos:function name="infer-encoding" prefix="bin">
        <fos:signatures>
            <fos:proto name="infer-encoding" return-type="record(encoding as xs:string, offset as xs:integer)">
                <fos:arg name="value" type="(xs:hexBinary | xs:base64Binary)"/>
                <fos:arg name="encoding" type="xs:string?" default="()"/>
            </fos:proto>
        </fos:signatures>
        <fos:properties>
            <fos:property>deterministic</fos:property>
            <fos:property>context-independent</fos:property>
            <fos:property>focus-independent</fos:property>
        </fos:properties>
        <fos:summary>
            <p>Examines a binary value that encodes a string, to determine the encoding and the start offset of the content.</p>
        </fos:summary>
        <fos:rules>
            <p>The value for the encoding candidate <var>E</var> is
                <code>fn:upper-case($encoding)</code>, or an empty sequence if no encoding
                is supplied.</p>

            <p>The effective encoding is determined as follows:</p>
            <olist>
              <item><p><code>UTF-8</code> if <code>E</code> is
                 <code>UTF-8</code> or absent, and if the initial octets are <code>xEF</code>,
                 <code>xBB</code> and <code>xBF</code>; otherwise,</p></item>
              <item><p><code>UTF-16LE</code> if <var>E</var> is
                 <code>UTF-16</code>, <code>UTF-16LE</code> or absent, and if the initial octets are
                 <code>xFF</code> and <code>xFE</code>; otherwise,</p></item>
              <item><p><code>UTF-16BE</code> if <var>E</var> is
                 <code>UTF-16</code>, <code>UTF-16BE</code> or absent, and if the initial octets are
                 <code>xFE</code> and <code>xFF</code>; otherwise,</p></item>
              <item><p><code>UTF-16BE</code> if <var>E</var> is
                 <code>UTF-16</code>; otherwise,</p></item>
              <item><p>the original value of <code>$encoding</code> if <var>E</var> is present;
                 otherwise,</p></item>
              <item><p><code>UTF-8</code>, or a value that results from
                 implementation-defined heuristics.</p></item>
            </olist>

            <p>The effective start position is zero, unless the initial octets represent a
                byte order mark that has been evaluated by the above rules, in which case the
                effective start position is the zero-based offset (counting in octets) at which
                the byte order mark ends.</p>

            <p>The function returns a record with two fields:</p>
            <ulist>
                <item><p><code>encoding</code> contains the effective encoding.</p></item>
                <item><p><code>offset</code> contains the effective start position.</p></item>
            </ulist>
        </fos:rules>
        <fos:errors>
            <p><errorref spec="BIN40" code="unknown-encoding"/> is raised if <code>$encoding</code> is
                invalid or not supported by the implementation.</p>
        </fos:errors>
        <fos:notes>
            <p>The function is designed to be used in conjunction with <function>bin:decode-string</function>.
            Having established an encoding and a start offset, these can be used as arguments to the
            <function>bin:decode-string</function> function to decode the data.</p>
            <p>Unlike functions such as <function>fn:unparsed-text</function>, this function does
            not have access to external data such as HTTP headers that might assist in establishing the encoding.</p>
        </fos:notes>
            
        <fos:examples>
            <fos:example>
                <fos:test>
                    <fos:expression>bin:infer-encoding(bin:hex('41 42 43'))</fos:expression>
                    <fos:result>{ "encoding": "UTF-8", "offset": 0 }</fos:result>
                </fos:test>
                <fos:test>
                    <fos:expression>bin:infer-encoding(bin:hex('EFBBBF 41 42 43'))</fos:expression>
                    <fos:result>{ "encoding": "UTF-8", "offset": 3 }</fos:result>
                </fos:test>
                <fos:test>
                    <fos:expression>bin:infer-encoding(bin:hex('FEFF 0041 0042 0043'))</fos:expression>
                    <fos:result>{ "encoding": "UTF-16BE", "offset": 2 }</fos:result>
                </fos:test>
                <fos:test>
                    <fos:expression>bin:infer-encoding(bin:hex('0041 0042 0043'), "UTF-16BE")</fos:expression>
                    <fos:result>{ "encoding": "UTF-16BE", "offset": 0 }</fos:result>
                </fos:test>
                <fos:test>
                    <fos:expression>bin:infer-encoding(bin:hex('FFFE 4100 4200 4300'))</fos:expression>
                    <fos:result>{ "encoding": "UTF-16LE", "offset": 2 }</fos:result>
                </fos:test>
                <fos:test>
                    <fos:expression>bin:infer-encoding(bin:hex('FFFE 4100 4200 4300'), 'utf-16')</fos:expression>
                    <fos:result>{ "encoding": "UTF-16LE", "offset": 2 }</fos:result>
                </fos:test>
                <fos:test>
                    <fos:expression><eg>let $input := bin:hex('FFFE 4100 4200 4300')
let ${$encoding, $offset} := bin:infer-encoding($input)
return bin:decode-string($input, $encoding, $offset)</eg></fos:expression>
                    <fos:result>"ABC"</fos:result>
                </fos:test>
                
            </fos:example>

        </fos:examples>
        <fos:changes>
            <fos:change issue="2278" date="2025-11-12">
                <p>New in 4.0</p>
            </fos:change>
        </fos:changes>
    </fos:function>

    <fos:function name="decode-string" prefix="bin">
        <fos:signatures>
            <fos:proto name="decode-string" return-type="xs:string?">
                <fos:arg name="value" type="(xs:hexBinary | xs:base64Binary)?"/>
                <fos:arg name="encoding" type="xs:string?" default="()"/>
                <fos:arg name="offset" type="xs:integer?" default="()"/>
                <fos:arg name="size" type="xs:integer?" default="()"/>
            </fos:proto>
        </fos:signatures>
        <fos:properties>
            <fos:property>deterministic</fos:property>
            <fos:property>context-independent</fos:property>
            <fos:property>focus-independent</fos:property>
        </fos:properties>
        <fos:summary>
            <p>Decodes a binary value as a string.</p>
        </fos:summary>
        <fos:rules>
            <p>If the value of <code>$value</code> is the empty sequence, the function returns an
                empty sequence.</p>
            <p>If <code>$offset</code> or <code>$size</code> is non-empty, the effective value is
               computed by invoking <code>bin:part($value, $offset otherwise 0, $size)</code>.
               Otherwise, it is <code>$value</code>.</p>

            <p>The <code>$encoding</code> argument, if present, follows the same rules as for the
               <code>encoding</code> attribute in an XML declaration. The values which an
               implementation is <rfc2119>required</rfc2119> to recognize are <code>UTF-8</code>,
               <code>UTF-16</code>, <code>UTF-16LE</code>, and <code>UTF-16BE</code>.</p>

            <p>The effective encoding and start position is determined by invoking
               <function>bin:infer-encoding</function> with the effective value and
               <code>$encoding</code>.</p>
            <p>The result of the function is a string representation of the effective value,
               starting at the effective offset, and decoded according to the effective encoding.</p>
        </fos:rules>
        <fos:errors>
            <p><errorref spec="BIN40" code="index-out-of-range"/> is raised if <code>$offset</code> is
                negative or <code>$offset + $size</code> is larger than the size of the binary data
                of <code>$value</code>.</p>
            <p><errorref spec="BIN40" code="invalid-encoding"/> is raised if <code>$encoding</code> is
                invalid for the given input.</p>
            <p><errorref spec="BIN40" code="negative-size"/> is raised if <code>$size</code> is
                negative.</p>
            <p><errorref spec="BIN40" code="unknown-encoding"/> is raised if <code>$encoding</code> is
                invalid or not supported by the implementation.</p>
            <p><errorref spec="BIN40" code="conversion-error"/> is raised if there is an error or
                malformed input during decoding the string. Additional information about the error
                may be passed through suitable error reporting mechanisms – this is
                implementation-dependent.</p>
        </fos:errors>
        <fos:examples>
            <fos:example>
                <fos:test>
                    <fos:expression>bin:decode-string(bin:hex('41 42 43'))</fos:expression>
                    <fos:result>"ABC"</fos:result>
                    <fos:postamble>Whitespace in this and the following examples has been added
                        for clarity.</fos:postamble>
                </fos:test>
                <fos:test>
                    <fos:expression>bin:decode-string(bin:hex('EFBBBF 41 42 43'))</fos:expression>
                    <fos:result>"ABC"</fos:result>
                </fos:test>
                <fos:test>
                    <fos:expression>bin:decode-string(bin:hex('FFFE 4100 4200 4300'))</fos:expression>
                    <fos:result>"ABC"</fos:result>
                    <fos:postamble>Little-endian byte order is used because of the BOM at the start
                    of the data.</fos:postamble>
                </fos:test>
                <fos:test>
                    <fos:expression>bin:decode-string(bin:hex('41 42 43'), offset := 1)</fos:expression>
                    <fos:result>"BC"</fos:result>
                </fos:test>
                <fos:test>
                    <fos:expression>bin:decode-string(bin:hex('41 42 43'), offset := 1, size := 1)</fos:expression>
                    <fos:result>"B"</fos:result>
                </fos:test>
                <fos:test>
                    <fos:expression>bin:decode-string(bin:hex('41 42 43 44'), 'UTF-8', 3)</fos:expression>
                    <fos:result>"D"</fos:result>
                </fos:test>
                <fos:test>
                    <fos:expression>bin:decode-string(bin:hex('EFBBBF 41 42 43 44'), (), 3)</fos:expression>
                    <fos:result>"ABCD"</fos:result>
                </fos:test>
            </fos:example>
            <fos:example>
                <p>The following tests whether the binary value <code>$data</code> starts
                with four octets that decode to the string <code>"%PDF"</code>
                (which always appears at the start of a PDF file).</p>
                <eg xml:space="preserve">bin:decode-string($data, size := 4) eq '%PDF'</eg>
            </fos:example>
        </fos:examples>
        <fos:changes>
            <fos:change issue="2217" PR="2222" date="2025-12-01">
                <p>The revised encoding rules take byte order marks into account.</p>
            </fos:change>
        </fos:changes>
    </fos:function>

    <fos:function name="encode-string" prefix="bin">
        <fos:signatures>
            <fos:proto name="encode-string" return-type="xs:base64Binary?">
                <fos:arg name="value" type="xs:string?"/>
                <fos:arg name="encoding" type="xs:string?" default="'UTF-8'"/>
            </fos:proto>
        </fos:signatures>
        <fos:properties>
            <fos:property>deterministic</fos:property>
            <fos:property>context-independent</fos:property>
            <fos:property>focus-independent</fos:property>
        </fos:properties>
        <fos:summary>
            <p>Encodes a string into a binary value using a given encoding.</p>
        </fos:summary>
        <fos:rules>
            <p>If the value of <code>$value</code> is the empty sequence, the function returns an empty
                sequence.</p>
            <p>The <code>$encoding</code> argument is the name of an encoding. The values for 
                <code>$encoding</code> follow the same rules as for the 
                <code>encoding</code> attribute in an XML
                declaration. The only values which every implementation is
                    <rfc2119>required</rfc2119> to recognize are <code>UTF-8</code>,
                <code>UTF-16</code>, <code>UTF-16BE</code>, and <code>UTF-16LE</code>.
                The encoding <code>UTF-16</code> is interpreted as <code>UTF-16BE</code> (that is,
                most significant byte first).
            </p>
            <p>The function returns the binary value obtained by encoding the string <code>$value</code> using
                the specified <code>$encoding</code> name.</p>
            <p>If <code>$encoding</code> is omitted, <code>UTF-8</code> encoding is assumed.</p>
            <p>The function does not add a byte order mark to the data. 
                But if <code>$value</code> includes a byte order mark (<char>U+FEFF</char>) then it is encoded in the same
            way as any other character.</p>
            
        </fos:rules>
        <fos:errors>
            <p><errorref spec="BIN40" code="unknown-encoding"/> is raised if <code>$encoding</code> is
                invalid or not supported by the implementation.</p>
            <p><errorref spec="BIN40" code="conversion-error"/>is raised if there is an error or
                malformed input during encoding the string. Additional information about the error
                may be passed through suitable error reporting mechanisms – this is
                implementation-dependent.</p>
        </fos:errors>
        <fos:examples>
            <fos:example>
                <fos:test>
                    <fos:expression>bin:encode-string('ABC')</fos:expression>
                    <fos:result>bin:hex('414243')</fos:result>
                </fos:test>
                <fos:test>
                    <fos:expression>bin:encode-string('ABC', 'UTF-16')</fos:expression>
                    <fos:result>bin:hex('004100420043')</fos:result>
                    <fos:postamble>The result has no BOM, and uses big-endian encoding.</fos:postamble>
                </fos:test>
                <fos:test>
                    <fos:expression>bin:encode-string(char(0xfeff) || 'ABC', 'UTF-16LE')</fos:expression>
                    <fos:result>bin:hex('fffe410042004300')</fos:result>
                    <fos:postamble>The result has a BOM, and uses little-endian encoding.</fos:postamble>
                </fos:test>
            </fos:example>
        </fos:examples>
        <fos:changes>
            <fos:change issue="1751" PR="1765" date="2025-02-11"><p>The handling of byte order marks has been clarified. This may
            differ from the interpretation adopted by existing implementations.</p></fos:change>
        </fos:changes>
    </fos:function>

    <fos:function name="pack-integer" prefix="bin">
        <fos:signatures>
            <fos:proto name="pack-integer" return-type="xs:base64Binary">
                <fos:arg name="value" type="xs:integer"/>
                <fos:arg name="size" type="xs:integer"/>
                <fos:arg name="order" type="enum('least-significant-first', 'little-endian', 'LE',
                    'most-significant-first', 'big-endian', 'BE')?" default="'most-significant-first'"/>
            </fos:proto>
        </fos:signatures>
        <fos:properties>
            <fos:property>deterministic</fos:property>
            <fos:property>context-independent</fos:property>
            <fos:property>focus-independent</fos:property>
        </fos:properties>
        <fos:summary>
            <p>Returns the <emph>twos-complement</emph> binary representation of an integer value
                as a binary value of a given size.</p>
        </fos:summary>
        <fos:rules>
            <p>The function produces a binary value containing the twos-complement
            representation of <code>$value mod math:pow(256, $size)</code>, padded on the
            left to <code>$size</code> octets with zero bits if the value is positive,
            or one bits if it is negative.</p>
            <p>The order of octets in the result is most-significant-first unless
                <code>$order</code> specifies otherwise.
            Acceptable values for <code>$order</code> are described in <specref ref="endianness"/>.
            If least-significant-first ordering is requested then the order of octets
            in the result is reversed.</p>
            <p>Specifying a <code>$size</code> of zero yields a <termref def="dt-zero-length"/>
                binary value.</p>
        </fos:rules>
        <fos:errors>
            <p><errorref spec="BIN40" code="negative-size"/> is raised if <code>$size</code> is
                negative.</p>
        </fos:errors>
        <fos:notes>
            <p>If the integer being packed has a maximum precision of <code>$size</code> octets,
                then signed/unsigned versions are not necessary. If the data is considered unsigned,
                then the most significant bit of the bottom <code>$size</code> octets has a normal
                positive (<code>2^(8 *$size - 1)</code>) meaning. If it is considered to be a signed
                value, then the MSB and all the higher order, discarded bits will be '1' for a
                negative value and '0' for a positive or zero. If this function were to check the
                sizing of the supplied integer against the packing size, then any values of MSB
                and the discarded higher order bits other than 'all 1' or 'all 0' would constitute
                an error. <emph>This function does not perform such checking.</emph></p>
            <p>Least-significant-first byte ordering simply reverses the octets in the result.</p>
        </fos:notes>
        <fos:examples>
            <fos:example>
                <fos:test>
                    <fos:expression>bin:pack-integer(256, 2)</fos:expression>
                    <fos:result>bin:hex('0100')</fos:result>
                </fos:test>
                <fos:test>
                    <fos:expression>bin:pack-integer(256, 4)</fos:expression>
                    <fos:result>bin:hex('00000100')</fos:result>
                </fos:test>
                <fos:test>
                    <fos:expression>bin:pack-integer(65536, 2)</fos:expression>
                    <fos:result>bin:hex('0000')</fos:result>
                </fos:test>
                <fos:test>
                    <fos:expression>bin:pack-integer(256, 2, "LE")</fos:expression>
                    <fos:result>bin:hex('0001')</fos:result>
                </fos:test>
                <fos:test>
                    <fos:expression>bin:pack-integer(-1, 2)</fos:expression>
                    <fos:result>bin:hex('FFFF')</fos:result>
                </fos:test>
                <fos:test>
                    <fos:expression>bin:pack-integer(-2, 4)</fos:expression>
                    <fos:result>bin:hex('FFFFFFFE')</fos:result>
                </fos:test>
                <fos:test>
                    <fos:expression>bin:pack-integer(-2, 4, 'LE')</fos:expression>
                    <fos:result>bin:hex('FEFFFFFF')</fos:result>
                </fos:test>
            </fos:example>
        </fos:examples>
    </fos:function>
    
    <fos:function name="unpack-integer" prefix="bin">
        <fos:signatures>
            <fos:proto name="unpack-integer" return-type="xs:integer">
                <fos:arg name="value" type="(xs:hexBinary | xs:base64Binary)"/>
                <fos:arg name="offset" type="xs:integer"/>
                <fos:arg name="size" type="xs:integer"/>
                <fos:arg name="order" type="enum('least-significant-first', 'little-endian', 'LE',
                    'most-significant-first', 'big-endian', 'BE')?" default="'most-significant-first'"/>
            </fos:proto>
        </fos:signatures>
        <fos:properties>
            <fos:property>deterministic</fos:property>
            <fos:property>context-independent</fos:property>
            <fos:property>focus-independent</fos:property>
        </fos:properties>
        <fos:summary>
            <p>Returns a signed integer value represented by the <code>$size</code> octets starting
                from <code>$offset</code> in the input binary value.</p>
        </fos:summary>
        <fos:rules>
            <p>The function produces an integer represented by the binary value
                <code>bin:part($value, $offset, $size)</code>. This is interpreted
            as a twos-complement representation of a signed integer, with the most significant
            octet first unless the <code>$order</code> option specifies otherwise.</p>
            <p>Acceptable values for <code>$order</code> are described in <specref ref="endianness"/>.
            If least-significant-first ordering is requested then the order of octets
            in the input is reversed.</p>
            <p>The values of <code>$offset</code> and <code>$size</code>
                <rfc2119>must</rfc2119> be non-negative integers.</p>
            <p><code>$offset</code> is zero based.</p>
            <p>Specifying a <code>$size</code> of zero yields the integer <code>0</code>.</p>
        </fos:rules>
        <fos:errors>
            <p><errorref spec="BIN40" code="index-out-of-range"/> is raised if <code>$offset</code> is
                negative or <code>$offset + $size</code> is larger than the size of the binary data
                of <code>$value</code>.</p>
            <p><errorref spec="BIN40" code="negative-size"/> is raised if <code>$size</code> is
                negative.</p>
            <p><errorref spec="BIN40" code="integer-too-large"/> is raised if <code>$size</code> is
                too large for the implementation-defined maximum integer size.</p>
        </fos:errors>
        <fos:notes>
            <p>For discussion on integer range see <specref ref="integer"/>.</p>
        </fos:notes>
        <fos:examples>
            <fos:example>
                <fos:test>
                    <fos:expression>bin:unpack-integer(bin:hex('0100'), 0, 2)</fos:expression>
                    <fos:result>256</fos:result>
                </fos:test>
                <fos:test>
                    <fos:expression>bin:unpack-integer(bin:hex('00000100'), 0, 4)</fos:expression>
                    <fos:result>256</fos:result>
                </fos:test>
                <fos:test>
                    <fos:expression>bin:unpack-integer(bin:hex('FFFF'), 0, 2)</fos:expression>
                    <fos:result>-1</fos:result>
                </fos:test>
                <fos:test>
                    <fos:expression>bin:unpack-integer(bin:hex('00FFFFFFFF'), 1, 4)</fos:expression>
                    <fos:result>-1</fos:result>
                </fos:test>
                <fos:test>
                    <fos:expression>bin:unpack-integer(bin:hex('FEFF'), 0, 2, "LE")</fos:expression>
                    <fos:result>-2</fos:result>
                </fos:test>
            </fos:example>
        </fos:examples>
    </fos:function>

    <fos:function name="unpack-unsigned-integer" prefix="bin">
        <fos:signatures>
            <fos:proto name="unpack-unsigned-integer" return-type="xs:integer">
                <fos:arg name="value" type="(xs:hexBinary | xs:base64Binary)"/>
                <fos:arg name="offset" type="xs:integer"/>
                <fos:arg name="size" type="xs:integer"/>
                <fos:arg name="order" type="enum('least-significant-first', 'little-endian', 'LE',
                    'most-significant-first', 'big-endian', 'BE')?" default="'most-significant-first'"/>
            </fos:proto>
        </fos:signatures>
        <fos:properties>
            <fos:property>deterministic</fos:property>
            <fos:property>context-independent</fos:property>
            <fos:property>focus-independent</fos:property>
        </fos:properties>
        <fos:summary>
            <p>Returns an unsigned integer value represented by the <code>$size</code> octets
                starting from <code>$offset</code> in the input binary representation.</p>
        </fos:summary>
        <fos:rules>
            <p>The function produces an integer represented by the binary value
                <code>bin:part($value, $offset, $size)</code>. This is interpreted
            as a representation of an unsigned integer, with the most significant
            octet first unless the <code>$order</code> option specifies otherwise.</p>
            <p>Acceptable values for <code>$order</code> are described in <specref ref="endianness"/>.
            If least-significant-first ordering is requested then the order of octets
            in the input is reversed.</p>
            <p>The values of <code>$offset</code> and <code>$size</code>
                <rfc2119>must</rfc2119> be non-negative integers.</p>
            <p><code>$offset</code> is zero based.</p>
            <p>Specifying a <code>$size</code> of zero yields the integer <code>0</code>.</p>
        
        </fos:rules>
        <fos:errors>
            <p><errorref spec="BIN40" code="index-out-of-range"/> is raised if <code>$offset</code> is
                negative or <code>$offset + $size</code> is larger than the size of the binary data
                of <code>$value</code>.</p>
            <p><errorref spec="BIN40" code="negative-size"/> is raised if <code>$size</code> is
                negative.</p>
            <p><errorref spec="BIN40" code="integer-too-large"/> is raised if <code>$size</code> is
                too large for the implementation-defined maximum integer size.</p>
        </fos:errors>
        <fos:notes>
            <p>For discussion on integer range see <specref ref="integer"/>.</p>
        </fos:notes>
        <fos:examples>
           <fos:example>
                <fos:test>
                    <fos:expression>bin:unpack-unsigned-integer(bin:hex('0100'), 0, 2)</fos:expression>
                    <fos:result>256</fos:result>
                </fos:test>
                <fos:test>
                    <fos:expression>bin:unpack-unsigned-integer(bin:hex('00000100'), 0, 4)</fos:expression>
                    <fos:result>256</fos:result>
                </fos:test>
                <fos:test>
                    <fos:expression>bin:unpack-unsigned-integer(bin:hex('FFFF'), 0, 2)</fos:expression>
                    <fos:result>65535</fos:result>
                </fos:test>
                <fos:test>
                    <fos:expression>bin:unpack-unsigned-integer(bin:hex('00FFFFFFFF'), 1, 4)</fos:expression>
                    <fos:result>4294967295</fos:result>
                </fos:test>
                <fos:test>
                    <fos:expression>bin:unpack-integer(bin:hex('FEFF'), 0, 2, "LE")</fos:expression>
                    <fos:result>65279</fos:result>
                </fos:test>
            </fos:example>
        </fos:examples>
    </fos:function>


    <fos:function name="unpack-double" prefix="bin">
        <fos:signatures>
            <fos:proto name="unpack-double" return-type="xs:double">
                <fos:arg name="value" type="(xs:hexBinary | xs:base64Binary)"/>
                <fos:arg name="offset" type="xs:integer"/>
                <fos:arg name="order" type="enum('least-significant-first', 'little-endian', 'LE',
                    'most-significant-first', 'big-endian', 'BE')?" default="'most-significant-first'"/>
            </fos:proto>
        </fos:signatures>
        <fos:properties>
            <fos:property>deterministic</fos:property>
            <fos:property>context-independent</fos:property>
            <fos:property>focus-independent</fos:property>
        </fos:properties>
        <fos:summary>
            <p>Extracts an <code>xs:double</code> value
                held in IEEE format at the given offset in a binary value.</p>
        </fos:summary>
        <fos:rules>
            <p>Extract the <loc href="http://www.w3.org/TR/xmlschema-2/#double">double</loc> value
                stored in the 8 successive octets from the <code>$offset</code> octet of the binary
                data of <code>$value</code>.</p>
            <p>Most-significant-first number representation is assumed unless the
                <code>$order</code> parameter specifies otherwise. Acceptable values for
                <code>$order</code> are described in <specref ref="endianness"/>.</p>
            <p>The value of <code>$offset</code>
                <rfc2119>must</rfc2119> be a non-negative integer.</p>
            <p>The <code>$offset</code> is zero based.</p>
            <p>The binary representation is expected to correspond with that of the IEEE
                double-precision 64-bit floating point type <bibref ref="ieee754"/>. For more
                details see <specref ref="floating"/>.</p>
        </fos:rules>
        <fos:errors>
            <p><errorref spec="BIN40" code="index-out-of-range"/> is raised if <code>$offset</code> is
                negative or <code>$offset + 8</code> (octet-length of <code>xs:double</code>) is
                larger than the size of the binary data of <code>$value</code>.</p>

        </fos:errors>
    </fos:function>
    
    <fos:function name="unpack-float" prefix="bin">
        <fos:signatures>
            <fos:proto name="unpack-float" return-type="xs:float">
                <fos:arg name="value" type="(xs:hexBinary | xs:base64Binary)"/>
                <fos:arg name="offset" type="xs:integer"/>
                <fos:arg name="order" type="enum('least-significant-first', 'little-endian', 'LE',
                    'most-significant-first', 'big-endian', 'BE')?" default="'most-significant-first'"/>
            </fos:proto>
        </fos:signatures>
        <fos:properties>
            <fos:property>deterministic</fos:property>
            <fos:property>context-independent</fos:property>
            <fos:property>focus-independent</fos:property>
        </fos:properties>
        <fos:summary>
            <p>Extract <loc href="http://www.w3.org/TR/xmlschema-2/#float">float</loc> value stored
                at the particular offset in binary data.</p>
        </fos:summary>
        <fos:rules>
            <p>Extract the <loc href="http://www.w3.org/TR/xmlschema-2/#float">float</loc> value
                stored in the 4 successive octets from the <code>$offset</code> octet of the binary
                data of <code>$value</code>.</p>
            <p>Most-significant-octet-first number representation is assumed unless the
                <code>$order</code> parameter specifies otherwise. Acceptable values for
                <code>$order</code> are described in <specref ref="endianness"/>.</p>
            <p>The value of <code>$offset</code>
                <rfc2119>must</rfc2119> be a non-negative integer.</p>
            <p>The <code>$offset</code> is zero based.</p>
            <p>The binary representation is expected to correspond with that of the IEEE
                single-precision 32-bit floating point type <bibref ref="ieee754"/>. For more
                details see <specref ref="floating"/>.</p>
        </fos:rules>
        <fos:errors>
            <p><errorref spec="BIN40" code="index-out-of-range"/> is raised if <code>$offset</code> is
                negative or <code>$offset + 4</code> (octet-length of <code>xs:float</code>) is
                larger than the size of the binary data of <code>$value</code>.</p>
 
        </fos:errors>
    </fos:function>

    <fos:function name="pack-double" prefix="bin">
        <fos:signatures>
            <fos:proto name="pack-double" return-type="xs:base64Binary">
                <fos:arg name="value" type="xs:double"/>
                <fos:arg name="order" type="enum('least-significant-first', 'little-endian', 'LE',
                    'most-significant-first', 'big-endian', 'BE')?" default="'most-significant-first'"/>
            </fos:proto>
        </fos:signatures>
        <fos:properties>
            <fos:property>deterministic</fos:property>
            <fos:property>context-independent</fos:property>
            <fos:property>focus-independent</fos:property>
        </fos:properties>
        <fos:summary>
            <p>Returns the 8-octet binary representation of an <code>xs:double</code> value.</p>
        </fos:summary>
        <fos:rules>
            <p>Most-significant-octet-first number representation is assumed unless the
                <code>$order</code> parameter specifies otherwise. Acceptable values for
                <code>$order</code> are described in <specref ref="endianness"/>.</p>
            <p>The binary representation will correspond with that of the IEEE double-precision
                64-bit floating point type <bibref ref="ieee754"/>. For more details see <specref
                    ref="floating"/>.</p>
        </fos:rules>
 
    </fos:function>

    <fos:function name="pack-float" prefix="bin">
        <fos:signatures>
            <fos:proto name="pack-float" return-type="xs:base64Binary">
                <fos:arg name="value" type="xs:float"/>
                <fos:arg name="order" type="xs:enum('least-significant-first', 'little-endian', 'LE',
                    'most-significant-first', 'big-endian', 'BE')?" default="'most-significant-first'"/>
            </fos:proto>
        </fos:signatures>
        <fos:properties>
            <fos:property>deterministic</fos:property>
            <fos:property>context-independent</fos:property>
            <fos:property>focus-independent</fos:property>
        </fos:properties>
        <fos:summary>
            <p>Returns the 4-octet binary representation of a <loc
                    href="http://www.w3.org/TR/xmlschema-2/#float">float</loc> value.</p>
        </fos:summary>
        <fos:rules>
            <p>Most-significant-octet-first number representation is assumed unless the
                <code>$order</code> parameter is specified. Acceptable values for
                <code>$order</code> are described in <specref ref="endianness"/>.</p>
            <p>The binary representation will correspond with that of the IEEE single-precision
                32-bit floating point type <bibref ref="ieee754"/>. For more details see <specref
                    ref="floating"/>.</p>
        </fos:rules>
    </fos:function>


    <fos:function name="or" prefix="bin">
        <fos:signatures>
            <fos:proto name="or" return-type="xs:base64Binary?">
                <fos:arg name="value1" type="(xs:hexBinary | xs:base64Binary)?"/>
                <fos:arg name="value2" type="(xs:hexBinary | xs:base64Binary)?"/>
            </fos:proto>
        </fos:signatures>
        <fos:properties>
            <fos:property>deterministic</fos:property>
            <fos:property>context-independent</fos:property>
            <fos:property>focus-independent</fos:property>
        </fos:properties>
        <fos:summary>
            <p>Returns the bitwise OR of two binary values.</p>
        </fos:summary>
        <fos:rules>
            <p>If either argument is the empty sequence, an empty sequence is returned.</p>
            <p>Otherwise, <code>$value1</code> and <code>$value2</code> must have the same length.</p>
            <p>The function converts <code>$value1</code> and <code>$value2</code> to sequences
            of bits <var>A</var> and <var>B</var>, and returns a binary value in which 
                the <var>N</var>th bit is set to 1 if either or both of the <var>N</var>th bit of <var>A</var>
            and the <var>N</var>th bit of <var>B</var> are 1, and is set to 0 otherwise.</p>
            
        </fos:rules>
        <fos:equivalent style="xpath-expression" covers-error-cases="false">
let $octet-chars := fn($x) {
  bin:to-octets($x) 
  =!> format-integer('2^xxxxxxxx') 
  =>  string-join()
  =>  characters()
}
let $A := $octet-chars($value1)
let $B := $octet-chars($value2)
let $R := for-each-pair($A, $B, fn($p, $q) {
  if ($p eq '1' or $q eq '1') then '1' else '0'
})
return bin:bin(string-join($R))
        </fos:equivalent>
        <fos:errors>
            <p><errorref spec="BIN40" code="differing-length-arguments"/> is raised if the input
                arguments are of differing length.</p>
        </fos:errors>
    </fos:function>
    
    <fos:function name="xor" prefix="bin">
        <fos:signatures>
            <fos:proto name="xor" return-type="xs:base64Binary?">
                <fos:arg name="value1" type="(xs:hexBinary | xs:base64Binary)?"/>
                <fos:arg name="value2" type="(xs:hexBinary | xs:base64Binary)?"/>
            </fos:proto>
        </fos:signatures>
        <fos:properties>
            <fos:property>deterministic</fos:property>
            <fos:property>context-independent</fos:property>
            <fos:property>focus-independent</fos:property>
        </fos:properties>
        <fos:summary>
            <p>Returns the bitwise exclusive-OR of two binary arguments.</p>
        </fos:summary>
        <fos:rules>
            <p>If either argument is the empty sequence, an empty sequence is returned.</p>
            <p>Otherwise, <code>$value1</code> and <code>$value2</code> must have the same length.</p>
            <p>The function converts <code>$value1</code> and <code>$value2</code> to sequences
            of bits <var>A</var> and <var>B</var>, and returns a binary value in which 
                the <var>N</var>th bit is set to 1 if the <var>N</var>th bit of <var>A</var>
            differs from the <var>N</var>th bit of <var>B</var>, and is set to 0 if they are
                the same.</p>
            
        </fos:rules>
        <fos:equivalent style="xpath-expression" covers-error-cases="false">
let $octet-chars := fn($x) {
  bin:to-octets($x) 
  =!> format-integer('2^xxxxxxxx') 
  =>  string-join()
  =>  characters()
}
let $A := $octet-chars($value1)
let $B := $octet-chars($value2)
let $R := for-each-pair($A, $B, fn($p, $q) {
  if ($p ne $q) then '1' else '0'
})
return bin:bin(string-join($R))
        </fos:equivalent>
        <fos:errors>
            <p><errorref spec="BIN40" code="differing-length-arguments"/> is raised if the input
                arguments are of differing length.</p>
        </fos:errors>
    </fos:function>
    
    <fos:function name="and" prefix="bin">
        <fos:signatures>
            <fos:proto name="and" return-type="xs:base64Binary?">
                <fos:arg name="value1" type="(xs:hexBinary | xs:base64Binary)?"/>
                <fos:arg name="value2" type="(xs:hexBinary | xs:base64Binary)?"/>
            </fos:proto>
        </fos:signatures>
        <fos:properties>
            <fos:property>deterministic</fos:property>
            <fos:property>context-independent</fos:property>
            <fos:property>focus-independent</fos:property>
        </fos:properties>
        <fos:summary>
            <p>Returns the bitwise AND of two binary arguments.</p>
        </fos:summary>
        <fos:rules>
            <p>If either argument is the empty sequence, an empty sequence is returned.</p>
            <p>Otherwise, <code>$value1</code> and <code>$value2</code> must have the same length.</p>
            <p>The function converts <code>$value1</code> and <code>$value2</code> to sequences
            of bits <var>A</var> and <var>B</var>, and returns a binary value in which 
                the <var>N</var>th bit is set to 1 if both the <var>N</var>th bit of <var>A</var>
            and the <var>N</var>th bit of <var>B</var> are 1, and is set to 0 otherwise.</p>
            
        </fos:rules>
        <fos:equivalent style="xpath-expression" covers-error-cases="false">
let $octet-chars := fn($x) {
  bin:to-octets($x) 
  =!> format-integer('2^xxxxxxxx') 
  =>  string-join()
  =>  characters()
}
let $A := $octet-chars($value1)
let $B := $octet-chars($value2)
let $R := for-each-pair($A, $B, fn($p, $q) {
  if ($p eq '1' and $q eq '1') then '1' else '0'
})
return bin:bin(string-join($R))
        </fos:equivalent>
        <fos:errors>
            <p><errorref spec="BIN40" code="differing-length-arguments"/> is raised if the input
                arguments are of differing length.</p>
        </fos:errors>
    </fos:function>
    
    <fos:function name="not" prefix="bin">
        <fos:signatures>
            <fos:proto name="not" return-type="xs:base64Binary?">
                <fos:arg name="value" type="(xs:hexBinary | xs:base64Binary)?"/>
            </fos:proto>
        </fos:signatures>
        <fos:properties>
            <fos:property>deterministic</fos:property>
            <fos:property>context-independent</fos:property>
            <fos:property>focus-independent</fos:property>
        </fos:properties>
        <fos:summary>
            <p>Returns the "bitwise not" of a binary argument.</p>
        </fos:summary>
        <fos:rules>
            <p>Returns "bitwise not" applied to <code>$value</code>.</p>
            <p>If the argument is the empty sequence, an empty sequence is returned.</p>
        </fos:rules>
        <fos:equivalent style="xpath-expression" covers-error-cases="false">
let $octet-chars := fn($x) {
  bin:to-octets($x) 
  =!> format-integer('2^xxxxxxxx') 
  =>  string-join()
}
return (
  $octet-chars($value)
  => translate('01', '10')
  => bin:bin()
)
        </fos:equivalent>
    </fos:function>

    <fos:function name="shift" prefix="bin">
        <fos:signatures>
            <fos:proto name="shift" return-type="xs:base64Binary?">
                <fos:arg name="value" type="(xs:hexBinary | xs:base64Binary)?"/>
                <fos:arg name="by" type="xs:integer"/>
            </fos:proto>
        </fos:signatures>
        <fos:properties>
            <fos:property>deterministic</fos:property>
            <fos:property>context-independent</fos:property>
            <fos:property>focus-independent</fos:property>
        </fos:properties>
        <fos:summary>
            <p>Shift the bits of a binary value left or right.</p>
        </fos:summary>
        <fos:rules>
            <p>If the value of <code>$value</code> is the empty sequence, the function returns an empty
                sequence.</p> 
            <p>In other cases the length of the result is always the same as the
                length of <code>$value</code>.</p>
            <p>If <code>$by</code> is positive then bits are shifted <code>$by</code> times to the
                left. The first <code>$by</code> bits are discarded, and <code>$by</code>
                zero bits are injected at the end.</p>
            <p>If <code>$by</code> is negative then bits are shifted <code>-$by</code> times to the
                right. The last <code>-$by</code> bits are discarded, and <code>-$by</code>
                zero bits are injected at the start.</p>           
            <p>If <code>$by</code> is zero, the result is identical to <code>$value</code>.</p>
            <p>If <code>abs($by)</code> is greater than the bit-length of <code>$value</code> then an
                all-zeros result, of the same length as <code>$value</code>, is returned.</p>
            <p><code>abs($by)</code> can be greater than 8, implying multi-byte shifts.</p>
            
        </fos:rules>
        <fos:equivalent style="xpath-expression" covers-error-cases="false">
let $string := (
  bin:to-octets($value) 
  =!> format-integer('2^xxxxxxxx') 
  =>  string-join()
)
let $len := string-length($string)
let $shifted := if (abs($by) >= $len) then (
  string-join(replicate('0', $len))
) else if ($by >= 0) then (
  substring($string, $by + 1) || replicate('0', $by)
) else (
  replicate('0', -$by) || substring($string, 1, -$by)
)
return bin:bin($shifted)
        </fos:equivalent>
        <fos:notes>
            <p>Bit shifting across byte boundaries implies “big-endian treatment”, i.e. the leftmost
                (high-order) bit when shifted left becomes the low-order bit of the preceding
                byte.</p>
        </fos:notes>
        <fos:examples>
            <fos:example>
                <fos:test>
                    <fos:expression><eg>bin:shift(bin:hex("000001"), 17)</eg></fos:expression>
                    <fos:result><eg>bin:hex("020000")</eg></fos:result>
                </fos:test>
                <!--<eg xml:space="preserve">bin:shift(bin:hex("000001"), 17) → bin:hex("020000")</eg>-->
            </fos:example>
        </fos:examples>
    </fos:function>    
    

</fos:functions>
