/// <summary> /// Opens a stream from a store by its key string. /// </summary> /// <param name="key">The key, including store prefix</param> /// <returns>A stream, or null if not found.</returns> public Stream Open(SwiffotronContext ctx, string key) { Uri storeURI = new Uri(key); if (storeURI.Scheme != "store") /* ISSUE 67: Constants, please. */ { throw new SwiffotronException( SwiffotronError.BadInputXML, ctx, @"Store paths should begin with store://"); } string storeId = storeURI.Host; if (!stores.ContainsKey(storeId)) { throw new SwiffotronException( SwiffotronError.BadInputXML, ctx, @"Store '" + storeId + @"' not registered."); } try { return(stores[storeId].OpenInput(storeURI.LocalPath.Substring(1))); } catch (FileNotFoundException fnfe) { throw new SwiffotronException( SwiffotronError.BadPathOrID, ctx.Sentinel("FileNotFoundInStore"), "File not found: " + key, fnfe); } }
/// <summary> /// Retrieves a cached object given its fully qualified cache key of the form /// [cache name]:[cache key] /// </summary> /// <param name="key">Full cache path</param> /// <returns>The cached object, or null.</returns> public object Get(SwiffotronContext ctx, string key) { int pos = key.IndexOf(':'); if (pos < 0) { throw new SwiffotronException( SwiffotronError.BadInputXML, ctx, @"Bad cache key (Requires prefix): " + key); } string cacheId = key.Substring(0, pos); key = key.Substring(pos + 1); if (!caches.ContainsKey(cacheId)) { throw new SwiffotronException( SwiffotronError.BadInputXML, ctx, @"Cache '" + cacheId + @"' not registered."); } return(this.caches[cacheId].Get(key)); }
/// <summary> /// Writes a block of data to the store specified in the fully qualified /// store key of the form [store name]:[store key] /// </summary> /// <param name="key">The store key</param> /// <param name="data">The data to store as a byte array.</param> /// <returns>Null if it was not saved (Saves disabled) or the relative /// store path from the store URL, e.g. "store://mystore/things/thing" returns /// "things/thing"</returns> public string Save(SwiffotronContext ctx, string key, byte[] data) { Uri storeURI = new Uri(key); if (storeURI.Scheme != "store") /* ISSUE 67: Constants, please. */ { throw new SwiffotronException( SwiffotronError.BadInputXML, ctx, @"Store paths should begin with store://"); } string storeId = storeURI.Host; key = storeURI.AbsolutePath.Substring(1); if (!conf.EnableStoreWrites) { /* Give up, but return the key we would have used. Used in debug * tests. */ return(key); } if (!stores.ContainsKey(storeId)) { throw new SwiffotronException( SwiffotronError.BadInputXML, ctx, @"Store '" + storeId + @"' not registered."); } ISwiffotronStore store = stores[storeId]; using (Stream s = store.OpenOutput(key)) { s.Write(data, 0, data.Length); } store.Commit(key); return(key); }
/// <summary> /// Writes a block of data to the store specified in the fully qualified /// store key of the form [store name]:[store key] /// </summary> /// <param name="key">The store key</param> /// <param name="data">The data to store as a byte array.</param> /// <returns>Null if it was not saved (Saves disabled) or the relative /// store path from the store URL, e.g. "store://mystore/things/thing" returns /// "things/thing"</returns> public string Save(SwiffotronContext ctx, string key, byte[] data) { Uri storeURI = new Uri(key); if (storeURI.Scheme != "store") /* ISSUE 67: Constants, please. */ { throw new SwiffotronException( SwiffotronError.BadInputXML, ctx, @"Store paths should begin with store://"); } string storeId = storeURI.Host; key = storeURI.AbsolutePath.Substring(1); if (!conf.EnableStoreWrites) { /* Give up, but return the key we would have used. Used in debug * tests. */ return key; } if (!stores.ContainsKey(storeId)) { throw new SwiffotronException( SwiffotronError.BadInputXML, ctx, @"Store '" + storeId + @"' not registered."); } ISwiffotronStore store = stores[storeId]; using (Stream s = store.OpenOutput(key)) { s.Write(data, 0, data.Length); } store.Commit(key); return key; }
/// <summary> /// Retrieves a cached object given its fully qualified cache key of the form /// [cache name]:[cache key] /// </summary> /// <param name="key">Full cache path</param> /// <returns>The cached object, or null.</returns> public object Get(SwiffotronContext ctx, string key) { int pos = key.IndexOf(':'); if (pos < 0) { throw new SwiffotronException( SwiffotronError.BadInputXML, ctx, @"Bad cache key (Requires prefix): " + key); } string cacheId = key.Substring(0, pos); key = key.Substring(pos + 1); if (!caches.ContainsKey(cacheId)) { throw new SwiffotronException( SwiffotronError.BadInputXML, ctx, @"Cache '" + cacheId + @"' not registered."); } return this.caches[cacheId].Get(key); }
public void SetContext(SwiffotronContext ctx) { this.Context = ctx; }
/// <summary> /// Process a job XML file. /// </summary> /// <param name="xml">An open stream to the XML data.</param> /// <param name="commitStore">If not null, this will hold all store commits made /// by this job.</param> /// <param name="writeLog">Ignored in release builds. This will accumulate a /// log of write operations into the output SWF file(s).</param> /// <param name="abcWriteLog">A log of write events to ABC data within the /// output SWF files.</param> /// <param name="abcInterceptor">Ignored in release builds. This will be called /// when an ABC file is loaded as an opportunity to dump the data to file /// for inspection.</param> /// <param name="readLogHandler">Ignored in release builds. Whenever /// the Swiffotron reads a SWF file, this is called so that it can dump read /// operations to a log.</param> public void Process( Stream xml, Dictionary<string, byte[]> commitStore = null, StringBuilder writeLog = null, StringBuilder abcWriteLog = null, IABCLoadInterceptor abcInterceptor = null, ISwiffotronReadLogHandler readLogHandler = null) { #if DEBUG this.abcInterceptor = abcInterceptor; this.readLogHandler = readLogHandler; #endif this.commitStore = commitStore; Xml.LoadSwiffotronXML(xml); string jobID = Xml.SelectString("swf:swiffotron/@id"); this.Context = new SwiffotronContext(jobID); this.Xml.SetContext(this.Context); this.swfProc = new SWFProcessor(this.Context); this.processingList = new List<XPathNavigator>(); this.dependencyMap = new List<DependencyList>(); this.processedSWFs = new Dictionary<string, SWF>(); this.localCache = new Dictionary<string, object>(); /* Take local copies of all referenced cache objects to guard against * them being ejected before we access them, since we work out what we * need to do based on what's in the cache before we do it. */ foreach (XPathNavigator keyNode in Xml.Select(@"//@cachekey")) { string key = keyNode.ToString(); object data = this.caches.Get(this.Context, key); if (data != null) { this.localCache.Add(key, data); } } /* Select all the swf tags that have some sort of output: */ foreach (XPathNavigator outputTag in Xml.Select(@"//swf:swfout|//swf:pngout|//swf:vidout|//swf:svgout|//swf:htmlout")) { XmlAttributeCollection attribs = ((XmlElement)outputTag.UnderlyingObject).Attributes; /* ISSUE 28: Check the runifnotchanged thing. */ string dest = outputTag.GetAttribute(XMLHelper.AttrStore, string.Empty); outputTag.MoveToParent(); /* Select SWF tag */ if (!this.IsInDependenciesMap(outputTag)) { /* Add them with no dependencies. We'll work out dependencies in the * next step. */ this.dependencyMap.Add(new DependencyList(outputTag, null)); } } int pos = 0; while (pos < this.dependencyMap.Count) { this.AddDependencies(this.dependencyMap[pos]); pos++; } /* Now that we have a list of things and their dependencies, we * need to copy those nodes into the processingList in the correct * order. */ while (this.dependencyMap.Count > 0) { List<DependencyList> newMap = new List<DependencyList>(); foreach (DependencyList dep in this.dependencyMap) { if (dep.Count == 0) { this.processingList.Add(dep.Node); foreach (DependencyList filterDep in this.dependencyMap) { filterDep.RemoveDependency(dep.Node); } } else { /* Things still to be done. */ newMap.Add(dep); } } if (newMap.Count == this.dependencyMap.Count) { /* No progress was made, so: */ throw new SwiffotronException( SwiffotronError.BadInputXML, this.Context, @"A circular dependency was detected."); } this.dependencyMap = newMap; } /* And so, after all that, we can begin: */ this.GenerateSWFs(writeLog, abcWriteLog); }
/// <summary> /// Opens a stream from a store by its key string. /// </summary> /// <param name="key">The key, including store prefix</param> /// <returns>A stream, or null if not found.</returns> public Stream Open(SwiffotronContext ctx, string key) { Uri storeURI = new Uri(key); if (storeURI.Scheme != "store") /* ISSUE 67: Constants, please. */ { throw new SwiffotronException( SwiffotronError.BadInputXML, ctx, @"Store paths should begin with store://"); } string storeId = storeURI.Host; if (!stores.ContainsKey(storeId)) { throw new SwiffotronException( SwiffotronError.BadInputXML, ctx, @"Store '" + storeId + @"' not registered."); } try { return stores[storeId].OpenInput(storeURI.LocalPath.Substring(1)); } catch (FileNotFoundException fnfe) { throw new SwiffotronException( SwiffotronError.BadPathOrID, ctx.Sentinel("FileNotFoundInStore"), "File not found: " + key, fnfe); } }
/// <summary> /// Initializes a new instance of an exception without an error message /// </summary> /// <param name="error">The error code.</param> /// <param name="ctx">A context object that describes what was being done when the exception occured.</param> public SwiffotronException(SwiffotronError error, SwiffotronContext ctx) : base(error.ToString() + "; " + ctx.ToString()) { this.Error = error; this.Sentinel = ctx.SentinelString; }
/// <summary> /// Initializes a new instance of an exception with an error message /// </summary> /// <param name="error">The error code.</param> /// <param name="ctx">A context object that describes what was being done when the exception occured.</param> /// <param name="msg">The error message</param> /// <param name="inner">The inner exception</param> public SwiffotronException(SwiffotronError error, SwiffotronContext ctx, string msg, Exception inner) : base(error.ToString() + "; " + msg + "; " + ctx.ToString(), inner) { this.Error = error; this.Sentinel = ctx.SentinelString; }