HTML5 video from MVC3 action not working correctly - asp.net-mvc-3

I'm serving video from an MVC3 site, with the controller action that returns the video returning a FilePathResult, and when trying to play back in the browser, I'm seeing some frustrating issues, regardless of my using video.js or mediaelement.js.
Chrome doesn't let you change the position using progressbar, nor does it allow you to replay the video once it has completed
IE9 seems relatively fine
Firefox doesn't show the elapsed/remaining time correctly
However, if I just give a relative path to the file being hosted, it all works fine.
The videos need to be available only to users who belong to certain roles, so that isn't really an option.
The Action:
[Authorize]
public ActionResult Video(string fileName)
{
var pathBase = Server.MapPath("~/Downloads/Videos/");
var filePath = pathBase + fileName;
var contentType = ContentType(fileName);
return new FilePathResult(filePath, contentType) { FileDownloadName = fileName };
}
The Razor:
<!-- #t = the video entity -->
<video width="640" height="360" id="#t.Id" poster="#Url.Action("Video", "Download", new { fileName = #t.Poster })" controls="controls" preload="none">
<!-- MP4 source must come first for iOS -->
<source src="#Url.Action("Video", "Download", new { fileName = #t.Mp4 })" type='video/mp4' />
<!-- WebM for Firefox 4 and Opera -->
<source src="#Url.Action("Video", "Download", new { fileName = #t.WebM })" type='video/webm' />
<!-- OGG for Firefox 3 -->
<source src="#Url.Action("Video", "Download", new { fileName = #t.Ogv })" type='video/ogg' />
<!-- Fallback flash player for no-HTML5 browsers with JavaScript turned off -->
<object width="640" height="360" type="application/x-shockwave-flash" data="#Url.Content("~/Content/flashmediaelement.swf")">
<param name="movie" value="#Url.Content("~/Content/flashmediaelement.swf")" />
<param name="flashvars" value="controls=true&poster=#Url.Action("Video", "Download", new { fileName = #t.Poster })&file=#Url.Action("Video", "Download", new { fileName = #t.Mp4 })" />
<!-- Image fall back for non-HTML5 browser with JavaScript turned off and no Flash player installed -->
<img src="#Url.Action("Video", "Download", new { fileName = #t.Poster })" width="640" height="360" alt="#t.Title"
title="No video playback capabilities" />
</object>
</video>

