2016-10-22 5 views
1

xml 파일에 저장되고 프로그램 시작시로드되는 userbase를 포함하는 응용 프로그램이 있습니다. 이 목적으로 QXmlStreamWriter/Reader를 사용합니다. 암호화 된 (해쉬 된?) 암호 형식 (QCryptographicHash 및 Sha256 사용)을 직렬화하려고하면이 문제가 발생합니다.암호화 된 암호를 XML로 serialize

QCryptographicHash QByteArray는 QString으로 변환 될 수 있습니다 (QXmlStreamWriter/Reader 사용시 필요). 아래 관련 코드. 모든 것은 serialization (로그인 할 수 있습니다.) 전에는 제대로 작동하지만 xml에서 데이터를 읽을 때 해쉬 된 암호를 찾은 후에 함수는 EOF를 찾은 것처럼 동작하고 QXmlStreamReader에 의해 QString에 약 2 개의 문자 만로드됩니다.

코드에서 예약 등 (영화 패널 임)을 무시하십시오. 관련 조각은 암호이며, 경우에 대비해 모든 기능을 제공합니다.

가 나는 문제가 무엇인지 설명 희망, 여기 내 코드의 조각이다

QString hash = QCryptographicHash::hash(pass.toUtf8(), QCryptographicHash::Sha256); 

User* user_pointer; 
user_pointer = new User(name, hash, admin); 
:

등록 기능 (해시는, 패스는 QString이다) (주 해싱 모든 것이 잘 작동 추가하기 전에)

쓰기 기능 :

QFile file("users/users.xml"); 
if(!file.open(QIODevice::WriteOnly)) 
    throw "Error podczas otwierania bazy użytkowników!"; 


    QXmlStreamWriter writer (&file); 

    writer.setAutoFormatting(true); 
    writer.writeStartDocument(); 
    writer.writeStartElement("USERS"); 
    int list_size = userList.size(); 

    for(int i = 0; i < list_size; i++) 
    { 
     writer.writeStartElement("USER"); 
     writer.writeTextElement("name", userList.at(i)->name); 
     writer.writeTextElement("pass", userList.at(i)->password); 
     writer.writeTextElement("admin", QString::number(userList.at(i)->is_admin)); 
     writer.writeStartElement("RESERVATIONS"); 
     for(int m = 0; m < userList.at(i)->reservList.size(); m++) 
     { 
      writer.writeStartElement("reservation"); 
      writer.writeTextElement("moviename", userList.at(i)->reservList.at(m)->movie_name); 
      writer.writeTextElement("date", userList.at(i)->reservList.at(m)->date.toString("dd.MM.yyyy")); 
      writer.writeTextElement("hour", (userList.at(i)->reservList.at(m)->hour).toString("hhmm")); 
      writer.writeTextElement("paid", QString::number(userList.at(i)->reservList.at(m)->paid)); 
      for(int n = 0; n < userList.at(i)->reservList.at(m)->placeList.size(); n++) 
       writer.writeTextElement("place", QString::number(userList.at(i)->reservList.at(m)->placeList.at(n))); 
      writer.writeEndElement(); 
     } 
     writer.writeEndElement(); 
     writer.writeEndElement(); 
    } 
    writer.writeEndDocument(); 


    file.close(); 

} 

읽기 기능 :

QFile file("users/users.xml"); 
if(!file.open(QIODevice::ReadOnly)) 
    throw "Brak bazy danych użytkowników lub błąd jej otworzenia!"; 

QXmlStreamReader reader; 

reader.setDevice(&file); 
reader.readNext(); 

QString user_name; 
QString user_pass; 
bool admin; 
QString movie_name; 
QTime hour; 
QDate date; 
bool paid; 

User* user_pointer = NULL; 
int user_counter = -1; 
Reservation* reserv_pointer = NULL; 
int reserv_counter = -1; 

