Ejemplo n.º 1
0
        // generates unique and duplicate hashes for bnodes
        /// <exception cref="JsonLD.Core.JsonLdError"></exception>
        public virtual object HashBlankNodes(IEnumerable <string> unnamed_)
        {
#if !PORTABLE
            IList <string> unnamed     = new List <string>(unnamed_);
            IList <string> nextUnnamed = new List <string>();
            IDictionary <string, IList <string> > duplicates = new Dictionary <string, IList <string
                                                                                              > >();
            IDictionary <string, string> unique = new Dictionary <string, string>();
            // NOTE: not using the same structure as javascript here to avoid
            // possible stack overflows
            // hash quads for each unnamed bnode
            for (int hui = 0; ; hui++)
            {
                if (hui == unnamed.Count)
                {
                    // done, name blank nodes
                    bool           named  = false;
                    IList <string> hashes = new List <string>(unique.Keys);
                    hashes.SortInPlace();
                    foreach (string hash in hashes)
                    {
                        string bnode = unique[hash];
                        namer.GetName(bnode);
                        named = true;
                    }
                    // continue to hash bnodes if a bnode was assigned a name
                    if (named)
                    {
                        // this resets the initial variables, so it seems like it
                        // has to go on the stack
                        // but since this is the end of the function either way, it
                        // might not have to
                        // hashBlankNodes(unnamed);
                        hui         = -1;
                        unnamed     = nextUnnamed;
                        nextUnnamed = new List <string>();
                        duplicates  = new Dictionary <string, IList <string> >();
                        unique      = new Dictionary <string, string>();
                        continue;
                    }
                    else
                    {
                        // name the duplicate hash bnods
                        // names duplicate hash bnodes
                        // enumerate duplicate hash groups in sorted order
                        hashes = new List <string>(duplicates.Keys);
                        hashes.SortInPlace();
                        // process each group
                        for (int pgi = 0; ; pgi++)
                        {
                            if (pgi == hashes.Count)
                            {
                                // done, create JSON-LD array
                                // return createArray();
                                IList <string> normalized = new List <string>();
                                // Note: At this point all bnodes in the set of RDF
                                // quads have been
                                // assigned canonical names, which have been stored
                                // in the 'namer' object.
                                // Here each quad is updated by assigning each of
                                // its bnodes its new name
                                // via the 'namer' object
                                // update bnode names in each quad and serialize
                                for (int cai = 0; cai < quads.Count; ++cai)
                                {
                                    RDFDataset.Quad quad = quads[cai];
                                    foreach (string attr in new string[] { "subject", "object", "name" })
                                    {
                                        if (quad.ContainsKey(attr))
                                        {
                                            IDictionary <string, object> qa = (IDictionary <string, object>)quad[attr];
                                            if (qa != null && (string)qa["type"] == "blank node" && ((string)qa["value"]).IndexOf
                                                    ("_:c14n") != 0)
                                            {
                                                qa["value"] = namer.GetName((string)qa["value"]);
                                            }
                                        }
                                    }
                                    normalized.Add(RDFDatasetUtils.ToNQuad(quad, quad.ContainsKey("name"
                                                                                                  ) && !(quad["name"] == null) ? (string)((IDictionary <string, object>)((IDictionary <string, object>)quad)["name"])["value"] : null));
                                }
                                // sort normalized output
                                normalized.SortInPlace();
                                // handle output format
                                if (options.format != null)
                                {
                                    if ("application/nquads".Equals(options.format))
                                    {
                                        string rval = string.Empty;
                                        foreach (string n in normalized)
                                        {
                                            rval += n;
                                        }
                                        return(rval);
                                    }
                                    else
                                    {
                                        throw new JsonLdError(JsonLdError.Error.UnknownFormat, options.format);
                                    }
                                }
                                string rval_1 = string.Empty;
                                foreach (string n_1 in normalized)
                                {
                                    rval_1 += n_1;
                                }
                                return(RDFDatasetUtils.ParseNQuads(rval_1));
                            }
                            // name each group member
                            IList <string> group = duplicates[hashes[pgi]];
                            IList <NormalizeUtils.HashResult> results = new List <NormalizeUtils.HashResult>();
                            for (int n_2 = 0; ; n_2++)
                            {
                                if (n_2 == group.Count)
                                {
                                    // name bnodes in hash order
                                    results.SortInPlace(new _IComparer_145());
                                    foreach (NormalizeUtils.HashResult r in results)
                                    {
                                        // name all bnodes in path namer in
                                        // key-entry order
                                        // Note: key-order is preserved in
                                        // javascript
                                        foreach (string key in r.pathNamer.Existing().GetKeys())
                                        {
                                            namer.GetName(key);
                                        }
                                    }
                                    // processGroup(i+1);
                                    break;
                                }
                                else
                                {
                                    // skip already-named bnodes
                                    string bnode = group[n_2];
                                    if (namer.IsNamed(bnode))
                                    {
                                        continue;
                                    }
                                    // hash bnode paths
                                    UniqueNamer pathNamer = new UniqueNamer("_:b");
                                    pathNamer.GetName(bnode);
                                    NormalizeUtils.HashResult result = HashPaths(bnode, bnodes, namer, pathNamer);
                                    results.Add(result);
                                }
                            }
                        }
                    }
                }
                // hash unnamed bnode
                string bnode_1 = unnamed[hui];
                string hash_1  = HashQuads(bnode_1, bnodes, namer);
                // store hash as unique or a duplicate
                if (duplicates.ContainsKey(hash_1))
                {
                    duplicates[hash_1].Add(bnode_1);
                    nextUnnamed.Add(bnode_1);
                }
                else
                {
                    if (unique.ContainsKey(hash_1))
                    {
                        IList <string> tmp = new List <string>();
                        tmp.Add(unique[hash_1]);
                        tmp.Add(bnode_1);
                        duplicates[hash_1] = tmp;
                        nextUnnamed.Add(unique[hash_1]);
                        nextUnnamed.Add(bnode_1);
                        JsonLD.Collections.Remove(unique, hash_1);
                    }
                    else
                    {
                        unique[hash_1] = bnode_1;
                    }
                }
            }
#else
            throw new PlatformNotSupportedException();
#endif
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Produces a hash for the paths of adjacent bnodes for a bnode,
        /// incorporating all information about its subgraph of bnodes.
        /// </summary>
        /// <remarks>
        /// Produces a hash for the paths of adjacent bnodes for a bnode,
        /// incorporating all information about its subgraph of bnodes. This method
        /// will recursively pick adjacent bnode permutations that produce the
        /// lexicographically-least 'path' serializations.
        /// </remarks>
        /// <param name="id">the ID of the bnode to hash paths for.</param>
        /// <param name="bnodes">the map of bnode quads.</param>
        /// <param name="namer">the canonical bnode namer.</param>
        /// <param name="pathNamer">the namer used to assign names to adjacent bnodes.</param>
        /// <param name="callback">(err, result) called once the operation completes.</param>
        private static NormalizeUtils.HashResult HashPaths(string id, IDictionary <string, IDictionary <string, object> > bnodes, UniqueNamer namer, UniqueNamer pathNamer)
        {
#if !PORTABLE
            MessageDigest md = null;

            try
            {
                // create SHA-1 digest
                md = MessageDigest.GetInstance("SHA-1");
                JObject                 groups = new JObject();
                IList <string>          groupHashes;
                IList <RDFDataset.Quad> quads = (IList <RDFDataset.Quad>)bnodes[id]["quads"];
                for (int hpi = 0; ; hpi++)
                {
                    if (hpi == quads.Count)
                    {
                        // done , hash groups
                        groupHashes = new List <string>(groups.GetKeys());
                        ((List <string>)groupHashes).Sort(StringComparer.CurrentCultureIgnoreCase);
                        for (int hgi = 0; ; hgi++)
                        {
                            if (hgi == groupHashes.Count)
                            {
                                NormalizeUtils.HashResult res = new NormalizeUtils.HashResult();
                                res.hash      = EncodeHex(md.Digest());
                                res.pathNamer = pathNamer;
                                return(res);
                            }
                            // digest group hash
                            string groupHash = groupHashes[hgi];
                            md.Update(JsonLD.JavaCompat.GetBytesForString(groupHash, "UTF-8"));
                            // choose a path and namer from the permutations
                            string      chosenPath  = null;
                            UniqueNamer chosenNamer = null;
                            NormalizeUtils.Permutator permutator = new NormalizeUtils.Permutator((JArray)groups[groupHash]);
                            while (true)
                            {
                                bool        contPermutation = false;
                                bool        breakOut        = false;
                                JArray      permutation     = permutator.Next();
                                UniqueNamer pathNamerCopy   = pathNamer.Clone();
                                // build adjacent path
                                string path    = string.Empty;
                                JArray recurse = new JArray();
                                foreach (string bnode in permutation)
                                {
                                    // use canonical name if available
                                    if (namer.IsNamed(bnode))
                                    {
                                        path += namer.GetName(bnode);
                                    }
                                    else
                                    {
                                        // recurse if bnode isn't named in the path
                                        // yet
                                        if (!pathNamerCopy.IsNamed(bnode))
                                        {
                                            recurse.Add(bnode);
                                        }
                                        path += pathNamerCopy.GetName(bnode);
                                    }
                                    // skip permutation if path is already >= chosen
                                    // path
                                    if (chosenPath != null && path.Length >= chosenPath.Length && string.CompareOrdinal
                                            (path, chosenPath) > 0)
                                    {
                                        // return nextPermutation(true);
                                        if (permutator.HasNext())
                                        {
                                            contPermutation = true;
                                        }
                                        else
                                        {
                                            // digest chosen path and update namer
                                            md.Update(JsonLD.JavaCompat.GetBytesForString(chosenPath, "UTF-8"));
                                            pathNamer = chosenNamer;
                                            // hash the nextGroup
                                            breakOut = true;
                                        }
                                        break;
                                    }
                                }
                                // if we should do the next permutation
                                if (contPermutation)
                                {
                                    continue;
                                }
                                // if we should stop processing this group
                                if (breakOut)
                                {
                                    break;
                                }
                                // does the next recursion
                                for (int nrn = 0; ; nrn++)
                                {
                                    if (nrn == recurse.Count)
                                    {
                                        // return nextPermutation(false);
                                        if (chosenPath == null || string.CompareOrdinal(path, chosenPath) < 0)
                                        {
                                            chosenPath  = path;
                                            chosenNamer = pathNamerCopy;
                                        }
                                        if (!permutator.HasNext())
                                        {
                                            // digest chosen path and update namer
                                            md.Update(JsonLD.JavaCompat.GetBytesForString(chosenPath, "UTF-8"));
                                            pathNamer = chosenNamer;
                                            // hash the nextGroup
                                            breakOut = true;
                                        }
                                        break;
                                    }
                                    // do recursion
                                    string bnode_1 = (string)recurse[nrn];
                                    NormalizeUtils.HashResult result = HashPaths(bnode_1, bnodes, namer, pathNamerCopy);
                                    path         += pathNamerCopy.GetName(bnode_1) + "<" + result.hash + ">";
                                    pathNamerCopy = result.pathNamer;
                                    // skip permutation if path is already >= chosen
                                    // path
                                    if (chosenPath != null && path.Length >= chosenPath.Length && string.CompareOrdinal
                                            (path, chosenPath) > 0)
                                    {
                                        // return nextPermutation(true);
                                        if (!permutator.HasNext())
                                        {
                                            // digest chosen path and update namer
                                            md.Update(JsonLD.JavaCompat.GetBytesForString(chosenPath, "UTF-8"));
                                            pathNamer = chosenNamer;
                                            // hash the nextGroup
                                            breakOut = true;
                                        }
                                        break;
                                    }
                                }
                                // do next recursion
                                // if we should stop processing this group
                                if (breakOut)
                                {
                                    break;
                                }
                            }
                        }
                    }
                    // get adjacent bnode
                    IDictionary <string, object> quad = (IDictionary <string, object>)quads[hpi];
                    string bnode_2 = GetAdjacentBlankNodeName((IDictionary <string, object>)quad["subject"
                                                              ], id);
                    string direction = null;
                    if (bnode_2 != null)
                    {
                        // normal property
                        direction = "p";
                    }
                    else
                    {
                        bnode_2 = GetAdjacentBlankNodeName((IDictionary <string, object>)quad["object"], id
                                                           );
                        if (bnode_2 != null)
                        {
                            // reverse property
                            direction = "r";
                        }
                    }
                    if (bnode_2 != null)
                    {
                        // get bnode name (try canonical, path, then hash)
                        string name;
                        if (namer.IsNamed(bnode_2))
                        {
                            name = namer.GetName(bnode_2);
                        }
                        else
                        {
                            if (pathNamer.IsNamed(bnode_2))
                            {
                                name = pathNamer.GetName(bnode_2);
                            }
                            else
                            {
                                name = HashQuads(bnode_2, bnodes, namer);
                            }
                        }
                        // hash direction, property, end bnode name/hash
                        using (MessageDigest md1 = MessageDigest.GetInstance("SHA-1"))
                        {
                            // String toHash = direction + (String) ((Map<String,
                            // Object>) quad.get("predicate")).get("value") + name;
                            md1.Update(JsonLD.JavaCompat.GetBytesForString(direction, "UTF-8"));
                            md1.Update(JsonLD.JavaCompat.GetBytesForString(((string)((IDictionary <string, object>)quad["predicate"])["value"]), "UTF-8"));
                            md1.Update(JsonLD.JavaCompat.GetBytesForString(name, "UTF-8"));
                            string groupHash = EncodeHex(md1.Digest());
                            if (groups.ContainsKey(groupHash))
                            {
                                ((JArray)groups[groupHash]).Add(bnode_2);
                            }
                            else
                            {
                                JArray tmp = new JArray();
                                tmp.Add(bnode_2);
                                groups[groupHash] = tmp;
                            }
                        }
                    }
                }
            }
            catch
            {
                // TODO: i don't expect that SHA-1 is even NOT going to be
                // available?
                // look into this further
                throw;
            }
            finally
            {
                md?.Dispose();
            }
#else
            throw new PlatformNotSupportedException();
#endif
        }