Finally getting around to finishing my recipe manager. it looks either, isn't commercial quality but I don't care as it is for the family.
With that in mind, I asked InfraTec for help and he is helping me with anything import/xml related. Heck, he wrote all the importers himself except for one.
When all import routines work properly, I'll add them to the recipe program and release it.
In the meantime, here is the only importer that I was able to write myself, a BigOven CRB books to SQLite database (for my recipe book format) in case anyone has a use for the code.
Code: Select all
; Author: Fangbeast (MGB Technical Solutions) 2015
; 
; License: Do whatever you want with it except claim that it is yours. You may never, ever sell it.
; 
; Credits; Bernd Krüger-Knauber (InfraTec) for fixing a lot of my blob, import mistakes and just about ever other program that I had issues with.
; People underestimate his knowledge and help, he is a top bloke.
; 
Define EventID, MenuID, GadgetID, WindowID
Enumeration 1
  #Window_BigOvenToSqLite
EndEnumeration
#WindowIndex = #PB_Compiler_EnumerationValue
Enumeration 1
  #Gadget_BigOvenToSqLite_Recipeboxes
  #Gadget_BigOvenToSqLite_Numberofrecipeboxes
  #Gadget_BigOvenToSqLite_TItlelist
  #Gadget_BigOvenToSqLite_Numberoftitles
  #Gadget_BigOvenToSqLite_Numberofpictures
  #Gadget_BigOvenToSqLite_Numberofingredients
  #Gadget_BigOvenToSqLite_Convertpath
  #Gadget_BigOvenToSqLite_Databasename
  #Gadget_BigOvenToSqLite_Getdatabase
  #Gadget_BigOvenToSqLite_Getpath
  #Gadget_BigOvenToSqLite_Convert
  #Gadget_BigOvenToSqLite_Exitprogram
  #Gadget_BigOvenToSqLite_Errorlist
