Seite 1 von 1

[Dedupe] Stringcodierung Posix/Windows

Verfasst: So Jan 22, 2012 11:26 pm
von Bebu
Hallo zusammen, neues von der Dedupe-Front ;)
Neben einem Umzug habe ich die letzte Zeit an einer Überraschung für unsere Windowsnutzer gearbeitet, die mir hiermit gründlich misslungen ist :( Ich wollte euch gerne eine Windowsversion per Crosscompiler erstellen, leider tun sich unerwartete Probleme auf. Nach langem googlen um Boost und Sqlite entsprechend zu kompilieren ärgert mich jetzt die Stringkodierung. Ich arbeite intern mit Boost Filesystem. Um die Sql Befehle zusammenzubauen, die Datenbank zu öffnen usw. ist es nötig, auf den nativen String zurückzugreifen, der unter der Haube eines Boost Path Objekts steckt. Und jetzt kommt das Problem: Ich habe bisher mit normalen Strings gearbeitet, was unter Linux kein Problem darstellt, weil hier auch ein normaler String im Path Objekt gekapselt ist. Unter Windows steckt aber ein wchar_t drinnen. Hier komme ich sowohl mit den normalen Strings, als auch mit Sqlite in Konflikt. Die aktuelle Öffnungsfunktion von Sqlite erwartet einen UTF-8 codierten normalen String. Ich will keine zwei Codeversionen für char und wchar pflegen müssen, ich will die Windowsversion nicht droppen und habe mir keine elegante Lösung ergooglen können. Habt ihr eine Idee, wie man das Problem lösen kann? Ich dachte schon daran, mir eine eigene Stringklasse zu bauen, die konvertieren kann, aber so was gibt es bestimmt schon. Ich habe auch etwas im neuen Standard entdeckt, aber ich weiß noch nicht, ob mir das weiterhilft. Danke für eure Hilfe im Voraus.

Re: [Dedupe] Stringcodierung Posix/Windows

Verfasst: Mo Jan 23, 2012 11:14 am
von Xin
Bebu hat geschrieben:Ich habe bisher mit normalen Strings gearbeitet, was unter Linux kein Problem darstellt, weil hier auch ein normaler String im Path Objekt gekapselt ist.
Was ist ein 'normaler' String? std::string? char *?
Bebu hat geschrieben:Unter Windows steckt aber ein wchar_t drinnen. Hier komme ich sowohl mit den normalen Strings, als auch mit Sqlite in Konflikt. Die aktuelle Öffnungsfunktion von Sqlite erwartet einen UTF-8 codierten normalen String. Ich will keine zwei Codeversionen für char und wchar pflegen müssen, ich will die Windowsversion nicht droppen und habe mir keine elegante Lösung ergooglen können. Habt ihr eine Idee, wie man das Problem lösen kann? Ich dachte schon daran, mir eine eigene Stringklasse zu bauen, die konvertieren kann, aber so was gibt es bestimmt schon.
Meine kann es noch nicht. Aber das könnte man ja mal ändern.
Bebu hat geschrieben:Ich habe auch etwas im neuen Standard entdeckt, aber ich weiß noch nicht, ob mir das weiterhilft.
Ich auch nicht, ich weiß nichtmals, was hast Du letztendlich entdeckt hast?

Re: [Dedupe] Stringcodierung Posix/Windows

Verfasst: Mo Jan 23, 2012 11:31 pm
von Bebu
Mit normaler String meine ich std::string. Der wird unter Linux und wahrscheinlich auch Mac genutzt. Nur bei Windows ist es ein std::wstring. Im neuen Standard gibt es Präfixe, um die Codierung des Strings sicher zu stellen, z.B:

Code: Alles auswählen

std::string EinString( u8"Ich bin ein UTF8 String";
Sqlite bietet die Möglichkeit, auch mit wstrings zu arbeiten, allerdings ist das die einfache Funktion. Die neuere gibt es nur mit UTF-8 Strings(std::string). Da wir aber Mulithreading nutzen wollen, sind wir mit der neuen Variante besser bedient.

Re: [Dedupe] Stringcodierung Posix/Windows

Verfasst: Di Jan 24, 2012 9:01 pm
von fat-lobyte
Bebu hat geschrieben:Hallo zusammen, neues von der Dedupe-Front ;)
Neben einem Umzug habe ich die letzte Zeit an einer Überraschung für unsere Windowsnutzer gearbeitet, die mir hiermit gründlich misslungen ist :( Ich wollte euch gerne eine Windowsversion per Crosscompiler erstellen, leider tun sich unerwartete Probleme auf.
Crosskompilieren ist zwar Nobel, aber nicht die einfachste aller Hürden. Versuchs mal mit nativ, auch wenn du dabei mit Windows arbeiten musst.
Um die Sql Befehle zusammenzubauen, die Datenbank zu öffnen usw. ist es nötig, auf den nativen String zurückzugreifen, der unter der Haube eines Boost Path Objekts steckt.
Also wer benötigt jetzt native Strings? SQLite? Oder gibt Boost welche zurück?
Und jetzt kommt das Problem: Ich habe bisher mit normalen Strings gearbeitet, was unter Linux kein Problem darstellt, weil hier auch ein normaler String im Path Objekt gekapselt ist.
Wenn du auch unter Unix wchar_t verwenden könntest wäre das schon mal eine Lösung (bis auf die Tatsache dass du eine Datenbank nicht zwischen Windows und Linux konvertieren könntest, denn wchar_t->32 bit auf Unix, 16 bit auf Windows).
Habt ihr eine Idee, wie man das Problem lösen kann? Ich dachte schon daran, mir eine eigene Stringklasse zu bauen, die konvertieren kann, aber so was gibt es bestimmt schon.
Von einer ganzen Klasse würde ich abraten, aber eine konvertierungsfunktion zwischen UTF32->UTF8 oder UTF16->UTF8 könnte gehen. Dafür gibts auf der Unicode-Webseite auch irgendwo Algorithmen in Pseudo-code.
Was du notfalls machen könntest wäre libicu zu verwenden, die soll einigermaßen leicht und effizient sein.

Re: [Dedupe] Stringcodierung Posix/Windows

Verfasst: Di Jan 24, 2012 10:06 pm
von Bebu
Dein Tip zum Crosscompilieren ist nobel, scheitert aber an einer Windowsinstallation und der Zeit/Lust eine aufzusetzen. Bis der Crosscompiler lief und ich die Libs alle soweit hatte, habe ich ja auch schon Zeit investiert. Ich scheitere auch nicht am kompilieren, sondern an Boost. Boost Path verwendet unter Posix entweder einen std::string, oder einen basic_string<char> um Pfade intern zu kapseln, genau weiß ich es jetzt nicht auswendig, es läuft sich aufs selbe raus. Sobald man aber unter Windows unterwegs ist, wird ein std::wstring oder halt basic_string<wchar_t> benutzt. Das ist das verhalten von Boost Filesystem und das kann und will ich nicht verändern. Ich komme dabei allerdings mit dieser Funktion von Sqlite in Konflikt:

Code: Alles auswählen

int sqlite3_open_v2(
  const char *filename,   /* Database filename (UTF-8) */
  sqlite3 **ppDb,         /* OUT: SQLite db handle */
  int flags,              /* Flags */
  const char *zVfs        /* Name of VFS module to use */
);
Es gibt alternativ noch diese Funktionen für die Datenbanköffnung:

Code: Alles auswählen

int sqlite3_open(
  const char *filename,   /* Database filename (UTF-8) */
  sqlite3 **ppDb          /* OUT: SQLite db handle */
);
int sqlite3_open16(
  const void *filename,   /* Database filename (UTF-16) */
  sqlite3 **ppDb          /* OUT: SQLite db handle */
);
Damit verliere ich aber die Möglichkeit, Sqlite in den Mulithreading-Modus zu schalten.

Zusätzlich bekomme ich durch dieses Verhalten von Boost ein Problem in diesen Funktionen:

Code: Alles auswählen

void Dataholding::AddFile( Dedupe::FileInfo const &IncomingFile )
{
  std::stringstream translateStream;
  std::string ExecString;

  translateStream
  << "INSERT INTO StoredFiles ( Path, Size, ChangeDate, Type, Hash) VALUES ('"
  << IncomingFile.GetPath().native() << "','"
  << IncomingFile.GetSize() << "','"
  << IncomingFile.GetDateChanged() << "','"
  << IncomingFile.GetType() << "','"
  << IncomingFile.GetHash() << "');";

  std::getline( translateStream, ExecString );
  SqlExec( ExecString );
}
Hier greife ich auf die native() Funktion eines Path Objekts zurück. Das passt unter Linux wunderbar, weil ein std::string zurückkommt, nicht aber unter Windows, weil hier ein wstring zurückkommt. Jetzt suche ich ein Möglichkeit das ganze zu lösen, ohne Code zu produzieren, der aufwändig für zwei OS gepflegt werden muss.

Re: [Dedupe] Stringcodierung Posix/Windows

Verfasst: Mi Jan 25, 2012 12:40 pm
von fat-lobyte
Bebu hat geschrieben:Dein Tip zum Crosscompilieren ist nobel, scheitert aber an einer Windowsinstallation und der Zeit/Lust eine aufzusetzen.
Schade. Wirklich perfekt testen kann man nur nativ.
wird ein std::wstring oder halt basic_string<wchar_t>
Das eine ist ein typedef fürs andere ;-)
Es gibt alternativ noch diese Funktionen für die Datenbanköffnung: Damit verliere ich aber die Möglichkeit, Sqlite in den Mulithreading-Modus zu schalten.
Das ist ein ziemlicher killer. Das würde ich dann nicht machen.
Jetzt suche ich ein Möglichkeit das ganze zu lösen, ohne Code zu produzieren, der aufwändig für zwei OS gepflegt werden muss.
Das Zauberwort heißt template specialization:

Code: Alles auswählen

#include <iostream>

const char* UTF16toUTF8(const wchar_t*);


template <typename CharType>
std::basic_string<char> convert_string(const std::basic_string<CharType>&);

template <>
std::basic_string<char> convert_string(const std::basic_string<char>& in)
{
    return in;
}

template <>
std::basic_string<char> convert_string(const std::basic_string<wchar_t>& in)
{
    const char* out = UTF16toUTF8(in.c_str());
    return std::basic_string<char>(out);
}



int main()
{
    std::string  cs("Ich bin ein char-string");
    std::wstring ws(L"Ich bin ein wchar_t-string");

    std::string s1(convert_string(cs));
    std::string s2(convert_string(ws));
    
    std::cout<<s1<<'\n';
    std::cout<<s2<<'\n';
    
    return 0;
}


const char* UTF16toUTF8(const wchar_t*)
{
    // ganz komplizierte konvertierungsfunktion
    return "Ich wurde konvertiert.";
}
Ist jetzt mal so rudimentär zusammengehackt. Für UTF16toUTF8() müsste man sich was einfallen lassen oder libicu verwenden, und die kopiererei könnte man auch optimieren, aber im prinzip hast du da deinen Adaptor.

Re: [Dedupe] Stringcodierung Posix/Windows

Verfasst: Mi Jan 25, 2012 12:53 pm
von fat-lobyte
Da fällt mir ein, simple Überladung hätts auch getan...
Manchmal ist man so voll mit dem ganzen Template-zeugs dass man die einfachen Dinge vergisst :-D

Re: [Dedupe] Stringcodierung Posix/Windows

Verfasst: Mi Jan 25, 2012 1:05 pm
von Bebu
Na, das sieht doch schon ganz gut aus. Jetzt muss ich mich noch mit der Konvertierung schlau machen, dann könnte das klappen. Vielleicht schaffe ich es ja doch noch, ein Windows Xp in die Virtuelle Maschine zu prügeln, dann könnte es klappen. Besten Dank.