1: public override void Write(byte[] buffer, int offset, int count)
2: {
3: // If we are not capturing script blocks anymore, just redirect to response stream
4: if (!this.captureScripts)
5: {
6: this.responseStream.Write(buffer, offset, count);
7: return;
8: }
9:
10: /*
11: * Script and HTML can be in one of the following combinations in the specified buffer:
12: * .....< script ....>..........
13: * < script ....>..........
14: * < script ....>.....
15: * < script ....>..... .....
16: * ....< script ....>.....
17: * < script ....>.....
18: * ..........
19: * .....
20: * < script>.....
21: * ....
22: * ......
23: * Here, "...." means html content between and outside script tags
24: */
25:
26: char[] content = this.encoding.GetChars(buffer, offset, count);
27:
28: int scriptTagStart = 0;
29: int lastScriptTagEnd = 0;
30: bool scriptTagStarted = false;
31:
32: for (int pos = 0; pos < content.Length; pos++)
33: {
34: // See if tag start
35: char c = content[pos];
36: if (c == '<')
37: {
38: int tagStart = pos;
39: // Check if it's a tag ending
40: if (content[pos+1] == '/')
41: {
42: pos+=2; // go past the
43:
44: // See if script tag is ending
45: if (isScriptTag(content, pos))
46: {
47: /// Script tag just ended. Get the whole script
48: /// and store in buffer
49: pos = pos + "script>".Length;
50: scriptBlocks.Append(content, scriptTagStart, pos - scriptTagStart);
51: scriptBlocks.Append(Environment.NewLine);
52: lastScriptTagEnd = pos;
53:
54: scriptTagStarted = false;
55: continue;
56: }
57: else if (isBodyTag(content, pos))
58: {
59: /// body tag has just end. Time for rendering all the script
60: /// blocks we have suppressed so far and stop capturing script blocks
61:
62: if (this.scriptBlocks.Length > 0)
63: {
64: // Render all pending html output till now
65: this.WriteOutput(content, lastScriptTagEnd, tagStart - lastScriptTagEnd);
66:
67: // Render the script blocks
68: byte[] scriptBytes = this.encoding.GetBytes(this.scriptBlocks.ToString());
69: this.responseStream.Write(scriptBytes, 0, scriptBytes.Length);
70:
71: // Stop capturing for script blocks
72: this.captureScripts = false;
73:
74: // Write from the body tag start to the end of the inut buffer and return
75: // from the function. We are done.
76: this.WriteOutput(content, tagStart, content.Length - tagStart);
77: return;
78: }
79: }
80: else
81: {
82: // some other tag's closing. safely skip one character as smallest
83: // html tag is one character e.g. . just an optimization to save one loop
84: pos++;
85: }
86: }
87: else
88: {
89: if (isScriptTag(content, pos+1))
90: {
91: /// Script tag started. Record the position as we will
92: /// capture the whole script tag including its content
93: /// and store in an internal buffer.
94: scriptTagStart = pos;
95:
96: // Write html content since last script tag closing upto this script tag
97: this.WriteOutput(content, lastScriptTagEnd, scriptTagStart - lastScriptTagEnd);
98:
99: // Skip the tag start to save some loops
100: pos += "< script".Length;
101:
102: scriptTagStarted = true;
103: }
104: else
105: {
106: // some other tag started
107: // safely skip 2 character because the smallest tag is one character e.g.
108: // just an optimization to eliminate one loop
109: pos++;
110: }
111: }
112: }
113: }
114:
115: // If a script tag is partially sent to buffer, then the remaining content
116: // is part of the last script block
117: if (scriptTagStarted)
118: {
119:
120: this.scriptBlocks.Append(content, scriptTagStart, content.Length - scriptTagStart);
121: }
122: else
123: {
124: /// Render the characters since the last script tag ending
125: this.WriteOutput(content, lastScriptTagEnd, content.Length - lastScriptTagEnd);
126: }
127: }