EndEnumeration
#GadgetIndex = #PB_Compiler_EnumerationValue
Procedure.i Window_BigOvenToSqLite()
  If OpenWindow(#Window_BigOvenToSqLite, 114, 68, 785, 715, "BigOven recipes to MGBRecipes", #PB_Window_SystemMenu|#PB_Window_ScreenCentered|#PB_Window_Invisible)
    ListIconGadget(#Gadget_BigOvenToSqLite_Recipeboxes, 5, 5, 160, 555, "Boxes", 156, #PB_ListIcon_FullRowSelect|#LVS_NOCOLUMNHEADER)
      SetGadgetColor(#Gadget_BigOvenToSqLite_Recipeboxes, #PB_Gadget_BackColor, $DBDBDB)
      SetGadgetFont(#Gadget_BigOvenToSqLite_Recipeboxes, LoadFont(#Gadget_BigOvenToSqLite_Recipeboxes, "Comic Sans MS", 10, 0))
    StringGadget(#Gadget_BigOvenToSqLite_Numberofrecipeboxes, 5, 565, 160, 25, "", #PB_String_ReadOnly)
      SetGadgetColor(#Gadget_BigOvenToSqLite_Numberofrecipeboxes, #PB_Gadget_BackColor, $DBDBDB)
      SetGadgetFont(#Gadget_BigOvenToSqLite_Numberofrecipeboxes, LoadFont(#Gadget_BigOvenToSqLite_Numberofrecipeboxes, "Comic Sans MS", 10, 0))
    ListIconGadget(#Gadget_BigOvenToSqLite_TItlelist, 170, 5, 610, 555, "Titles", 596, #PB_ListIcon_FullRowSelect|#PB_ListIcon_AlwaysShowSelection|#LVS_NOCOLUMNHEADER)
      SetGadgetColor(#Gadget_BigOvenToSqLite_TItlelist, #PB_Gadget_BackColor, $DBDBDB)
      SetGadgetFont(#Gadget_BigOvenToSqLite_TItlelist, LoadFont(#Gadget_BigOvenToSqLite_TItlelist, "Comic Sans MS", 10, 0))
    StringGadget(#Gadget_BigOvenToSqLite_Numberoftitles, 170, 565, 200, 25, "", #PB_String_ReadOnly)
      SetGadgetColor(#Gadget_BigOvenToSqLite_Numberoftitles, #PB_Gadget_BackColor, $DBDBDB)
      SetGadgetFont(#Gadget_BigOvenToSqLite_Numberoftitles, LoadFont(#Gadget_BigOvenToSqLite_Numberoftitles, "Comic Sans MS", 10, 0))
    StringGadget(#Gadget_BigOvenToSqLite_Numberofpictures, 375, 565, 200, 25, "", #PB_String_ReadOnly)
      SetGadgetColor(#Gadget_BigOvenToSqLite_Numberofpictures, #PB_Gadget_BackColor, $DBDBDB)
      SetGadgetFont(#Gadget_BigOvenToSqLite_Numberofpictures, LoadFont(#Gadget_BigOvenToSqLite_Numberofpictures, "Comic Sans MS", 10, 0))
    StringGadget(#Gadget_BigOvenToSqLite_Numberofingredients, 580, 565, 200, 25, "", #PB_String_ReadOnly)
      SetGadgetColor(#Gadget_BigOvenToSqLite_Numberofingredients, #PB_Gadget_BackColor, $DBDBDB)
      SetGadgetFont(#Gadget_BigOvenToSqLite_Numberofingredients, LoadFont(#Gadget_BigOvenToSqLite_Numberofingredients, "Comic Sans MS", 10, 0))
    StringGadget(#Gadget_BigOvenToSqLite_Convertpath, 5, 595, 775, 25, "", #PB_String_ReadOnly)
      SetGadgetColor(#Gadget_BigOvenToSqLite_Convertpath, #PB_Gadget_BackColor, $DBDBDB)
      SetGadgetFont(#Gadget_BigOvenToSqLite_Convertpath, LoadFont(#Gadget_BigOvenToSqLite_Convertpath, "Comic Sans MS", 10, 0))
    StringGadget(#Gadget_BigOvenToSqLite_Databasename, 5, 625, 775, 25, "", #PB_String_ReadOnly)
      SetGadgetColor(#Gadget_BigOvenToSqLite_Databasename, #PB_Gadget_BackColor, $DBDBDB)
      SetGadgetFont(#Gadget_BigOvenToSqLite_Databasename, LoadFont(#Gadget_BigOvenToSqLite_Databasename, "Comic Sans MS", 10, 0))
    ButtonGadget(#Gadget_BigOvenToSqLite_Getdatabase, 5, 655, 190, 25, "Open database")
      SetGadgetFont(#Gadget_BigOvenToSqLite_Getdatabase, LoadFont(#Gadget_BigOvenToSqLite_Getdatabase, "Comic Sans MS", 10, 0))
    ButtonGadget(#Gadget_BigOvenToSqLite_Getpath, 200, 655, 190, 25, "Get path")
      SetGadgetFont(#Gadget_BigOvenToSqLite_Getpath, LoadFont(#Gadget_BigOvenToSqLite_Getpath, "Comic Sans MS", 10, 0))
    ButtonGadget(#Gadget_BigOvenToSqLite_Convert, 395, 655, 190, 25, "Convert now")
      SetGadgetFont(#Gadget_BigOvenToSqLite_Convert, LoadFont(#Gadget_BigOvenToSqLite_Convert, "Comic Sans MS", 10, 0))
    ButtonGadget(#Gadget_BigOvenToSqLite_Exitprogram, 590, 655, 190, 25, "Exit program")
      SetGadgetFont(#Gadget_BigOvenToSqLite_Exitprogram, LoadFont(#Gadget_BigOvenToSqLite_Exitprogram, "Comic Sans MS", 10, 0))
    StringGadget(#Gadget_BigOvenToSqLite_Errorlist, 5, 685, 775, 25, "", #PB_String_ReadOnly)
      SetGadgetColor(#Gadget_BigOvenToSqLite_Errorlist, #PB_Gadget_BackColor, $DBDBDB)
      SetGadgetFont(#Gadget_BigOvenToSqLite_Errorlist, LoadFont(#Gadget_BigOvenToSqLite_Errorlist, "Comic Sans MS", 10, 0))
    HideWindow(#Window_BigOvenToSqLite, 0)
    ProcedureReturn WindowID(#Window_BigOvenToSqLite)
  EndIf
EndProcedure
; My generic includes
Declare.s CountRecords(QueryString.s)
Declare.s DatabaseLastInsertRowId()
Declare.s KillQuote(Instring.s)
Declare   LastLine(Gadget.i, LineNumber.i)
Declare.s MakeSureDirectoryPathExists(Directory.s)
Declare   OpenOtherDatabase()
Declare   OpenSystemDatabase()
Declare.s RepQuote(Instring.s)
Declare.s TextToXML(TextString.s)
Declare.s XMLToText(XMLString.s)
; Custom includes
Declare   ConvertBigOvenToSqLite(CurrentFile.s)
Declare   GetConvertPath()
Declare   SearchEngine(SearchDirectory.s)
; Need a unicode aware version of the API directory creator
Import "shell32.lib"                                                                                ; 
  SHCreateDirectory(*hwnd, pszPath.p-unicode)                                                        ; 
EndImport                                                                                           ; 
; 
UseJPEG2000ImageDecoder()                                                                           ; PureBasic native image decoder
UseJPEGImageDecoder()                                                                               ; PureBasic native image decoder
UsePNGImageDecoder()                                                                                ; PureBasic native image decoder
UseTGAImageDecoder()                                                                                ; PureBasic native image decoder
UseTIFFImageDecoder()                                                                               ; PureBasic native image decoder
; 
UseODBCDatabase()                                                                                   ; 
UseSQLiteDatabase()                                                                                 ; 
; 
#ODBC_ADD_DSN                       =   1 ; Add Data source
#ODBC_ADD_SYS_DSN                   =   4 ; Add SYSTEM Data source
#ODBC_CONFIG_DSN                    =   2 ; Configure (edit) Data source
#ODBC_REMOVE_DSN                    =   3 ; Remove Data source
#ODBC_REMOVE_SYS_DSN                =   6 ; Remove SYSTEM Data source
#SQL_SUCCESS                        =   0
#SQL_SUCCESS_WITH_INFO              =   1
#SQL_ERROR                          =  -1
#SQL_INVALID_HANDLE                 =  -2
#SQL_NO_DATA                        = 100
#SQL_MAX_MESSAGE_LENGTH             = 512
#SQL_NTS                            =  -3
#SQL_HANDLE_ENV                     =   1;?
#SQL_HANDLE_DBC                     =   2;?
#SQL_HANDLE_STMT                    =   3
#SQL_HANDLE_DESC                    =   4;?
#SQL_C_CHAR                         =   1
#ODBC_ERROR_GENERAL_ERR             =   1
#ODBC_ERROR_INVALID_BUFF_LEN        =   2
#ODBC_ERROR_INVALID_HWND            =   3
#ODBC_ERROR_INVALID_STR             =   4
#ODBC_ERROR_INVALID_REQUEST_TYPE    =   5
#ODBC_ERROR_COMPONENT_NOT_FOUND     =   6
#ODBC_ERROR_INVALID_NAME            =   7
#ODBC_ERROR_INVALID_KEYWORD_VALUE   =   8
#ODBC_ERROR_INVALID_DSN             =   9
#ODBC_ERROR_INVALID_INF             =  10
#ODBC_ERROR_REQUEST_FAILED          =  11
#ODBC_ERROR_INVALID_PATH            =  12
#ODBC_ERROR_LOAD_LIB_FAILED         =  13
#ODBC_ERROR_INVALID_PARAM_SEQUENCE  =  14
#ODBC_ERROR_INVALID_LOG_FILE        =  15
#ODBC_ERROR_USER_CANCELED           =  16
#ODBC_ERROR_USAGE_UPDATE_FAILED     =  17
#ODBC_ERROR_CREATE_DSN_FAILED       =  18
#ODBC_ERROR_WRITING_SYSINFO_FAILED  =  19
#ODBC_ERROR_REMOVE_DSN_FAILED       =  20
#ODBC_ERROR_OUT_OF_MEM              =  21
#ODBC_ERROR_OUTPUT_STRING_TRUNCATED =  22
; My personal constants - Program details etc
#Author                         = "Miklos G Bolvary"                                                ; Author's name
#CopyRight                      = "MGB Technical Services 2015 "                                    ; Copyright holder
#Basename                       = "OvenConvert "                                                    ; Base name for ini and dataabse
#Version                        = "v0.00 "                                                          ; Program version
#Program                        = #Basename + #Version                                              ; Copyright string
#Eol                            = Chr(13) + Chr(10)                                                 ; End of line marker
#Fish                           = "<°)))o><²³  "                                                    ; My favourite fish!!
#Traynote                       = #Basename + #Version                                              ; Copyright string
; My personal constants - Program constants that don't need to change
#AtTheEndOfTheList              = -1                                                                ; 
#NoPictureHandle                = 0                                                                 ; 
#NoFileHandle                   = 0                                                                 ; 
#NoFileFound                    = -1                                                                ; 
#NoXMLNodeHandle                = 0                                                                 ; 
#NoBlobFound                    = 0                                                                 ; 
#NoDataFound                    = 0                                                                 ; 
#NoBufferDataFound              = 0                                                                 ; 
#NothingEncoded                 = 0                                                                 ; 
#NothingDecoded                 = 0                                                                 ; 
#NothingSelected                = -1                                                                ; 
#NothingFound                   = 0                                                                 ; 
#NoItems                        = 0                                                                 ; 
#FirstItem                      = 0                                                                 ; 
#EmptyString                    = ""                                                                ; 
#DatabaseQueryFail              = 0                                                                 ; 
#DatabaseUpdateFail             = 0                                                                 ; 
#DatabaseOpenFail               = 0                                                                 ; 
#NotEndOfFile                   = 0                                                                 ; 
; 
Structure ProgramData
  ; Program flags
  QuitValue.i                                                                                       ; 
  ConvertPath.s                                                                                     ; 
  
  ; BigOven specific
  Numberofrecipeboxes.i                                                                             ; 
  Numberoftitles.i                                                                                  ; 
  Numberofpictures.i                                                                                ; 
  Numberofingredients.i                                                                             ; 
  
  ; Database specific
  DatabaseHandle.i                                                                                  ; Handle to the current database
  DatabaseDirectory.s                                                                               ; Directory for the database
  DatabaseName.s                                                                                    ; Current path and name of the system database
  
  ; Directory directives
  CurrentDirectory.s                                                                                ; The current program startup directory
  TemporaryDirectory.s                                                                              ; Temporary files directory
  
  CrbPassword.s                                                                                     ; 
  
  Configfile.s                                                                                      ; 
  LastDatabase.s                                                                                    ; 
  LastConvertPath.s                                                                                 ; 
EndStructure
; 
Global Program.ProgramData                                                                         ; 
Global NewList FoundDirs.s()                                                                      ; List of recursed import directories
; 
Program\CrbPassword         = "mealpoint123"                                                        ; 
; Get working directories variables and create the physical dirs that go with them
Program\CurrentDirectory    = GetCurrentDirectory()                                                 ; Get the current directory name
; Setup the various system directory names and paths
Program\DatabaseDirectory   = Program\CurrentDirectory  + "Database\"                               ; Database directory
; Setup the various system file names and where they go.
Program\DatabaseName        = Program\DatabaseDirectory   + ReplaceString(#Basename, " ", "_") + #Version  +  ".Sqlite" ; Database name and path
; Setup the program config text file
Program\Configfile          = Program\CurrentDirectory + "Configfile.ini"                           ; 
; Create the directories if you can
MakeSureDirectoryPathExists(Program\DatabaseDirectory)                                              ; 
; Count the number of records in an SQLite database
Procedure.s CountRecords(QueryString.s)
  ; 
  If DatabaseQuery(Program\DatabaseHandle, QueryString.s)
    While NextDatabaseRow(Program\DatabaseHandle)
      Records.s = GetDatabaseString(Program\DatabaseHandle, 0)
    Wend
    ProcedureReturn Records.s
  EndIf
  ; 
EndProcedure
; Get the ID of the last inserted record
Procedure.s DatabaseLastInsertRowId()
  ; 
  If DatabaseQuery(Program\DatabaseHandle, "SELECT last_insert_rowid()")
    While NextDatabaseRow(Program\DatabaseHandle)
      RecordId.s = GetDatabaseString(Program\DatabaseHandle, 0)
    Wend
    FinishDatabaseQuery(Program\DatabaseHandle)
  EndIf
  ; 
  ProcedureReturn RecordId.s
  ; 
EndProcedure
; Kill double quotes in strings for display purposes
Procedure.s KillQuote(Instring.s)
  ; 
  ProcedureReturn ReplaceString(Instring.s, "''", "'", 1, 1)
  ; 
EndProcedure
; Go to the last line of a ListIconGadget
Procedure LastLine(Gadget.i, LineNumber.i)
  ; Make sure the current line is visible
  SendMessage_(GadgetID(Gadget.i), #LVM_ENSUREVISIBLE, LineNumber.i, 0)
  ; 
EndProcedure
; Need a unicode aware version of the API directory creator
Procedure.s MakeSureDirectoryPathExists(Directory.s)
  ; 
  ErrorCode.i = SHCreateDirectory(#Null, Directory.s)
  ; 
  Select ErrorCode.i
    Case #ERROR_SUCCESS               : Message.s ="Okay"                                           ; ResultCode = 0
    Case #ERROR_BAD_PATHNAME          : Message.s ="Bad directory path"                             ; ResultCode = 161
    Case #ERROR_FILENAME_EXCED_RANGE  : Message.s ="Directory path too long"                        ; ResultCode = 206
    Case #ERROR_FILE_EXISTS           : Message.s ="Directory already exists"                       ; ResultCode = 80
    Case #ERROR_ALREADY_EXISTS        : Message.s ="Directory already exists"                       ; ResultCode = 183
;   Case #ERROR_CANCELLED             : Message.s ="The user canceled the operation."                ; ResultCode = ??. Not defined in compiler residents
  EndSelect
  ; 
  ProcedureReturn Message.s
  ; 
  ; Debug MakeSureDirectoryPathExists("c:\1\2\3\4\5\6")
  ; 
EndProcedure
; Try to open the system database and create missing tables
Procedure OpenOtherDatabase()
  ; 
  DatabaseName.s = OpenFileRequester("Open database", Program\DatabaseName, "SQLite (*.sqlite)|*.sqlite", 0)
  ; 
  If DatabaseName.s <> #EmptyString
    ; 
    If Program\DatabaseHandle
      CloseDatabase(Program\DatabaseHandle)
    EndIf
    ; 
    Program\DatabaseHandle = OpenDatabase(#PB_Any, Program\DatabaseName, #EmptyString, #EmptyString, #PB_Database_SQLite)
    ; 
    If Program\DatabaseHandle <> #DatabaseOpenFail
      ; 
      Program\LastDatabase = DatabaseName.s
      ; 
    Else
      SetGadgetText(#Gadget_BigOvenToSqLite_Errorlist, "There was a problem attempting to open " + DatabaseName.s + ", could be corrupt or open by some other process.")
    EndIf 
    ; 
  Else
    SetGadgetText(#Gadget_BigOvenToSqLite_Errorlist, "User cancelled the database chooser, nothing to do.")
  EndIf
  ; 
EndProcedure
; Try to open the system database and create missing tables
Procedure OpenSystemDatabase()
  ; 
  FileHandle.i = OpenFile(#PB_Any, Program\DatabaseName)
  ; 
  If FileHandle.i
    ; 
    CloseFile(FileHandle.i)
    ; 
    Program\DatabaseHandle = OpenDatabase(#PB_Any, Program\DatabaseName, #EmptyString, #EmptyString, #PB_Database_SQLite)
    ; 
    If Program\DatabaseHandle <> #DatabaseOpenFail
      ; Turn on auto database vacuum
      If Not DatabaseUpdate(Program\DatabaseHandle, "PRAGMA auto_vacuum = on")                    ; 
        ;Debug "Could not setup auto database vacuum: " + DatabaseError()
      EndIf                                                                                       ; 
      ; Create the Recipes table
      DatabaseUpdate.s = "CREATE TABLE IF NOT EXISTS Recipes("                                    ; 
      DatabaseUpdate.s + "Recipetitle TEXT, "                                                     ; Title
      DatabaseUpdate.s + "Numberofservings TEXT, "                                                ; YieldText (YieldNumber not used)
      DatabaseUpdate.s + "Recipeauthor TEXT, "                                                    ; 
      DatabaseUpdate.s + "Categories TEXT, "                                                      ; PrimaryIngredient
      DatabaseUpdate.s + "Subcategories TEXT, "                                                   ; AllCategoriesText
      DatabaseUpdate.s + "Preparationtime TEXT, "                                                 ; 
      DatabaseUpdate.s + "Cookingtime TEXT, "                                                     ; 
      DatabaseUpdate.s + "Difficulty TEXT, "                                                      ; 
      DatabaseUpdate.s + "Recipeversion TEXT, "                                                   ; 
      DatabaseUpdate.s + "Recipesource TEXT, "                                                    ; Source
      DatabaseUpdate.s + "Copyright TEXT, "                                                       ; 
      DatabaseUpdate.s + "Cuisine TEXT, "                                                         ; Cuisine
      DatabaseUpdate.s + "Reciperating TEXT, "                                                    ; 
      DatabaseUpdate.s + "Importedfrom TEXT, "                                                    ; 
      DatabaseUpdate.s + "Authorcomments TEXT, "                                                  ; 
      DatabaseUpdate.s + "Instructions TEXT, "                                                    ; Instructions
      DatabaseUpdate.s + "Nutritionaldata TEXT, "                                                 ; 
      DatabaseUpdate.s + "Othercomments TEXT, "                                                   ; Notes
      DatabaseUpdate.s + "Deleted TEXT, "                                                         ; 
      DatabaseUpdate.s + "Updated TEXT, "                                                         ; 
      DatabaseUpdate.s + "Favourite TEXT, "                                                       ; 
      DatabaseUpdate.s + "Locked TEXT, "                                                          ; 
      DatabaseUpdate.s + "Recordid INTEGER PRIMARY KEY AUTOINCREMENT, "                           ; RecipeID
      DatabaseUpdate.s + "UNIQUE (Recipetitle, Instructions) ON CONFLICT FAIL)"                   ; 
      If DatabaseUpdate(Program\DatabaseHandle, DatabaseUpdate.s)                                 ; 
      Else                                                                                        ; 
        SetGadgetText(#Gadget_BigOvenToSqLite_Errorlist, "Could not create recipe table in database: " + DatabaseError()) ; 
      EndIf                                                                                       ; 
      ; Create the index table
      DatabaseUpdate.s = "CREATE INDEX IF NOT EXISTS RecipeIndex ON Recipes(Recipetitle)"         ; 
      If DatabaseUpdate(Program\DatabaseHandle, DatabaseUpdate.s)                                 ; 
      Else                                                                                        ; 
        SetGadgetText(#Gadget_BigOvenToSqLite_Errorlist, "Could not create index table in database: " + DatabaseError() ); 
      EndIf                                                                                       ; 
      ; Create the picture table
      DatabaseUpdate.s = "CREATE TABLE IF NOT EXISTS Pictures("                                   ; 
      DatabaseUpdate.s + "Pictureid INTEGER PRIMARY KEY AUTOINCREMENT, "                          ; PictureID
      DatabaseUpdate.s + "Picture BLOB, "                                                         ; 
      DatabaseUpdate.s + "Description TEXT, "                                                     ; 
      DatabaseUpdate.s + "Filename TEXT, "                                                        ; 
      DatabaseUpdate.s + "Recordid INTEGER, "                                                     ; 
      DatabaseUpdate.s + "FOREIGN KEY(Recordid) REFERENCES Recipes(Recordid) ON DELETE CASCADE)"  ; 
      If Not DatabaseUpdate(Program\DatabaseHandle, DatabaseUpdate.s)                             ; 
        SetGadgetText(#Gadget_BigOvenToSqLite_Errorlist, DatabaseUpdate.s  + "  --  "  + DatabaseError()) ; 
      EndIf                                                                                       ; 
      ; Create the ingredients table
      DatabaseUpdate.s = "CREATE TABLE IF NOT EXISTS Ingredients("                                ; 
      DatabaseUpdate.s + "Ingredientid INTEGER PRIMARY KEY AUTOINCREMENT, "                       ; IngredientLinesID
      DatabaseUpdate.s + "Unit TEXT, "                                                            ; TextQty
      DatabaseUpdate.s + "Measure TEXT, "                                                         ; Measure
      DatabaseUpdate.s + "Ingredient TEXT, "                                                      ; Name
      DatabaseUpdate.s + "Preparation TEXT, "                                                     ; PrepNotes
      DatabaseUpdate.s + "Lineorder TEXT, "                                                       ; LineOrder
      DatabaseUpdate.s + "Recordid INTEGER, "                                                     ; RecipeID
      DatabaseUpdate.s + "FOREIGN KEY(Recordid) REFERENCES Recipes(Recordid) ON DELETE CASCADE)"  ; 
      If DatabaseUpdate(Program\DatabaseHandle, DatabaseUpdate.s)                                 ; 
      Else                                                                                        ; 
        SetGadgetText(#Gadget_BigOvenToSqLite_Errorlist, "Could not create ingredients table: "  + DatabaseError()) ; 
      EndIf                                                                                       ; 
      ; 
    Else
      SetGadgetText(#Gadget_BigOvenToSqLite_Errorlist, "There was a serious problem attempting to connect to " + #BaseName + #Version + " system database. Could be corrupt or open by some other process.")
    EndIf 
    ; 
  Else
    SetGadgetText(#Gadget_BigOvenToSqLite_Errorlist, "Could not open or create raw database file.")
  EndIf
  ; 
EndProcedure
; Berikco's routine to properly replace single quotes with double for SQL passing
Procedure.s RepQuote(Instring.s)
  ;
  Protected.s TemporaryString.s
  ;
  For i = 1 To Len(Instring.s)
    If Mid(Instring.s, i, 1) = "'"
      TemporaryString.s = TemporaryString.s + "''"
    Else
      TemporaryString.s = TemporaryString.s + Mid(Instring.s, i, 1)
    EndIf
  Next i
  ;
  ProcedureReturn TemporaryString.s
  ; 
EndProcedure
; Replace bad characters with XML compatible ones. Thorsten Hoeppner
Procedure.s TextToXML(TextString.s)
  ; 
  XMLString.s = ReplaceString(TextString.s,     "&", "&")
  XMLString.s = ReplaceString(XMLString.s,       "<", "<")
  XMLString.s = ReplaceString(XMLString.s,       ">", ">")
  XMLString.s = ReplaceString(XMLString.s,     "'", "'")
  XMLString.s = ReplaceString(XMLString.s,      "€", "€")
  XMLString.s = ReplaceString(XMLString.s, #DQUOTE$, """)
  XMLString.s = RemoveString(XMLString.s,  #CR$)
  XMLString.s = ReplaceString(XMLString.s, #LF$, Chr(182))
  ; 
  ProcedureReturn XMLString.s
  ; 
EndProcedure
; Strip illegal characters from text strings
Procedure.s XMLToText(XMLString.s)
  ;
  TextString.s = RemoveString(XMLString.s, #CR$)
  ;
  If Left(TextString.s, 1) = #LF$
    TextString.s = Mid(TextString.s, 2)
  EndIf
  ;
  TextString.s = ReplaceString(TextString.s, "&",          "&")
  TextString.s = ReplaceString(TextString.s, "<",           "<")
  TextString.s = ReplaceString(TextString.s, ">",           ">")
  TextString.s = ReplaceString(TextString.s, "'",         "'")
  TextString.s = ReplaceString(TextString.s, """,    #DQUOTE$)
  TextString.s = ReplaceString(TextString.s, "€",          "€")
  TextString.s = ReplaceString(TextString.s, "'",          "'")
  TextString.s = ReplaceString(TextString.s, #LF$,    #EmptyString)
  ;TextString.s = ReplaceString(TextString.s, Chr(182), #LF$)
  TextString.s = ReplaceString(TextString.s, #CR$,    #EmptyString)
  ;
  ProcedureReturn Trim(TextString.s)
  ;
EndProcedure
; Universal, recursive search engine used by many functions
Procedure ConvertBigOvenToSqLite(CurrentFile.s)
  ; Try to configure the MDB data source via ODBC
  If SQLConfigDataSource_(0, #ODBC_ADD_DSN, "Microsoft Access Driver (*.mdb)","Server=127.0.0.1; Description=MyDescription ;DSN=ConnectMDB;DBQ=" + CurrentFile.s + ";UID=;PWD=" + Program\CrbPassword + ";")
    ; Now try to open the current MDB database
    MDBDatabaseHandle.i = OpenDatabase(#PB_Any, "ConnectMDB", #EmptyString, #EmptyString, #PB_Database_ODBC)
    ; Check to see if the database failed to open
    If MDBDatabaseHandle.i  <> #DatabaseOpenFail
      ; Create a new list to hold the recipe ID's in
      NewList RecipeId.s()
      ; Create the ID retrieval query
      DatabaseQuery.s = "SELECT RecipeID FROM Recipes"
      ; Get all the current recipe ID's from the current MDB file
      If DatabaseQuery(MDBDatabaseHandle.i, DatabaseQuery.s) <> #DatabaseQueryFail
        While NextDatabaseRow(MDBDatabaseHandle.i)
          AddElement(RecipeId.s())
          RecipeId.s()  = GetDatabaseString(MDBDatabaseHandle.i, 0)
        Wend
        FinishDatabaseQuery(MDBDatabaseHandle.i)
      Else 
        SetGadgetText(#Gadget_BigOvenToSqLite_Errorlist, "The database query failed: " + DatabaseError())
      EndIf
      ; Process all the current recipe ID's from the current MDB file
      If ListSize(RecipeId.s())
        ; 
        DatabaseUpdate(Program\DatabaseHandle, "Begin Transaction")
        ; Iterate each RecipeID from the list and process the wanted recipe elements
        ForEach RecipeId.s()
          DatabaseQuery.s = "SELECT Title, YieldText, Instructions, Source, "
          DatabaseQuery.s + "YieldNumber, PrimaryIngredient, Cuisine, "
          DatabaseQuery.s + "PictureFile1, Notes, AllCategoriesText "
          DatabaseQuery.s + "FROM Recipes WHERE RecipeID = " + RecipeId.s()  + ""
          If DatabaseQuery(MDBDatabaseHandle.i, DatabaseQuery.s) <> #DatabaseQueryFail
            While NextDatabaseRow(MDBDatabaseHandle.i) <> 0
              Title.s             = KillQuote(GetDatabaseString(MDBDatabaseHandle.i, 0))
              YieldText.s         = KillQuote(GetDatabaseString(MDBDatabaseHandle.i, 1))
              Instructions.s      = KillQuote(GetDatabaseString(MDBDatabaseHandle.i, 2))
              Source.s            = KillQuote(GetDatabaseString(MDBDatabaseHandle.i, 3))
              YieldNumber.s       = KillQuote(GetDatabaseString(MDBDatabaseHandle.i, 4))
              PrimaryIngredient.s = KillQuote(GetDatabaseString(MDBDatabaseHandle.i, 5))
              Cuisine.s           = KillQuote(GetDatabaseString(MDBDatabaseHandle.i, 6))
              PictureFile1.s      = KillQuote(GetDatabaseString(MDBDatabaseHandle.i, 7))
              Notes.s             = KillQuote(GetDatabaseString(MDBDatabaseHandle.i, 8))
              AllCategoriesText.s = KillQuote(GetDatabaseString(MDBDatabaseHandle.i, 9))
              AllCategoriesText.s = ReplaceString(AllCategoriesText.s, "|", ",", #PB_String_NoCase, 1)
              AllCategoriesText.s = Trim(AllCategoriesText.s, ",")
              Updated.s           = FormatDate("%yyyy-%mm-%dd", Date()) ; Standard ISO date format
              ; Save the recipe item into the SQLite database
              DatabaseUpdate.s  = "INSERT INTO Recipes("
              DatabaseUpdate.s  + "Recipetitle, Numberofservings, Recipeauthor, Categories, "
              DatabaseUpdate.s  + "Subcategories, Preparationtime, Cookingtime, Difficulty, "
              DatabaseUpdate.s  + "Recipeversion, Recipesource, Copyright, Cuisine, "
              DatabaseUpdate.s  + "Reciperating, Importedfrom, Authorcomments, Instructions, "
              DatabaseUpdate.s  + "Nutritionaldata, Othercomments, Deleted, Updated, "
              DatabaseUpdate.s  + "Favourite, Locked) "
              DatabaseUpdate.s  + "VALUES("
              DatabaseUpdate.s  + "'"  + RepQuote(Title.s)              + "', " ; Recipetitle
              DatabaseUpdate.s  + "'"  + RepQuote(YieldText.s)          + "', " ; Numberofservings
              DatabaseUpdate.s  + "'"  +                                  "', " ; Recipeauthor
              DatabaseUpdate.s  + "'"  + RepQuote(PrimaryIngredient.s)  + "', " ; Categories
              DatabaseUpdate.s  + "'"  + RepQuote(AllCategoriesText.s)  + "', " ; SubCategoriesText
              DatabaseUpdate.s  + "'"  +                                  "', " ; Preparationtime
              DatabaseUpdate.s  + "'"  +                                  "', " ; Cookingtime
              DatabaseUpdate.s  + "'"  +                                  "', " ; Difficulty
              DatabaseUpdate.s  + "'"  +                                  "', " ; Recipeversion
              DatabaseUpdate.s  + "'"  + RepQuote(Source.s)             + "', " ; Recipesource
              DatabaseUpdate.s  + "'"  + RepQuote(Copyright.s)          + "', " ; Copyright
              DatabaseUpdate.s  + "'"  + RepQuote(Cuisine.s)            + "', " ; Cuisine
              DatabaseUpdate.s  + "'"  +                                  "', " ; Reciperating
              DatabaseUpdate.s  + "'"  +          "BigOven"             + "', " ; Importedfrom
              DatabaseUpdate.s  + "'"  +                                  "', " ; Authorcomments
              DatabaseUpdate.s  + "'"  + RepQuote(Instructions.s)       + "', " ; Instructions
              DatabaseUpdate.s  + "'"  +                                  "', " ; Nutritionaldata
              DatabaseUpdate.s  + "'"  + RepQuote(Notes.s)              + "', " ; Othercomments
              DatabaseUpdate.s  + "'"  + "0"                            + "', " ; Deleted
              DatabaseUpdate.s  + "'"  +          Updated.s             + "', " ; Updated
              DatabaseUpdate.s  + "'"  + "0"                            + "', " ; Favourite
              DatabaseUpdate.s  + "'"  + "0"                            + "')"  ; Locked
              If DatabaseUpdate(Program\DatabaseHandle, DatabaseUpdate.s) <> #DatabaseUpdateFail
                LastRecordNumberInserted.s = DatabaseLastInsertRowId()
                If LastRecordNumberInserted.s
                  Program\Numberoftitles  + 1
                  AddGadgetItem(#Gadget_BigOvenToSqLite_TItlelist, #AtTheEndOfTheList, Title.s)
                  LastLine(#Gadget_BigOvenToSqLite_TItlelist, Program\Numberoftitles - 1)
                  SetGadgetText(#Gadget_BigOvenToSqLite_Numberoftitles, "Recipes found: "  + Str(Program\Numberoftitles))                  
                  While WindowEvent() : Wend
                  ; Process the picture into its own table
                  If PictureFile1.s <> #EmptyString
                    Program\Numberofpictures  + 1
                    SetGadgetText(#Gadget_BigOvenToSqLite_Numberofpictures, "Pictures found: "  + Str(Program\Numberofpictures))                  
                    PictureName.s = GetPathPart(CurrentFile.s)  + "Pictures\" + PictureFile1.s
                    PictureFileIn.i = ReadFile(#PB_Any, PictureName.s)
                    If PictureFileIn.i
                      FileInSize.i = Lof(PictureFileIn.i)
                      *Buffer = AllocateMemory(FileInSize.i)
                      If *Buffer
                        If ReadData(PictureFileIn.i, *Buffer, FileInSize.i) = FileInSize.i
                          SetDatabaseBlob(Program\DatabaseHandle, 0, *Buffer, FileInSize.i)
                          DatabaseUpdate.s  = "INSERT INTO Pictures("                 ; 
                         ;DatabaseUpdate.s + "Pictureid, "                            ; Pictureid
                          DatabaseUpdate.s + "Picture, "                              ; Picture
                          DatabaseUpdate.s + "Description, "                          ; Description
                          DatabaseUpdate.s + "Filename, "                             ; Filename
                          DatabaseUpdate.s + "Recordid) "                             ; Recordid
                          DatabaseUpdate.s + "VALUES("                                ; 
                         ;DatabaseUpdate.s + "Pictureid, "                            ; Pictureid
                          DatabaseUpdate.s + "?, "                                    ; Picture
                          DatabaseUpdate.s + "'', "                                   ; Description
                          DatabaseUpdate.s + "'" + RepQuote(PictureFile1.s)  + "', "  ; Filename
                          DatabaseUpdate.s + "'" + LastRecordNumberInserted.s + "')"  ; Recordid
                          If DatabaseUpdate(Program\DatabaseHandle, DatabaseUpdate.s) <> #DatabaseUpdateFail
                            NewPictureRecord.s = DatabaseLastInsertRowId()
                            If NewPictureRecord.s <> #EmptyString
                              ; Tell the user something here
                            Else
                              SetGadgetText(#Gadget_BigOvenToSqLite_Errorlist, "Could not get a new record number for picture data")
                            EndIf
                          Else
                            SetGadgetText(#Gadget_BigOvenToSqLite_Errorlist, "Could not save the picture data into the database")
                          EndIf
                        Else
                          SetGadgetText(#Gadget_BigOvenToSqLite_Errorlist, "Could not read the picture data into the buffer")
                        EndIf
                        FreeMemory(*Buffer)
                      Else
                        SetGadgetText(#Gadget_BigOvenToSqLite_Errorlist,  "Could not allocate a buffer for the picture data")
                      EndIf
                      CloseFile(PictureFileIn.i)
                    Else
                      SetGadgetText(#Gadget_BigOvenToSqLite_Errorlist,  "Could not open the designated file to read from")
                    EndIf
                  Else
                    SetGadgetText(#Gadget_BigOvenToSqLite_Errorlist,  "No picture for this record")
                  EndIf
                Else
                  SetGadgetText(#Gadget_BigOvenToSqLite_Errorlist,  "Failed to get a new database record ID")
                EndIf
              Else
                SetGadgetText(#Gadget_BigOvenToSqLite_Errorlist,  "The database update failed: "  + DatabaseError())
              EndIf
              ; 
            Wend
            FinishDatabaseQuery(MDBDatabaseHandle.i)
            ; Process the ingredients for this recipe
            If LastRecordNumberInserted.s
              DatabaseQuery.s = "SELECT TextQty, Measure, Name, PrepNotes, LineOrder "
              DatabaseQuery.s + "FROM IngredientLines "
              DatabaseQuery.s + "WHERE RecipeID = "    + RecipeId.s()  + ""
              If DatabaseQuery(MDBDatabaseHandle.i, DatabaseQuery.s) <> #DatabaseQueryFail
                While NextDatabaseRow(MDBDatabaseHandle.i)
                  Program\Numberofingredients  + 1
                  SetGadgetText(#Gadget_BigOvenToSqLite_Numberofingredients, "Ingredients found: "  + Str(Program\Numberofingredients))                  
                  TextQty.s   = KillQuote(GetDatabaseString(MDBDatabaseHandle.i, 0))
                  Measure.s   = KillQuote(GetDatabaseString(MDBDatabaseHandle.i, 1))
                  Name.s      = KillQuote(GetDatabaseString(MDBDatabaseHandle.i, 2))
                  PrepNotes.s = KillQuote(GetDatabaseString(MDBDatabaseHandle.i, 3))
                  LineOrder.s = KillQuote(GetDatabaseString(MDBDatabaseHandle.i, 4))
                  ; 
                  DatabaseUpdate.s = "INSERT INTO Ingredients("                       ; 
                 ;DatabaseUpdate.s + "Ingredientid, "                                 ; IngredientLinesID
                  DatabaseUpdate.s + "Unit, "                                         ; TextQty
                  DatabaseUpdate.s + "Measure, "                                      ; Measure
                  DatabaseUpdate.s + "Ingredient, "                                   ; Name
                  DatabaseUpdate.s + "Preparation, "                                  ; PrepNotes
                  DatabaseUpdate.s + "Lineorder, "                                    ; LineOrder
                  DatabaseUpdate.s + "Recordid) "                                     ; RecipeID
                  DatabaseUpdate.s + "VALUES("                                        ; 
                  DatabaseUpdate.s + "'" + RepQuote(TextQty.s)        + "', "         ; 
                  DatabaseUpdate.s + "'" + RepQuote(Measure.s)        + "', "         ; 
                  DatabaseUpdate.s + "'" + RepQuote(Name.s)           + "', "         ; 
                  DatabaseUpdate.s + "'" + RepQuote(PrepNotes.s)      + "', "         ; 
                  DatabaseUpdate.s + "'" + RepQuote(LineOrder.s)      + "', "         ; 
                  DatabaseUpdate.s + "'" + LastRecordNumberInserted.s + "')"          ; 
                  If DatabaseUpdate(Program\DatabaseHandle, DatabaseUpdate.s) <> #DatabaseUpdateFail
                  Else
                    SetGadgetText(#Gadget_BigOvenToSqLite_Errorlist,  "Could not insert the current ingredient into the database")
                  EndIf
                  ; 
                Wend
                FinishDatabaseQuery(MDBDatabaseHandle.i)
              EndIf
            Else
              SetGadgetText(#Gadget_BigOvenToSqLite_Errorlist,  "No last record number created")
            EndIf
            ; 
          Else 
            SetGadgetText(#Gadget_BigOvenToSqLite_Errorlist,  "The database query failed: " + DatabaseError())
          EndIf
          ; 
        Next ;RecipeID()  
        ; 
        DatabaseUpdate(Program\DatabaseHandle, "Commit")
        ; 
      Else
        ; The list is empty, nothing to process
      EndIf
      ; 
      CloseDatabase(MDBDatabaseHandle.i)
      ; 
    Else
      SetGadgetText(#Gadget_BigOvenToSqLite_Errorlist,  "No MDB database handle: " + DatabaseError())
    EndIf
    ; 
    SQLConfigDataSource_(0, #ODBC_REMOVE_DSN, "Microsoft Access Driver (*.mdb)","Server=127.0.0.1; Description=MyDescription ;DSN=ConnectMDB;DBQ=" + CurrentFile.s + ";UID=;PWD=" + Program\CrbPassword + ";")
    ; 
  Else
    SetGadgetText(#Gadget_BigOvenToSqLite_Errorlist,  "Could not configure MDB data source: " + DatabaseError())
  EndIf
  ; 
EndProcedure
; 
Procedure GetConvertPath()
  ; 
  ConvertPath.s = PathRequester("CRB convert path", Program\CurrentDirectory)
  ; 
  If ConvertPath.s <> #EmptyString
    SetGadgetText(#Gadget_BigOvenToSqLite_Convertpath, ConvertPath.s)
    Program\LastConvertPath = ConvertPath.s
  Else
    SetGadgetText(#Gadget_BigOvenToSqLite_Errorlist, "[ No BigOven CRB path set yet? ]")
  EndIf
  ; 
EndProcedure
; Universal, recursive search engine used by many functions
Procedure SearchEngine(SearchDirectory.s)
  ; 
  If SearchDirectory.s  <> "[ No BigOven CRB path set yet? ]"
    ; 
    ClearGadgetItems(#Gadget_BigOvenToSqLite_Recipeboxes)
    Program\Numberofrecipeboxes = 0
    SetGadgetText(#Gadget_BigOvenToSqLite_Numberofrecipeboxes, "Boxes found: "  + Str(Program\Numberofrecipeboxes))
    ; 
    ClearGadgetItems(#Gadget_BigOvenToSqLite_TItlelist)
    Program\Numberoftitles = 0
    SetGadgetText(#Gadget_BigOvenToSqLite_Numberoftitles, "Recipes found: "  + Str(Program\Numberofrecipeboxes))
    ; 
    NewList FoundDirectories.s()
    ; 
    If SearchDirectory.s <> #EmptyString
      If Right(SearchDirectory.s, 1) = "\"
        SearchDirectory.s = Left(SearchDirectory.s, Len(SearchDirectory.s) - 1)
      EndIf
      AddElement(FoundDirectories.s())
      FoundDirectories.s() = SearchDirectory.s
      IndexLevel.i = 0
      Repeat
        SelectElement(FoundDirectories.s(), IndexLevel.i)
        If ExamineDirectory(0, FoundDirectories.s(), "*.*")
          Path.s = FoundDirectories.s() + "\"
          While NextDirectoryEntry(0)
            Filename.s = DirectoryEntryName(0)
            Select DirectoryEntryType(0)
              Case 1
                ; 
                If LCase(GetExtensionPart(Path.s + Filename.s)) = "crb"
                  Program\Numberofrecipeboxes + 1
                  AddGadgetItem(#Gadget_BigOvenToSqLite_Recipeboxes, #AtTheEndOfTheList,  Filename.s)
                  SetGadgetText(#Gadget_BigOvenToSqLite_Numberofrecipeboxes, "Boxes found: "  + Str(Program\Numberofrecipeboxes))
                  While WindowEvent() : Wend
                  ConvertBigOvenToSqLite(Path.s + Filename.s)
                EndIf
                ; 
              Case 2
                Filename.s = DirectoryEntryName(0)
                If Filename.s <> ".." And Filename.s <> "."
                  AddElement(FoundDirectories())
                  FoundDirectories() = Path + Filename.s
                EndIf
            EndSelect
          Wend
        EndIf
        IndexLevel.i + 1
      Until IndexLevel.i > ListSize(FoundDirectories()) -1
    EndIf
    ; 
  EndIf
  ; 
EndProcedure
; Main program body
If Window_BigOvenToSqLite()
  ; 
  If FileSize(Program\Configfile) <> #NoFileFound                           ; Config file was found
    ConfigFile.i = ReadFile(#PB_Any, Program\Configfile)
    If ConfigFile.i <> #NoFileHandle
      Program\LastDatabase    = ReadString(ConfigFile.i,  #PB_Ascii)
      SetGadgetText(#Gadget_BigOvenToSqLite_Databasename, Program\LastDatabase)
      Program\LastConvertPath = ReadString(ConfigFile.i,  #PB_Ascii)
      SetGadgetText(#Gadget_BigOvenToSqLite_Convertpath,  Program\LastConvertPath)
      CloseFile(ConfigFile.i)
      SetGadgetText(#Gadget_BigOvenToSqLite_Errorlist, "Config file read, BigOven converter ready to work...")
    Else
      SetGadgetText(#Gadget_BigOvenToSqLite_Errorlist,  "Couldn't open up the config file")
    EndIf
  ElseIf FileSize(Program\Configfile) = #NoFileFound
    OpenSystemDatabase()
    SetGadgetText(#Gadget_BigOvenToSqLite_Databasename, Program\DatabaseName)
    Program\LastDatabase    = Program\DatabaseName
    SetGadgetText(#Gadget_BigOvenToSqLite_Convertpath,  "[ No BigOven CRB path set yet? ]")
    Program\LastConvertPath = "[ No BigOven CRB path set yet? ]"
    SetGadgetText(#Gadget_BigOvenToSqLite_Errorlist,    "No config file, default database opened, ready to work")
  EndIf
  ; 
  Program\QuitValue = #False
  ; 
  Repeat
    EventID  = WaitWindowEvent()
    MenuID   = EventMenu()
    GadgetID = EventGadget()
    WindowID = EventWindow()
    Select EventID
      Case #PB_Event_CloseWindow
        Select WindowID
        Case  #Window_BigOvenToSqLite                 : Program\QuitValue = #True
        EndSelect
      Case #PB_Event_Gadget
        Select GadgetID
          Case  #Gadget_BigOvenToSqLite_Getdatabase   : OpenOtherDatabase()
          Case  #Gadget_BigOvenToSqLite_Getpath       : GetConvertPath()
          Case  #Gadget_BigOvenToSqLite_Convert       : SearchEngine(Program\ConvertPath)
          Case  #Gadget_BigOvenToSqLite_Exitprogram   : Program\QuitValue = #True
        EndSelect
    EndSelect
  Until Program\QuitValue = #True
  ; 
  CloseWindow(#Window_BigOvenToSqLite)
  ; 
  ConfigFile.i = CreateFile(#PB_Any, Program\Configfile)
  If ConfigFile.i <> #NoFileHandle
    WriteStringN(ConfigFile.i, Program\LastDatabase,    #PB_Ascii)
    WriteStringN(ConfigFile.i, Program\LastConvertPath, #PB_Ascii)
    CloseFile(ConfigFile.i)
  Else
    Debug "Couldn't open up the config file"
  EndIf
  ; 
EndIf
; 
End