while(!reader.atEnd()) 
{ 
    if(reader.isStartElement()) 
    { 
     if(reader.name() == "USER") 
     { 
      reserv_counter = -1; 

     } 

     if(reader.name() == "name") 
      user_name = reader.readElementText(); 
     if(reader.name() == "pass") 
      user_pass = reader.readElementText(); 
     if(reader.name() == "admin") 
     { 
      admin = reader.readElementText().toInt(); 
      user_pointer = new User(user_name, user_pass, admin); 
      userList.append(user_pointer); 

      user_counter++; 
     } 
     if(reader.name() == "reservation") 
     { 
      reserv_counter++; 
     } 
     if(reader.name() == "moviename") 
      movie_name = reader.readElementText(); 
     if(reader.name() == "hour") 
      hour = QTime::fromString(reader.readElementText(), "hhmm"); 
     if(reader.name() == "date") 
      date = QDate::fromString(reader.readElementText(), "dd.MM.yyyy"); 
     if(reader.name() == "paid") 
     { 
      paid = reader.readElementText().toInt(); 
      reserv_pointer = new Reservation(movie_name, date, hour, paid); 
      userList.at(user_counter)->reservList.append(reserv_pointer); 
     } 
     if(reader.name() == "place") 
      { 
      userList.at(user_counter)->reservList.at(reserv_counter)->placeList.append(reader.readElementText().toInt()); 

      } 

     reader.readNextStartElement(); 
    } 
    else 
     reader.readNext(); 
} 

file.close(); 
} 

답변

1

해시 값은 문자열이 아니며 임의의 바이트 값의 시퀀스입니다. 일부는 문자열로 해석 할 때 문제가 될 수 있습니다.

바이트 어레이가 fromUtf8() 함수를 사용하여 유니 코드로 변환된다

당신은 문서가 있다고하는 QByteArray에서 QString까지 암시 적 변환을 갖는다. 이 함수는 찾은 첫 번째 NUL 문자에서 변환을 중지하거나 바 바이트 배열의 끝 부분에서 변환을 중지합니다. 당신은 예를 들어 길이 지정 명시 적 변환 사용할 수

:

QString::fromUtf8(byteArray.data(), length); 

프랭크 Osterfeld가 UTF8은 좋은 생각이 아니다 사용 코멘트에 언급했듯이을, 나는 광대를위한에서와 라틴어로 테스트 한 내가 작업하고 있던 프로젝트와 바이너리 데이터는 동일하지만 XML 형식의 읽기 및 쓰기 기능을 제대로 수행하지 못하는 텍스트 형식의 "펑키"형식에서는 toHex()이 0-F로 문자 집합을 제한하여이를 수정합니다.

QByteArray b; // hash 
QString ss = QString::fromLatin1(b.toHex()); // to QString 
b = QByteArray::fromHex(ss.toLatin1()); // back to QByteArray 
+0

는 바이너리 데이터 경우 작동하지 않습니다 아마도 여기에있는 것처럼 utf-8은 유효하지 않습니다. 나는 QString :: fromLatin1 (byteArray.toHex())를 사용할 것이다. toHex()의 대안은 toBase64()입니다. –

+0

UTF8에 대해서는 /에서 테스트하지 않았으므로 Latin1에서는 제대로 작동하는 것으로 보입니다. 사실 XML 대신 이진 형식으로 시작하겠습니다. – dtech

0

문제는 XML이 텍스트 형식이지만 암호화 된 암호는 바이너리 형식이라는 점입니다. 이 두 가지는 호환되지 않습니다. 이진 데이터를 텍스트 형식으로 인코딩하는 방법이 필요합니다.

@ddriver가 언급 한 것처럼, QByteArray::toHex()을 사용하는 한 가지 방법은 모든 바이트를 사람이 읽을 수있는 텍스트 문자로 변환하기 때문입니다. 그러나 비용은 크기가 100 % 증가합니다 (암호 해시의 각 바이트에 2 문자가 반환 됨)

이진 데이터를 텍스트 형식으로 전송하는 또 다른 보편적이고 효율적인 방법은 QByteArray::toBase64()을 사용하는 것입니다.텍스트 형식의 이진 데이터도 반환하지만 크기가 33 1/3 % 증가합니다 (3 바이트의 암호 해시마다 4 바이트가 반환 됨).

는 (당신은 일반적으로 하나 개 또는 두 개의 = 문자로 끝나는 그것 무의미한 텍스트 때문에이 인코딩을 인식하고 이메일에 바이너리 데이터를 전송하는 데 사용되는 일반적인 인코딩입니다 수)

관련 문제