I ended up writing an HTTP Handler to deal with these extensions, though it seems Chrome's issue is to do with my handler not supporting Range requests.
I used the following blog post to help me out: http://blogs.visigo.com/chriscoulson/easy-handling-of-http-range-requests-in-asp-net/. The solution (modified by me to include content type, as well as some basic security) is as follows:
public void ProcessRequest(HttpContext context)
{
if (!context.Request.RequestContext.HttpContext.User.Identity.IsAuthenticated)
context.Response.Redirect("~");
var path =
context.Request.RequestContext.HttpContext.Server.MapPath(
context.Request.AppRelativeCurrentExecutionFilePath);
long size, start, end, length, fp = 0;
using (StreamReader reader = new StreamReader(path))
{
size = reader.BaseStream.Length;
start = 0;
end = size - 1;
length = size;
// Now that we've gotten so far without errors we send the accept range header
/* At the moment we only support single ranges.
* Multiple ranges requires some more work to ensure it works correctly
* and comply with the spesifications: http://www.w3.org/Protocols/rfc2616/rfc2616-sec19.html#sec19.2
*
* Multirange support annouces itself with:
* header('Accept-Ranges: bytes');
*
* Multirange content must be sent with multipart/byteranges mediatype,
* (mediatype = mimetype)
* as well as a boundry header to indicate the various chunks of data.
*/
context.Response.AddHeader("Accept-Ranges", "0-" + size);
context.Response.ContentType = "video/mp4";
// header('Accept-Ranges: bytes');
// multipart/byteranges
// http://www.w3.org/Protocols/rfc2616/rfc2616-sec19.html#sec19.2
if (!String.IsNullOrEmpty(context.Request.ServerVariables["HTTP_RANGE"]))
{
long anotherStart = start;
long anotherEnd = end;
string[] arr_split =
context.Request.ServerVariables["HTTP_RANGE"].Split(new char[] {Convert.ToChar("=")});
string range = arr_split[1];
// Make sure the client hasn't sent us a multibyte range
if (range.IndexOf(",") > -1)
{
// (?) Shoud this be issued here, or should the first
// range be used? Or should the header be ignored and
// we output the whole content?
context.Response.AddHeader("Content-Range", "bytes " + start + "-" + end + "/" + size);
throw new HttpException(416, "Requested Range Not Satisfiable");
}
// If the range starts with an '-' we start from the beginning
// If not, we forward the file pointer
// And make sure to get the end byte if spesified
if (range.StartsWith("-"))
{
// The n-number of the last bytes is requested
anotherStart = size - Convert.ToInt64(range.Substring(1));
}
else
{
arr_split = range.Split(new char[] {Convert.ToChar("-")});
anotherStart = Convert.ToInt64(arr_split[0]);
long temp = 0;
anotherEnd = (arr_split.Length > 1 && Int64.TryParse(arr_split[1].ToString(), out temp))
? Convert.ToInt64(arr_split[1])
: size;
}
/* Check the range and make sure it's treated according to the specs.
* http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html
*/
// End bytes can not be larger than $end.
anotherEnd = (anotherEnd > end) ? end : anotherEnd;
// Validate the requested range and return an error if it's not correct.
if (anotherStart > anotherEnd || anotherStart > size - 1 || anotherEnd >= size)
{
context.Response.AddHeader("Content-Range", "bytes " + start + "-" + end + "/" + size);
throw new HttpException(416, "Requested Range Not Satisfiable");
}
start = anotherStart;
end = anotherEnd;
length = end - start + 1; // Calculate new content length
fp = reader.BaseStream.Seek(start, SeekOrigin.Begin);
context.Response.StatusCode = 206;
}
}
// Notify the client the byte range we'll be outputting
context.Response.AddHeader("Content-Range", "bytes " + start + "-" + end + "/" + size);
context.Response.AddHeader("Content-Length", length.ToString());
// Start buffered download
context.Response.WriteFile(path, fp, length);
context.Response.Flush();
}

Thanks for your answer!
I used something similar:
internal static void StreamVideo(string fullpath, HttpContextBase context)
{
long size, start, end, length, fp = 0;
using (StreamReader reader = new StreamReader(fullpath))
{
size = reader.BaseStream.Length;
start = 0;
end = size - 1;
length = size;
// Now that we've gotten so far without errors we send the accept range header
/* At the moment we only support single ranges.
* Multiple ranges requires some more work to ensure it works correctly
* and comply with the spesifications: http://www.w3.org/Protocols/rfc2616/rfc2616-sec19.html#sec19.2
*
* Multirange support annouces itself with:
* header('Accept-Ranges: bytes');
*
* Multirange content must be sent with multipart/byteranges mediatype,
* (mediatype = mimetype)
* as well as a boundry header to indicate the various chunks of data.
*/
context.Response.AddHeader("Accept-Ranges", "0-" + size);
// header('Accept-Ranges: bytes');
// multipart/byteranges
// http://www.w3.org/Protocols/rfc2616/rfc2616-sec19.html#sec19.2
if (!String.IsNullOrEmpty(context.Request.ServerVariables["HTTP_RANGE"]))
{
long anotherStart = start;
long anotherEnd = end;
string[] arr_split = context.Request.ServerVariables["HTTP_RANGE"].Split(new char[] { Convert.ToChar("=") });
string range = arr_split[1];
// Make sure the client hasn't sent us a multibyte range
if (range.IndexOf(",") > -1)
{
// (?) Shoud this be issued here, or should the first
// range be used? Or should the header be ignored and
// we output the whole content?
context.Response.AddHeader("Content-Range", "bytes " + start + "-" + end + "/" + size);
throw new HttpException(416, "Requested Range Not Satisfiable");
}
// If the range starts with an '-' we start from the beginning
// If not, we forward the file pointer
// And make sure to get the end byte if spesified
if (range.StartsWith("-"))
{
// The n-number of the last bytes is requested
anotherStart = size - Convert.ToInt64(range.Substring(1));
}
else
{
arr_split = range.Split(new char[] { Convert.ToChar("-") });
anotherStart = Convert.ToInt64(arr_split[0]);
long temp = 0;
anotherEnd = (arr_split.Length > 1 && Int64.TryParse(arr_split[1].ToString(), out temp)) ? Convert.ToInt64(arr_split[1]) : size;
}
/* Check the range and make sure it's treated according to the specs.
* http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html
*/
// End bytes can not be larger than $end.
anotherEnd = (anotherEnd > end) ? end : anotherEnd;
// Validate the requested range and return an error if it's not correct.
if (anotherStart > anotherEnd || anotherStart > size - 1 || anotherEnd >= size)
{
context.Response.ContentType = MimeMapping.GetMimeMapping(fullpath);
context.Response.AddHeader("Content-Range", "bytes " + start + "-" + end + "/" + size);
throw new HttpException(416, "Requested Range Not Satisfiable");
}
start = anotherStart;
end = anotherEnd;
length = end - start + 1; // Calculate new content length
fp = reader.BaseStream.Seek(start, SeekOrigin.Begin);
context.Response.StatusCode = 206;
}
}
// Notify the client the byte range we'll be outputting
context.Response.AddHeader("Content-Range", "bytes " + start + "-" + end + "/" + size);
context.Response.AddHeader("Content-Length", length.ToString());
// Start buffered download
context.Response.WriteFile(fullpath, fp, length);
context.Response.End();
}

