views:

111

answers:

3

I need to read files produced by a legacy Windows app that stores real numbers (the 8-byte "double" type) in binary - i.e. as a packed array of 8 bytes. I can read the 8 byte group OK but how can I present it to my ASP JScript code such I can get the real number back again.

Or to put it another way:

Say a file was produced by a Windows (Delphi) program:

Assign (f, 'test.bin') ;
rewrite (f, 1) ;
r := 1234.56E78 ;
BlockWrite (f, r, SizeOf (Double)) ;
Close (f) ;

Inspection of the file will show it contains 8 bytes, being:

94 0E 4C CA C2 97 AD 53

which is the real number in IEEE format. Assuming I can read these 8 bytes back in ASP, is there a simple way of getting the real number back again?

A: 

You could use an ADO stream. It is used to read, write, and manage a stream of binary data or text.

Dim objStream As ADODB.Stream
objStream.Type = 1
objStream.LoadFromFile path

Dim Number : Number = BytesToNumEx(objStream.Read 8, 1, 8, False)

You'll need the following function though:

Function BytesToNumEx(ByteArray(), StartRec, EndRec, UnSigned) 
    Dim i
    Dim lng256 : lng256 = 1
    Dim lngReturn : lngReturn = 0

    If EndRec < 1 Then
        EndRec = UBound(ByteArray)
    End If

    If StartRec > EndRec Or StartRec < 0 Then
        BytesToNumEx = -1
        Exit Function
    End If

    lngReturn = lngReturn + (ByteArray(StartRec))
    For i = (StartRec + 1) To EndRec
        lng256 = lng256 * 256
        If i < EndRec Then
            lngReturn = lngReturn + (ByteArray(i) * lng256)
        Else
            If ByteArray(i) > 127 And UnSigned = False Then
             lngReturn = (lngReturn + ((ByteArray(i) - 256) * lng256))
            Else
                lngReturn = lngReturn + (ByteArray(i) * lng256)
            End If
        End If
    Next 

    BytesToNumEx = lngReturn
End Function
TTT
I can already do that bit (getting the 8 bytes). What I want to do is get it as a real, i.e. I want to be able to write "Response.Write (RealNumber) and see the real number displayed.
+1  A: 

Look at BitConverter.ToDouble().

In an ASP.NET page, this could look like:

<%@ Page Language="JScript"
    AutoEventWireup="true"
    CodeBehind="Default.aspx.cs"
    Inherits="WebApplication1._Default" %>
<%
    var bytes: byte[] = [0x94, 0x0e, 0x4c, 0xca, 0xc2, 0x97, 0xad, 0x53];
    var d = BitConverter.ToDouble(bytes, 0);
    Response.Write(d);
%>

Which gets you the output:

1.2345678E+95

(You can check for correctness at http://babbage.cs.qc.edu/IEEE-754/)

Oren Trutner
looks perfect. but does JScript have toDouble...doesn't seem to...
There seems to be a wealth of stuff in cs for getting to and from various number formats, but all the source I can find on Google Code is just wrappers for library routines. I guess I'm looking at cutting some JS to do a lot of arithmetic. Shame, when the number format within JScript is almost certainly the same as what I an starting with. If there any way of "typecasting" my eight byte array on top of the double variable (I guess not, 'cos JScript arrays aren't true arrays anyhow)?
Hmm, didn't realize you needed JScript code. I modified the answer to server-side JScript. If you need client-side javascript, the .NET BCL will indeed not be available; you will then need to parse the IEEE 754 floating point double precision number from its bits. See http://steve.hollasch.net/cgindex/coding/ieeefloat.html.
Oren Trutner
The current code is actually Classic ASP. Your code failed on my server (as "test.aspx") with "Parser Error Message: Could not load type 'WebApplication1._Default'." I removed that line and - voila! - it seems to work - but can I access that function through classic ASP?
Well, this is asp.net. Classic ASP is indeed a travel down memory lane. And no, unfortunately this wouldn't work in classic ASP. If that is the case, you may indeed need to parse out the double on your own. As far as I know, jscript does not have any built-in notion of casting a byte array into a float.
Oren Trutner
+1  A: 

Thanks Oren for your help. The babbage stuff was particularly useful. For what it's worth here the code I had to write (not thoroughly tested for anything other than norms):

function ReadFileDouble (Stream)
{ 
var Bytes0To3 = ReadFileLongword (Stream) ;
var Bytes4To5 = ReadFileWord (Stream) ;
var Bytes6To7 = ReadFileWord (Stream) ;

var Mantissa = Bytes0To3 + (Bytes4To5 * 65536 * 65536) + ((Bytes6To7 & 0x0F) * 65536 * 65536 * 65536) ;
var Fraction = Mantissa / 0x0010000000000000 ;
var Exponent = ((Bytes6To7 >>> 4) & 0x07FF) ;
var SignBit  = ((Bytes6To7 & 0x8000) != 0) ;
if (SignBit)
    {
    Sign = -1 ;
    }
else
    {
    Sign = +1 ;
    }    

var Bias     = 1023 ;

if (Exponent == 0)
    {
    if (Mantissa == 0)
        {
        return (0.00 * Sign) ;
        }
    else
        {
        return ((Fraction * (Math.pow (2.0, - Bias + 1))) * Sign) ;
        }        
    }
else if (Exponent == 1023)
    {
    if (Mantissa == 0)
        {
        return (Number.POSITIVE_INFINITY * Sign) ;
        }
    else if (Mantissa < 0x0008000000000000)
        {
        return (Number.NaN * Sign) ;
        }
    else
        {
        return (Number.NaN * Sign) ;
        }        
    }    
else 
    {
    return ((1.0 + Fraction) * (Math.pow (2.0, Exponent - Bias)) * Sign) ;
    }    
}
+1. Parsing binary floating point in javascript -- neat!
Oren Trutner