StandaloneWebResources.cs 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. using System;
  2. using System.Collections.Generic;
  3. using System.IO;
  4. using System.IO.Compression;
  5. using System.Text;
  6. using System.Threading;
  7. using UnityEngine;
  8. namespace ZenFulcrum.EmbeddedBrowser {
  9. /**
  10. * Implements fetching BrowserAssets for standalone builds.
  11. *
  12. * During build, everything in BrowserAssets is packaged into a single file with the following format:
  13. * brString {FileHeader}
  14. * i32 numEntries
  15. * {numEntries} IndexEntry objects
  16. * data //The data section is a series of filedata chunks, as laid out in the index.
  17. */
  18. public class StandaloneWebResources : WebResources {
  19. public struct IndexEntry {
  20. public string name;
  21. public long offset;
  22. public int length;
  23. }
  24. private const string FileHeader = "zfbRes_v1";
  25. protected Dictionary<string, IndexEntry> toc = new Dictionary<string, IndexEntry>();
  26. protected string dataFile;
  27. public StandaloneWebResources(string dataFile) {
  28. this.dataFile = dataFile;
  29. }
  30. public const string DefaultPath = "Resources/browser_assets";
  31. public void LoadIndex() {
  32. using (var data = new BinaryReader(File.OpenRead(dataFile))) {
  33. var header = data.ReadString();
  34. if (header != FileHeader) throw new Exception("Invalid web resource file");
  35. var num = data.ReadInt32();
  36. for (int i = 0; i < num; ++i) {
  37. var entry = new IndexEntry() {
  38. name = data.ReadString(),
  39. offset = data.ReadInt64(),
  40. length = data.ReadInt32(),
  41. };
  42. toc[entry.name] = entry;
  43. }
  44. }
  45. }
  46. public override void HandleRequest(int id, string url) {
  47. var parsedURL = new Uri(url);
  48. var path = WWW.UnEscapeURL(parsedURL.AbsolutePath);
  49. IndexEntry entry;
  50. if (!toc.TryGetValue(path, out entry)) {
  51. SendError(id, "Not found", 404);
  52. return;
  53. }
  54. new Thread(() => {
  55. try {
  56. var ext = Path.GetExtension(entry.name);
  57. if (ext.Length > 0) ext = ext.Substring(1);
  58. string mimeType;
  59. if (!extensionMimeTypes.TryGetValue(ext, out mimeType)) {
  60. mimeType = extensionMimeTypes["*"];
  61. }
  62. using (var file = File.OpenRead(dataFile)) {
  63. var pre = new ResponsePreamble {
  64. headers = null,
  65. length = entry.length,
  66. mimeType = mimeType,
  67. statusCode = 200,
  68. };
  69. SendPreamble(id, pre);
  70. file.Seek(entry.offset, SeekOrigin.Begin);
  71. var data = new byte[entry.length];
  72. var readLen = file.Read(data, 0, entry.length);
  73. if (readLen != data.Length) throw new Exception("Insufficient data for file");
  74. SendData(id, data);
  75. }
  76. } catch (Exception ex) {
  77. Debug.LogException(ex);
  78. }
  79. }).Start();
  80. }
  81. public void WriteData(Dictionary<string, byte[]> files) {
  82. var entries = new Dictionary<string, IndexEntry>();
  83. using (var file = File.OpenWrite(dataFile)) {
  84. var writer = new BinaryWriter(file, Encoding.UTF8 /*, true (Mono too old)*/);
  85. writer.Write(FileHeader);
  86. writer.Write(files.Count);
  87. var tocStart = file.Position;
  88. foreach (var kvp in files) {
  89. writer.Write(kvp.Key);
  90. writer.Write(0L);
  91. writer.Write(0);
  92. }
  93. //we'll come back and fill it in right later
  94. foreach (var kvp in files) {
  95. var data = kvp.Value;
  96. var entry = new IndexEntry {
  97. name = kvp.Key,
  98. length = kvp.Value.Length,
  99. offset = file.Position,
  100. };
  101. writer.Write(data);
  102. entries[kvp.Key] = entry;
  103. }
  104. //now go back and write the correct data.
  105. writer.Seek((int)tocStart, SeekOrigin.Begin);
  106. foreach (var kvp in files) {
  107. var entry = entries[kvp.Key];
  108. writer.Write(kvp.Key);
  109. writer.Write(entry.offset);
  110. writer.Write(entry.length);
  111. }
  112. }
  113. }
  114. }
  115. }