Related

BufferedSoundStream can't play wav files

I'm making an app for my drum classes and to make it cross-platform I've chosen Urho.Sharp, because it has low level Sound API as well as rich graphics capabilities.
As a first step I'm making a metronome app and for that I'm working with BufferedSoundStream adding here audio and then needed silence, as described here: https://github.com/xamarin/urho-samples/blob/master/FeatureSamples/Core/29_SoundSynthesis/SoundSynthesis.cs
But the resulting sound is not a sound at all, like random bits got into buffered stream.
This is my code:
///
/// this code initialize sound subsystem
///
void CreateSound()
{
// Sound source needs a node so that it is considered enabled
node = new Node();
SoundSource source = node.CreateComponent<SoundSource>();
soundStream = new BufferedSoundStream();
// Set format: 44100 Hz, sixteen bit, stereo
soundStream.SetFormat(44100, true, true);
// Start playback. We don't have data in the stream yet, but the
SoundSource will wait until there is data,
// as the stream is by default in the "don't stop at end" mode
source.Play(soundStream);
}
///
/// this code preload all sound resources
///
readonly Dictionary<PointSoundType, string> SoundsMapping = new Dictionary<PointSoundType, string>
{
{PointSoundType.beat, "wav/beat.wav"},
{PointSoundType.click, "wav/click.wav"},
{PointSoundType.click_accent, "wav/click_accent.wav"},
{PointSoundType.crash, "wav/crash.wav"},
{PointSoundType.foot_hh, "wav/foot_hh.wav"},
{PointSoundType.hh, "wav/hh.wav"},
{PointSoundType.open_hh, "wav/open_hh.wav"},
{PointSoundType.ride, "wav/ride.wav"},
{PointSoundType.snare, "wav/snare.wav"},
{PointSoundType.tom_1, "wav/tom_1.wav"},
{PointSoundType.tom_2, "wav/tom_2.wav"},
};
Dictionary<PointSoundType, Sound> SoundCache = new Dictionary<PointSoundType, Sound>();
private void LoadSoundResources()
{
// preload all sounds
foreach (var s in SoundsMapping)
{
SoundCache[s.Key] = ResourceCache.GetSound(s.Value);
Debug.WriteLine("resource loaded: " + s.Value + ", length = " + SoundCache[s.Key].Length);
}
}
///
/// this code fill up the stream with audio
///
private void UpdateSound()
{
// Try to keep 1/10 seconds of sound in the buffer, to avoid both dropouts and unnecessary latency
//float targetLength = 1.0f / 10.0f;
// temporary increase buffer to 1s
float targetLength = 1.0f;
float requiredLength = targetLength - soundStream.BufferLength;
if (requiredLength < 0.0f)
return;
uint numSamples = (uint)(soundStream.Frequency * requiredLength);
// check if stream is still full
if (numSamples == 0)
return;
var silencePause = new short[44100];
// iterate and play all sounds
SoundCache.All(s =>
{
soundStream.AddData(s.Value.Handle, s.Value.DataSize);
// add silencio
soundStream.AddData(silencePause, 0, silencePause.Length);
return true;
});
}
Make sure your wav files are in the resource cache. Then don't play the BufferedSoundStream, but the Urho.Audio.Sound sound. This is just a different override of the same method Urho.Audio.SoundSource.Play(), but it works.
int PlaySound(string sSound)
{
var cache = Application.Current.ResourceCache;
Urho.Audio.Sound sound = cache.GetSound(sSound);
if (sound != null)
{
Node soundNode = scene.CreateChild("Sound");
Urho.Audio.SoundSource soundSource = soundNode.CreateComponent<Urho.Audio.SoundSource>();
soundSource.Play(sound);
soundSource.Gain = 0.99f;
return 1;
}
return 0;
}
Since you're using urhosamples, you can start each drum sample from the override update something like this:
public float fRun = 0.0f;
public int iRet = 0; // keep counting the played sounds
public override void OnUpdate(float timeStep)
{
fRun = fRun + timeStep;
int iMS = (int)(10f * fRun); // tenth of seconds
if (iMS == 100) iRet = iRet + PlaySound("wav/hh.wav");
if (iMS == 120) iRet = iRet + PlaySound("wav/hh.wav");
if (iMS == 140) iRet = iRet + PlaySound("wav/hh.wav");
if (iMS == 160) iRet = iRet + PlaySound("wav/open_hh.wav");
if (iMS >= 160) fRun = 0.8f;
}

