Category: Programming

(PB) Loading CSV directly to a Hash Map

Posted by on February 21, 2013

When dealing with string maps, being able to easily load them from a file is a must. For example take language files for different local translations. The simplest, cleanest format would be CSV. The ideal data structure? — A hash map.

While trivial, this code will come in handy for many other things!

EnableExplicit
#CSV_QUOTE 	= "'"
#CSV_SEPARATOR 	= ","
 
Procedure IsEvenNumber(N)
   ProcedureReturn ( 1 - 1 & N )
EndProcedure
 
Procedure IsOddNumber(N)
   ProcedureReturn ( 1 & N )
EndProcedure 
 
Procedure.s RemoveQuotes( String.s )
 
	If Left(String, 1) = #CSV_QUOTE
		String = Mid( String, 2 )
	EndIf
	If Right(String, 1) = #CSV_QUOTE
		String = Left( String, Len(String) - 1 )
	EndIf
 
	ProcedureReturn String
EndProcedure
 
Procedure.i LoadStringMap( FileName.s, Map StringMap.s() )
	; escaping of quotes is currently not supported
	; if an uneven number of quotes is found on a line, the line is ignored.
 
	Define.i fp = ReadFile( #PB_Any, FileName )
	If IsFile(fp)
 
		While Not Eof(fp)
 
			Define.s line = Trim(ReadString( fp ))
			If line
				If CountString( line, #CSV_SEPARATOR ) => 1
 
					Define.i quote_count = CountString( line, #CSV_QUOTE )
					If IsEvenNumber( quote_count )
 
						Define.s key		= RemoveQuotes( StringField( line, 2, #CSV_QUOTE ) ) 
						Define.s content	= RemoveQuotes( StringField( line, 4, #CSV_QUOTE ) )
 
						StringMap( key ) 	= content
 
					EndIf
 
				EndIf
			EndIf
 
		Wend
 
		CloseFile(fp)
		ProcedureReturn MapSize( StringMap() )
	EndIf
 
EndProcedure

Example of data:

'Update', 'Actualizar'
'Databases', 'Bases de datos'
'Program', 'Programa'
'Options', 'Opciones'
'Export', 'Exportar'

Example of use:

NewMap spanish.s()
LoadStringMap( "locale/spanish.csv", spanish() )
 
ForEach spanish()
 
	Debug MapKey(spanish())
	Debug spanish()
 
Next

Couldn’t be easier!
Cheers.

(SQLITE) When duplicate tables are needed…

Posted by on February 5, 2013

Here’s a quick tip if you want to keep a “schema” or “template” table on your database that you’ll then duplicate to populate with arbitrary data. This system works for collection of files where a particular table could represent a specific drive or medium, just as an example of the many uses it can have.

CREATE TABLE 'new_table' AS SELECT * FROM 'schema'; -- where 'schema' is our template table.

This is basic SQL, but if you were to look up how to duplicate a Sqlite table you may come up short if you aren’t aware of standard SQL. As an exercise, here’s how Sqlite interprets the CREATE command.
A few restrictions could be applied to your SELECT statement, this will depend on your particular requirements.

As always, don’t forget to sanitize every input and when possible, remove user interaction altogether from the query — specially during the construction phase.

Cheers

(PB) Using the Thinkpad Accelerometer

Posted by on January 29, 2013

So I recently got a proper Thinkpad and I was wondering how to interface with the accelerometer to obtain data from it. First of all, I had a look around and it seems the ADXL320 is used in most models, it’s a Low Power, 3-Axis ±5 g MEMS Accelerometer manufactured by Analog Devices.

There are, at least on Windows, two possible interfaces. One is through a device manager, the other is directly through a DLL exposed by Lenovo.

I had yet another look around and found a few snippets in C# by Ben Suter. Decided to port the code and give it a go, instead of looking any further. Despite the fact that I had already exported the function names of the DLL (using my good ol’ dllspyr) I just couldn’t bother looking any further. I had to add the z value, since it was originally ignored. Perhaps because previously a mere 2 axis tilt sensor was used?

The other method involves getting a handle of “ShockMgr” with createFile(); setting up by DeviceIoControl(); and then reading through the data. This makes it easier to validate if the “service” is available, because the DLL could be exposed but non functional, for example.

Da codez:

Here’s the preliminary test code, implementing a crude alarm system:

Structure ACCDATA
  status.i
  x.w
  y.w
  z.w
EndStructure
 
Structure SHOCKSTATUS
  status.i
EndStructure
 
Enumeration 
  #SHOCKSTATUS_RUNNING
  #SHOCKSTATUS_STOPPED
  #SHOCKSTATUS_AUTOIGNORE
  #SHOCKSTATUS_UNDEFINED
EndEnumeration
 
Prototype.i pShockproofGetAccelerometerData( *AccData.ACCDATA )
Prototype.i pShockproofGetShockStatus( *ShockStatus.SHOCKSTATUS )
 
 
If OpenLibrary(0, "Sensor.dll")
 
  ShockproofGetAccelerometerData.pShockproofGetAccelerometerData = GetFunction(0, "ShockproofGetAccelerometerData")
  ShockproofGetShockStatus.pShockproofGetShockStatus = GetFunction(0, "ShockproofGetShockStatus")
 
  Define.ACCDATA old_data, new_data
  ShockproofGetAccelerometerData( old_data )
 
  Define.i triggered = #False
  Repeat
 
    Delay(200)
 
    ShockproofGetAccelerometerData( new_data )
 
    If Not CompareMemory( old_data, new_data, SizeOf(ACCDATA) ) Or triggered
      triggered = #True
      Beep_(1000, 1000)
    EndIf
 
  ForEver
 
  CloseLibrary(0)
EndIf

The status code is interpreted by another function, which I’m not using at the moment but the author had guessed the threshold values and addressed a name for each, from the known possible states exposed by Lenovo.

Procedure.i convertStatusCode( statusCode.i )
 
  If statusCode >= 0 And statusCode < = 4
    ProcedureReturn #SHOCKSTATUS_RUNNING
  ElseIf statusCode = 8 Or statusCode = 9
    ProcedureReturn #SHOCKSTATUS_STOPPED
  ElseIf statusCode = 13
    ProcedureReturn #SHOCKSTATUS_AUTOIGNORE
  Else
    ProcedureReturn #SHOCKSTATUS_UNDEFINED
  EndIf
 
EndProcedure

What now?

I’m going to clean up the code and start making use of this feature, I mean, why not?

As for a proper alarm, you’d have to manage the mute and volume settings plus instead of comparing against the baseline values you’d have to implement a threshold. I’m aware that they’ve issued an application that does exactly this, but I’m not a fan of big resident bloatware — plus where’s the fun in that?

Anyway, that’s all for now!
Cheers.

Sony Vaio Bios Unlock Code / Algorithm

Posted by on January 16, 2013

What, when?

I wrote this about 3-4 years ago, we had a discussion on IRC with a couple friends about how pathetic some algorithms are as I showed the reference code from a Sony Vaio bios. We had two pairs of codes and that was enough to reverse the algorithm, the pattern clearly emerged with this minuscule sample size which goes to show just how simple some algorithms out there really are.

At the time that piece of code was actually valuable, I could’ve sold the unlock service to people (like a few weasels began to afterwards…) but being the kind that would rather avoid legal issues, I simply put it on the back-burner.

Legal issues?

Well, I didn’t want any trouble with Sony. I did email them, nobody ever replied. So that’s as far as I got. I guess they would rather ignore certain problems than to face them — it ought to be cheaper…

Show me the code!

OK, Since I’m sure by now the relevance of the code has decreased and thus it’s value, and perhaps someone else already decided to post it after reversing it… (don’t know, haven’t checked — don’t care) I’m posting it here so any remaining weasels cease to profit from it.

;Sony Vaio Bios Unlock Calculator
;www.gushh.net
 
; input is numeric 7 digits, we only trim and obtain the left 7 digits as input sanitation.
Define.s input	= Left( Trim(InputRequester( "input code", "", "" )), 7 )
Define.s output	= ""
Define.i i
 
Dim buffer.i(6)
For i=0 To 6 ; extract the characters from the input string onto the working buffer
	buffer(i) = Val( Mid( input, i + 1, 1 ) )
Next
 
;10 8 7 12 11 12 16 ;- the magic pattern, reminds me of LOST...
 
Dim LUT.i(6) ; input the LUT
		LUT(0) = 10
		LUT(1) = 8
		LUT(2) = 7
		LUT(3) = 12
		LUT(4) = 11
		LUT(5) = 12
		LUT(6) = 16
 
For i=0 To 6 ; offset the buffer contents based on the LUT
	buffer(i) = LUT(i) - buffer(i)
Next
 
For i=0 To 6 ; generate the output string
	output + Right( Str( buffer(i) ), 1)
Next
 
; display it
MessageRequester( "result", output )

I’ll let it up to you to figure out the language and how to compile it. If you know other languages, porting it will be trivial. If you are not a programmer, send me a message and we’ll figure something out — I’m not going to upload / send any executables, sorry.

As an exercise, can you actually come up with the look-up table just by looking at these two pairs of numbers?

9876543 = 1006683
2335568 = 8547668

Which Vaio models?

Ah, good question… Turns out, it’s been a long time and I lost the pertinent details, can you come up with a list of supported models? — If it worked for your Vaio, maybe consider buying me a coffee?

Do you have more?

Actually yes, we broke a few other algorithms back then. But I won’t post it all at once. I am however willing to take a challenge — Just let me know. I may consider adding a live calculator to the page if someone requests it.
 
That’s all for now, cheers.
 

Embedding Python in PureBasic – Part 2

Posted by on December 25, 2012

Alright, so we were able to define a statement, run it and obtain the result within PB using Python on the previous tutorial, now let’s try to modify a Python variable, in this case a long, from within PB!

The code is pretty much the same, but we’ve “imported” three extra functions to do the job. First we define our variable, instead of relying on it already being defined/instanced. Then we execute the script and finally read the results.

Import "python33.lib"
	Py_Initialize()
	Py_Finalize()
	PyRun_SimpleString( String.s )
	PyImport_AddModule( String.s )
	PyModule_GetDict( *PyModule.i )
	PyDict_GetItemString( *PyObject.i, Key.s )
	PyLong_AsLong( *PyObject.i )
	
	PyLong_FromLong( Var.l )
	PyDict_SetItemString( *PyObject.i, Key.s, *Content.i )
	Py_DecRef( *PyObject.i )
EndImport

Define.i *module, *dictionary, *retval, *longvar

If Py_Initialize()
	*module	= PyImport_AddModule("__main__") ; Obtain a reference from main
	If *module ; Did we get a reference to main?
		*dictionary = PyModule_GetDict(*module) ; Let's get a reference of it's dictionary then.
		If *dictionary
			*longvar = PyLong_FromLong(100) ; new instance of a pylong set to 100
			If *longvar
				
				PyDict_SetItemString( *dictionary, "retval", *longvar ) ; set the long to "retval", this initializes the variable.
				Py_DecRef(*longvar) ; decrease the reference count (since we instanced it and Python uses a GC)
				
				PyRun_SimpleString( "retval += 100" ) ; now let's execute our statement, this time we add 100 to retval, which was set to 100 in PB!
				
				*retval = PyDict_GetItemString(*dictionary, "retval")
				If *retval
					Debug PyLong_AsLong(*retval) ; should return 200, this function returns a long representation of *retval, which internally would be a PyLong in this case.
				EndIf
				
			EndIf
		EndIf
	EndIf
	
	Py_Finalize()
EndIf

In a real world application you would have one big script that would assume certain variables were already set or “initialized” by the host, and if not possibly set some defaults or assert in some way. That’s why we are initializing the variable first, then we execute the script and then we obtain the result.

Remember: There are many ways of achieving a goal, this is just one of them.

This method works fine for longs, but we’ve yet to talk about floats, strings and more complex data!

But for now…

Happy holidays!
Cheers.