Double to string, possible?

Everything else that doesn't fall into one of the other PB categories.
Justin
Addict
Addict
Posts: 956
Joined: Sat Apr 26, 2003 2:49 pm

Double to string, possible?

Post by Justin »

i use this function to get huge filesizes,
Procedure GetFileSize64(file$, *fs.DOUBLE_)
hfile.l = CreateFile_(file$, 0, 0, #NULL, #OPEN_EXISTING, #FILE_ATTRIBUTE_NORMAL, #NULL)

If hfile<>#INVALID_HANDLE_VALUE
*fs\l1 = GetFileSize_(hfile, @*fs\l2)
CloseHandle_(hfile)
ProcedureReturn *fs\l1
Else
ProcedureReturn #INVALID_FILE_SIZE
EndIf
EndProcedure
it is possible to turn the double into its string representation?, like
'2345645355332'
MrMat
Enthusiast
Enthusiast
Posts: 762
Joined: Sun Sep 05, 2004 6:27 am
Location: England

Post by MrMat »

I knocked this up which may work:

Code: Select all

Procedure.s Multiply(string.s, mult.l, power.l)
  answer.s = string
  If power < 0
    answer = "Power too small"
  ElseIf mult < 1 Or mult > 10
    answer = "Multiplier out of range"
  ElseIf mult = 10
    ext.s = Space(power)
    ReplaceString(ext, " ", "0", 2)
    answer = string + ext
  ElseIf mult > 1 And power <> 0
    For powloop = 1 To power
      answer = ""
      lenstr.l = Len(string)
      carry.l = 0
      For loopy = lenstr To 1 Step -1
        value.l = Val(Mid(string, loopy, 1))
        value * mult
        value + carry
        carry = value / 10
        answer = Str(value % 10) + answer
      Next
      If carry <> 0
        answer = Str(carry) + answer
      EndIf
      string = answer
    Next
  EndIf
  ProcedureReturn answer
EndProcedure

Procedure.s Addition(str1.s, str2.s)
  answer.s = ""
  len1.l = Len(str1)
  len2.l = Len(str2)
  If len1 > len2
    prefix.s = Space(len1-len2)
    ReplaceString(prefix, " ", "0", 2)
    str2 = prefix + str2
  ElseIf len1 < len2
    prefix.s = Space(len2-len1)
    ReplaceString(prefix, " ", "0", 2)
    str1 = prefix + str1
  EndIf
  carry.l = 0
  For loopy = Len(str1) To 1 Step -1
    value.l = Val(Mid(str1, loopy, 1)) + Val(Mid(str2, loopy, 1)) + carry
    carry = value / 10
    answer = Str(value % 10) + answer
  Next
  If carry <> 0
    answer = Str(carry) + answer
  EndIf
  ProcedureReturn answer
EndProcedure

Procedure.s MemToStr(*mem, lenbytes.l)
  string.s = "0"
  For loopy = 0 To lenbytes - 1
    value.l = PeekB(*mem + loopy) & $FF
    string = Addition(string, Multiply(Str(value), 2, 8 * loopy))
  Next
  ProcedureReturn string
EndProcedure

#INVALID_FILE_SIZE = $FFFFFFFF

Procedure GetFileSize64(file$, *fs.LARGE_INTEGER)
  hfile.l = CreateFile_(file$, 0, 0, #NULL, #OPEN_EXISTING, #FILE_ATTRIBUTE_NORMAL, #NULL)
  
  If hfile<>#INVALID_HANDLE_VALUE
    *fs\lowpart = GetFileSize_(hfile, @*fs\highpart)
    CloseHandle_(hfile)
    ProcedureReturn *fs\lowpart
  Else
    ProcedureReturn #INVALID_FILE_SIZE
  EndIf
EndProcedure

filename.s = OpenFileRequester("", "", "", 0)
If filename <> ""
  GetFileSize64(filename, @fs.LARGE_INTEGER)
  Debug(MemToStr(@fs, SizeOf(LARGE_INTEGER)))
EndIf
It's very inefficient and only briefly tested but it seems ok!
Mat
Justin
Addict
Addict
Posts: 956
Joined: Sat Apr 26, 2003 2:49 pm

Post by Justin »

it seems to work, i think there is an easier way using some variant arithmetic api calls, i'll post it if i get it to work. thanks
MrMat
Enthusiast
Enthusiast
Posts: 762
Joined: Sun Sep 05, 2004 6:27 am
Location: England

Post by MrMat »

It looks like Pupil has written some far superior code to mine that does what you want:
viewtopic.php?t=5223
Mat
jack
Addict
Addict
Posts: 1358
Joined: Fri Apr 25, 2003 11:10 pm

Post by jack »

Justin wrote:Just a workaround to display filesizes >2gb as strings due to the lack of doubles

Code: Select all

#INVALID_FILE_SIZE = $FFFFFFFF

Structure DOUBLE_
	l1.l
	l2.l
EndStructure 

Procedure GetFileSize64(file$, *fs.DOUBLE_)
	hfile.l = CreateFile_(file$, #GENERIC_READ, 0, #NULL, #OPEN_EXISTING, #FILE_ATTRIBUTE_NORMAL, #NULL)

	If hfile<>#INVALID_HANDLE_VALUE
		*fs\l1 = GetFileSize_(hfile, @*fs\l2)
		CloseHandle_(hfile)
		ProcedureReturn *fs\l1
	Else
		ProcedureReturn #INVALID_FILE_SIZE 
	EndIf 
EndProcedure 

Procedure.s GetFileSize64Str(file$)
	If GetFileSize64(file$, @fs.DOUBLE_)<>#INVALID_FILE_SIZE 
		sz$ = Space(100)
		If StrFormatByteSize64_(fs\l1, fs\l2, @sz$, 100)
			ProcedureReturn sz$
		Else
			ProcedureReturn ""
		EndIf 
	Else
		ProcedureReturn ""
	EndIf 
EndProcedure 

file$ = OpenFileRequester("", "", "", 0)
If file$
	Debug GetFileSize64Str(file$)
EndIf 
in Windows you can use msvcrt.dll, example.

Code: Select all

Structure DOUBLE_ 
   l1.l 
   l2.l 
EndStructure 

y.DOUBLE_
b.s="2345645355332"

#LIB=0

OpenLibrary(#LIB,"msvcrt.dll") 
  y\l1=CallCFunction(#LIB,"_atoi64",b);convert string to I64, result in EAX,EDX
  ;y\l1 already has the value of EAX, so we are free to use the register EAX 
  ;now store the value in EDX into y\l2                                     
  ! lea eax,[v_y]
  ! mov dword [eax+4],edx ;y\l2=edx     
  a.s=Space(100)
  #radix=10  
  ;now convert 64bit integer back to string in a  
  CallCFunction(#LIB,"_ui64toa",y\l1,y\l2,a,#radix)
  Debug a    
CloseLibrary(#LIB)
Last edited by jack on Mon Jun 13, 2005 12:38 pm, edited 1 time in total.
Justin
Addict
Addict
Posts: 956
Joined: Sat Apr 26, 2003 2:49 pm

Post by Justin »

Great, _ui64toa does what i need. the only problem is you need to use openlibrary(), there is some PB bug with api calls that use '_' , you can't use the dll importer. thanks

Edit: i think the bug comes from functions that have ansi/unicode versions
_ui64toa / _ui64tow
jack
Addict
Addict
Posts: 1358
Joined: Fri Apr 25, 2003 11:10 pm

Post by jack »

The solutions of MrMat or Pupil are probably the way to go, mine was more of a curiosity.
on that note you can use sprintf but your are limited to signed int64.

Code: Select all

Structure DOUBLE_ 
   l1.l 
   l2.l 
EndStructure 

y.DOUBLE_ 
n.s="9223372036854775807" ;maximum positive integer 

#LIB=0 

OpenLibrary(#LIB,"msvcrt.dll")

  y\l1=CallCFunction(#LIB,"_atoi64",n);convert string to I64, result in EAX,EDX 
  ;y\l1 already has the value of EAX, so we are free to use the register EAX 
  ;now store the value in EDX into y\l2                                      
  ! lea eax,[v_y] 
  ! mov dword [eax+4],edx ;y\l2=edx 
  ;get the string length required by passing "0" where string argument should be.  
  StrLength.l=CallCFunction(#LIB,"sprintf",0,"%I64d",y\l1,y\l2)       
  a.s=Space(StrLength) 
  ;now convert 64bit integer back to string in a  
  CallCFunction(#LIB,"sprintf",a,"%I64d",y\l1,y\l2)
  ;get the string length required by passing "0" where string argument should be.   
  StrLength=CallCFunction(#LIB,"sprintf",0,"%I64X",y\l1,y\l2)
  b.s=Space(StrLength)    
  CallCFunction(#LIB,"sprintf",b,"%I64X",y\l1,y\l2)  
  
  Debug a 
  Debug b+"        in hexadecimal"      
CloseLibrary(#LIB) 
Last edited by jack on Tue Jun 14, 2005 12:21 pm, edited 3 times in total.
Justin
Addict
Addict
Posts: 956
Joined: Sat Apr 26, 2003 2:49 pm

Post by Justin »

about the dll importer bug, maybe doesn't work because i think the function must be called in C style. using CallFunction() inside a procedure crashes, while CallCFunction() works
jack
Addict
Addict
Posts: 1358
Joined: Fri Apr 25, 2003 11:10 pm

Post by jack »

Justin wrote:about the dll importer bug, maybe doesn't work because i think the function must be called in C style. using CallFunction() inside a procedure crashes, while CallCFunction() works
yes, you are right, thanks for pointing it out. :)
I updated my 2 posts above, just in case someone decides to use that example.
User avatar
GedB
Addict
Addict
Posts: 1313
Joined: Fri May 16, 2003 3:47 pm
Location: England
Contact:

Post by GedB »

If it's for your own consumption then you can keep things simple by working in Hex.

Then you just need to use Hex() on the two longs and put the strings together.
Post Reply