ESP8266 + Teensyduino Web Server

Im using a Teensy 3.2 microcontroller paired with an ESP8266. Right now im just trying to serve a simple HTML web page that is updated with ajax. I can connect to the ESP and serve a page but im having trouble updating the page with XML data. The problem is somewhere in the loop function. Im not sure how to get the ESP to properly send XML data, or maybe im missing a critical function. Help greatly appreciated!
#define LED1 11
#define LED2 12
#define BUFFER_SIZE 4096
#define SSID "xxxx" // change this to match your WiFi SSID
#define PASS "xxxx" // change this to match your WiFi password
#define PORT "8080" // Port 8080 is default webserver port
char buffer[BUFFER_SIZE];
int n = 0;
String webSite, javaScript, XML, header, content;
void buildWebsite() {
header = "HTTP/1.1 200 OK\r\n";
header += "Content-Type: text/html\r\n";
header += "Connection: close\r\n";
//header += "Refresh: 5\r\n";
buildJavascript();
content = "<!DOCTYPE HTML>\n";
content += javaScript;
content += "<BODY onload='process()'>\n";
content += "<BR>This is the ESP website.<BR>\n";
content += "Runtime = <A id='runtime'></A>\n";
content += "</BODY>\n";
content += "</HTML>\n";
header += "Content-Length:";
header += (int)(content.length());
header += "\r\n\r\n";
webSite = header + content;
}
void buildJavascript() {
javaScript = "<SCRIPT>\n";
javaScript += "var xmlHttp = createXmlHttpObject();\n";
javaScript += "function createXmlHttpObject() {\n";
javaScript += " if(window.XMLHttpRequest) {\n";
javaScript += " xmlHttp = new XMLHttpRequest();\n";
javaScript += " } else {\n";
javaScript += " xmlHttp = new ActiveXObject('Microsoft.XMLHTTP');\n";
javaScript += " }\n";
javaScript += " return xmlHttp;\n";
javaScript += "}\n";
javaScript += "function process(){\n";
javaScript += " if(xmlHttp.readyState == 0 || xmlHttp.readyState == 4){\n";
javaScript += " xmlHttp.open('GET','xml',true);\n";
javaScript += " xmlHttp.onreadystatechange = handleServerResponse();\n"; // no brackets?????
javaScript += " xmlHttp.send();\n";
javaScript += " }\n";
javaScript += " setTimeout('process()',1000);\n";
javaScript += "}\n";
javaScript += "function handleServerResponse(){\n";
javaScript += " if(xmlHttp.readyState == 4 && xmlHttp.status == 200){\n";
javaScript += " xmlResponse = xmlHttp.responseXML;\n";
javaScript += " xmldoc = xmlResponse.getElementsByTagName('response');\n";
javaScript += " message = xmldoc[0].firstChild.nodeValue;\n";
javaScript += " document.getElementById('runtime').innerHTML = message;\n";
javaScript += " }\n";
javaScript += "}\n";
javaScript += "</SCRIPT>\n";
}
void buildXML() {
XML = "<?xml version='1.0' encoding='UTF-8'?>\n";
XML += "<response>\n";
XML += millis2time();
XML += "</response>\n";
}
String millis2time() {
String Time = "";
unsigned long ss;
byte mm, hh;
ss = millis() / 1000;
hh = ss / 3600;
mm = (ss - hh * 3600) / 60;
ss = (ss - hh * 3600) - mm * 60;
if (hh < 10)Time += "0";
Time += (String)hh + ":";
if (mm < 10)Time += "0";
Time += (String)mm + ":";
if (ss < 10)Time += "0";
Time += (String)ss;
return Time;
}
/*******************************************************************
* PROGRAM SETUP
********************************************************************/
void setup() {
delay(1000);
Serial1.begin(115200); // Teensy to ESP8266
Serial.begin(115200); // Teensy to USB Serial
Serial.println("Begin program.");
pinMode(LED1, OUTPUT);
pinMode(LED2, OUTPUT);
// Initialize ESP8266.
setupWiFi();
}
/*******************************************************************
* DEVICE FUNCTIONS
********************************************************************/
// Read line responses from ESP8266.
bool read_till_eol() {
static int i = 0;
if (Serial1.available()) {
buffer[i++] = Serial1.read();
if (i == BUFFER_SIZE) i = 0;
if (i > 1 && buffer[i - 2] == 13 && buffer[i - 1] == 10) {
buffer[i] = 0;
i = 0;
Serial.print(buffer);
return true;
}
}
return false;
}
// Listen for ESP8266 response. By default we are looking for OK\r\n
char OK[] = "OK\r\n";
byte wait_for_esp_response(int timeout, char* term = OK) {
unsigned long t = millis();
bool found = false;
int i = 0;
int len = strlen(term); // compute length of (string)
// wait for at most timeout milliseconds, or if OK\r\n is found
while (millis() < t + timeout) {
if (Serial1.available()) {
digitalWrite(LED2, HIGH);
buffer[i++] = Serial1.read();
if (i >= len) {
if (strncmp(buffer + i - len, term, len) == 0) {
found = true;
break;
}
}
digitalWrite(LED2, LOW);
}
}
buffer[i] = 0;
Serial.print(buffer);
return found;
}
/*******************************************************************
* LOOP
********************************************************************/
void loop() {
int ch_id, packet_len;
char *pb;
// Look for received IDP (unsolicited data packet) from browser refresh.
if (read_till_eol()) {
if (strncmp(buffer, "+IPD,", 5) == 0) // If strings match...
{
// Request: (+IPD, connection channel, data length)
sscanf(buffer + 5, "%d,%d", &ch_id, &packet_len);
if (packet_len > 0) {
// Read serial until packet_len character received
// start from :
pb = buffer + 5;
while (*pb != ':') pb++;
pb++;
if (strncmp(pb, "GET / HTTP", 10) == 0)
{
// Send HTML data.
wait_for_esp_response(2000);
Serial.println("Serving HTML ->");
buildWebsite();
serve(webSite, ch_id);
}
else if (strncmp(pb, "GET /xml", 8) == 0)
{
// Send XML data.
wait_for_esp_response(2000);
Serial.println("Serving XML ->");
buildXML();
serve(XML, ch_id);
Serial.println(millis2time());
}
}
}
}
}
/*******************************************************************
* SEND DATA
********************************************************************/
// Send the data to the ESP8266.
void serve(String data, int ch_id)
{
Serial1.print("AT+CIPSEND=");
Serial1.print(ch_id);
Serial1.print(",");
Serial1.println(data.length());
if (wait_for_esp_response(1000)) {
Serial1.print(data);
}
else {
Serial1.print("AT+CIPCLOSE=");
Serial1.println(ch_id);
}
}
/*******************************************************************
* SETUP WIFI
********************************************************************/
void setupWiFi() {
// Turn on echo.
Serial1.println("ATE1");
wait_for_esp_response(1000);
// Set mode 3 (client + AP).
Serial1.println("AT+CWMODE=3");
wait_for_esp_response(1000);
// Reset WiFi module.
Serial1.print("AT+RST\r\n");
wait_for_esp_response(1500);
// Join AP.
Serial1.print("AT+CWJAP=\"");
Serial1.print(SSID);
Serial1.print("\",\"");
Serial1.print(PASS);
Serial1.println("\"");
wait_for_esp_response(5000);
// Start server.
Serial1.println("AT+CIPMUX=1");
wait_for_esp_response(1000);
// Create TCP Server.
Serial1.print("AT+CIPSERVER=1,");
Serial1.println(PORT);
wait_for_esp_response(1000);
// Set the automatic socket client disconnection timeout from 1 to 28800 seconds.
Serial1.println("AT+CIPSTO=6000");
wait_for_esp_response(1000);
Serial1.println("AT+GMR");
wait_for_esp_response(1000);
Serial1.println("AT+CWJAP?");
wait_for_esp_response(1000);
Serial1.println("AT+CIPSTA?");
wait_for_esp_response(1000);
Serial1.println("AT+CWMODE?");
wait_for_esp_response(1000);
Serial1.println("AT+CIFSR");
wait_for_esp_response(5000);
Serial1.println("AT+CWLAP");
wait_for_esp_response(5000);
Serial1.println("AT+CIPSTATUS");
wait_for_esp_response(5000);
Serial.println("------------------------------------");
}
One of the problems is here:
xmlHttp.onreadystatechange = handleServerResponse();
You are not binding your handler to the readystatechange event. You are just setting what handleServerResponse() returns to xmlHttp.onreadystatechange.
It should be:
xmlHttp.onreadystatechange = handleServerResponse;
The second problem is that you aren't sending your XML as a proper HTTP response.
You should send it with HTTP headers like you are sending your HTML. And your XML response should set the Content-Type header as text/xml.
There are other possible problems/improvements like:
You are putting your <script> tag directly into the <html> tag. It should be under the <head> tag.
You are using Refresh: 5 header, but you are already refreshing your page with AJAX.
You don't need so send XML, if you just want a single value. You could just send what millis2time() returns and use document.getElementById('runtime').innerHTML = xmlHttp.responseText; in your JavaScript.
Your HTML code is static and doesn't change between requests. It doesn't make sense to build the whole request on every HTTP request.
You could just put the whole request string into a const variable and then serve that.

Get variable from web page with javascript in C++ Builder

I have a MiFi modem (Huawei e5776) which comes with its own web page that displays total traffic per month. I want to extract this value and display a meter in the icon tray. I'm sure this is possible in C++ Builder (or Delphi) but even though I'm pretty experienced in using C++ Builder, I am not in anything web related. Can someone give me some pointers how to do this? I assume I need to run the script and then extract the variable somewhere, how do I do this?
Thanks.
PS: I'd add the contents of the page but can't see a way to attach a document. Here's the first few lines..
// JavaScript Document
var g_monitoring_traffic_statistics = null;
var g_wlan_security_settings = null;
var g_wlan_basic_settings = null;
var g_connection_trafficresponse = null;
//Prefix string of ssid2 of Multi-SSID
var g_prefixWifiSsid = "ssid2_";
function getTrafficInfo(bit) {
var final_number = 0;
var final_str = "";
if(g_monitoring_dumeter_kb > bit) {
final_number = formatFloat(parseFloat(bit), 2);
final_str = final_number + " B";
}
else if(g_monitoring_dumeter_kb <= bit && g_monitoring_dumeter_mb > bit) {
final_number = formatFloat(parseFloat(bit) / g_monitoring_dumeter_kb, 2);
final_str = final_number + " KB";
}
else if(g_monitoring_dumeter_mb <= bit && g_monitoring_dumeter_gb > bit) {
final_number = formatFloat((parseFloat(bit) / g_monitoring_dumeter_mb), 2);
final_str = final_number + " MB";
}
else if(g_monitoring_dumeter_gb <= bit && g_monitoring_dumeter_tb > bit) {
final_number = formatFloat((parseFloat(bit) / g_monitoring_dumeter_gb), 2);
final_str = final_number + " GB";
}
else {
final_number = formatFloat((parseFloat(bit) / g_monitoring_dumeter_tb), 2);
final_str = final_number + " TB";
}
return final_str;
}
I suggest you to use a great html wrapper (named BCB HTML) for mshtml writed specially for C++Builder; With this wrapper you can execute java script inside C++ Builder cpp codes:
THTMLDocument document;
document.create();
document.write(
"<html><body><script>"
"function myFunc(n)"
"{"
"return n * n;"
"}"
"</script></body></html>");
document.parentWindow.execScript("alert(myFunc(3))", "javascript");
For your jscript:
String value = document.parentWindow.execScript("getTrafficInfo(1024)", "javascript");
Also it is possible to handle html events inside BCB, access html objects , ...
you can download it from here.
To use this source add html.cpp to your project.
If you use TWebBrowser to load a html page, you need just define document in global scope and write below code to connect/attach document variable to WebBrowser1->Document:
void __fastcall TForm1::WebBrowser1DocumentComplete(TObject *ASender,
const IDispatch *pDisp, const OleVariant &URL)
{
document.documentFromVariant(WebBrowser1->Document);
String value = document.parentWindow.execScript("getTrafficInfo(1024)", "javascript");
}

Download zip file (contains xml and images) through ajax and store binary data in localstorage in IE

I was able to download the zip file (2mb) from server through ajax call and storing binary data in the web storage where as this is not working in IE (7,8,9). Below is my code.
var req = new XMLHttpRequest();
req.open('GET', filename, false);
req.onreadystatechange=function()
{
if (req.readyState == 4)
{
if(req.status!=200){
chk_file = false;
alert('Sorry, Error occured while downloading the question paper. HTTP Error Code: '+req.status);
}
}
}
if (req.overrideMimeType) {
req.overrideMimeType('text/plain; charset=x-user-defined');
} else {
req.setRequestHeader('Accept-Charset', 'x-user-defined');
}
req.send('hello');
var buffer = "";
var dbata;
try {
bdata = BinaryToArray(req.responseBody).toArray();
for (var i = 0, len = bdata.length - 1; i < len; i++) {// dbata is one byte too long. Why ???
buffer += String.fromCharCode(bdata[i] & 0xFF);
}
} catch(e) {
bdata = req.responseText;
for (var i = 0, len = bdata.length; i < len; i++) {
buffer += String.fromCharCode(bdata.charCodeAt(i) & 0xFF);
}
}
Converting Binary data to array in VB script . following is the code.
var IE_HACK = (/msie/i.test(navigator.userAgent) &&
!/opera/i.test(navigator.userAgent));
if (IE_HACK) {
var vbScript = '<scr' + 'ipt type="text/vbscript">\n'+
'<!-' + '-\n' +
'Function BinaryToArray(Binary)\n'+
' Dim i\n'+
' ReDim byteArray(LenB(Binary))\n'+
' For i = 1 To LenB(Binary)\n'+
' byteArray(i-1) = AscB(MidB(Binary, i, 1))\n'+
' Next\n'+
' BinaryToArray = byteArray\n'+
'End Function\n'+
'--' + '>\n' +
'</scr' + 'ipt>';
//$(vbScript).insertAfter("script:last");
document.write(vbScript);
Storing this buffer value in html5 web storage.
I am not getting complete content in IE where it is working in FF, Chrome.
Any help!
Maybe this can help you, but guess you solved this by now, but it might help people that sees this question
is there a cross-browser alternative to the xhr.overrideMimeType() function?
https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/Sending_and_Receiving_Binary_Data
https://github.com/eligrey/FileSaver.js
http://stuk.github.io/jszip/

j2me midlet chinese character display message garbled

My J2ME midlet could retrieves message in Chinese character from a PHP server but it's garbled. The server basically returns the response string and by detecting the first 2 characters. AA = good, anything else indicates error of which the message is to be passed to the calling function for display
InputStream is = null;
StringBuffer sb = null;
String str = "";
HttpConnection http = null;
DataOutputStream dos = null;
try
{
URL = login.getURL();
URL += ctlFunction + "/" + uriStr;
URL = EncodeURL(URL);
//System.out.println(URL);
if(!ctlFunction.equals("login"))
{
msg += "&user=" + login.getUsername();
msg += "&token=" + login.getToken();
}
msg += "&lang=" + System.getProperty("microedition.locale");
// establish the connection
http = (HttpConnection) Connector.open(URL);
http.setRequestMethod(HttpConnection.POST);
http.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
http.setRequestProperty("Content-length", ""+EncodeURL(msg).getBytes().length);
dos = http.openDataOutputStream();
byte[] request_body = EncodeURL(msg).getBytes();
for (int i = 0; i < request_body.length; i++)
{
dos.writeByte(request_body[i]);
}
// server response
if (http.getResponseCode() == HttpConnection.HTTP_OK)
{
is = http.openDataInputStream();
int length = (int) http.getLength();
if (length != -1)
{
// Read data in one chunk
byte serverData[] = new byte[length];
is.read(serverData);
str = new String(serverData);
}
else // Length not available...
{
ByteArrayOutputStream bStrm = new ByteArrayOutputStream();
int ch;
while ((ch = is.read()) != -1)
bStrm.write(ch);
str = new String(bStrm.toByteArray());
bStrm.close();
}
}
else
{
networkError();
}
}
catch (Exception e)
{
System.err.println("Error3: " + e.toString());
networkError(e.toString());
}
finally
{
if (is != null)
is.close();
if (!str.equals(""))
post = str;
else
networkError();
if (http != null)
http.close();
}
if (post != null)
{
String fate = post.substring(0, 2);
if(fate.equals("AA"))
{
if(ctlFunction.equals("login"))
{
String rawPost = post.substring(2);
Vector v = new Vector();
int index = 0;
//find the first occurrence of the SPLITTER
int endIndex = rawPost.indexOf(SPLITTER, index);
String item = "";
//extract the items until the end of the last SPLITTER found in the rawPost string
while(endIndex != -1)
{
item = rawPost.substring(index, endIndex);
index = endIndex + 1;
endIndex = rawPost.indexOf(SPLITTER, index);
v.addElement(item);
}
//extract the rest of the rawPost (the text item)
item = rawPost.substring(index);
v.addElement(item);
String[] ret = new String[v.size()];
v.copyInto(ret);
login.setToken(ret[0]);
login.setToday(ret[1]);
login.setNextDrawDay(ret[2]);
}
midlet.returnResults(post.substring(2), getCurrentDisplay(), ctlFunction);
}
else
{
String errmessage = post.substring(2);
System.out.println(post);
midlet.showInfo(post, getCurrentDisplay());
}
}
else
{
networkError();
}
On the PHP server, I have set the header to UTF-8 encoding
<?php header("Content-Type:text/plain; charset=utf-8"); ?>
What could possibly be wrong?
I found that this user has the same problem and it's been answered
Reading UTF8 strings from a server through http using MIDP. Kudos to the answer.
I basically edited my MIDP code from
// is = http.openDataInputStream();
// int length = (int) http.getLength();
// if (length != -1)
// {
// // Read data in one chunk
// byte serverData[] = new byte[length];
// is.read(serverData);
// str = new String(serverData);
// }
// else // Length not available...
// {
// ByteArrayOutputStream bStrm = new ByteArrayOutputStream();
// int ch;
// while ((ch = is.read()) != -1)
// bStrm.write(ch);
//
// str = new String(bStrm.toByteArray());
// bStrm.close();
// }
to
Reader r = new InputStreamReader(http.openInputStream(), "UTF-8");
int ch;
while((ch = r.read()) != -1)
str = str + (char)ch;
just wondering though why does reading bytes messes up the UTF-8 characters?

Resources