Свойство NSPropertyListSerializationListWithData завершается с бинарным списком

Обновление: решено. Код обновлен.

Я работаю над кодом для обработки списков в Objective-C ++.

Когда я передаю функции путь к XML-списку, все работает без сбоев, и вывод говорит:

2014-08-12 17:06:47.932 plist_tests[96368:507] plist was in xml format

Когда я передаю функцию путь к двоичному списку, я получаю следующую ошибку:

2014-08-12 17:02:23.598 plist_tests[95709:507] could not deserialize plist: Error Domain=NSCocoaErrorDomain Code=3840 "The data couldn’t be read because it isn’t in the correct format." (Unexpected character b at line 1) UserInfo=0x7f9f2040cd60 {NSDebugDescription=Unexpected character b at line 1, kCFPropertyListOldStyleParsingError=The data couldn’t be read because it isn’t in the correct format.}

Вот код Обратите внимание, что я не могу использовать dictionaryWithContentsOfFile для моего варианта использования.

#include <iostream>
#include <fstream>
#include <sstream>
#include <string>

#include <boost/filesystem/operations.hpp>
#include <boost/filesystem/path.hpp>

#import <Foundation/Foundation.h>

class Status {
public:
Status(int c, std::string m) : code_(c), message_(m) {}
public:
int getCode() { return code_; }
std::string getMessage() { return message_; }
bool ok() { return getCode() == 0; }
std::string toString() { return getMessage(); }
private:
int code_;
std::string message_;
};

Status readFile(const std::string& path, std::string& content) {
if (!boost::filesystem::exists(path)) {
return Status(1, "File not found");
}

std::ifstream file_h(path);
if (file_h) {
file_h.seekg (0, file_h.end);
int len = file_h.tellg();
file_h.seekg (0, file_h.beg);
char *buffer = new char [len];
file_h.read(buffer, len);
if (!file_h) {
return Status(1, "Could not entire file");
}
content.assign(buffer, len);
} else {
return Status(1, "Could not open file for reading");
}

return Status(0, "OK");
}

void parsePlist(const std::string& path) {
std::string file_content;
Status readFileStatus = readFile(path, file_content);
if (!readFileStatus.ok()) {
NSLog(@"Couldn't read file");
return;
}
NSData *plist_content = [NSData dataWithBytes:file_content.c_str()
length:file_content.size()];

NSError *error;
NSPropertyListFormat plist_format;
id plist = [NSPropertyListSerialization propertyListWithData:plist_content
options:NSPropertyListImmutable
format:&plist_format
error:&error];

if (plist == nil) {
NSLog(@"could not deserialize plist: %@", error);
} else {
switch (plist_format) {
case NSPropertyListOpenStepFormat:
NSLog(@"plist was in openstep format");
break;
case NSPropertyListXMLFormat_v1_0:
NSLog(@"plist was in xml format");
break;
case NSPropertyListBinaryFormat_v1_0:
NSLog(@"plist was in binary format");
break;
default:
NSLog(@"plist was in unknown format");
break;
}
}
}

int main(int argc, char *argv[]) {
if (argc < 2) {
std::cout << "Usage: plist <filename>" << std::endl;
return 1;
}
parsePlist(argv[1]);
return 0;
}

Скомпилировать: g++ -lboost_system -lboost_filesystem -lglog -fobjc-arc -fobjc-link-runtime -framework Foundation plist.mm -o plist

Причина, по которой я чешу голову, заключается в том, что если я plutil -convert xml1 file.plist -o - на бинарном листе, он работает просто отлично.

0

Решение

То, как вы конвертируете данные в NSString а затем NSData несколько плохо для XML и очень плохо для двоичных данных. Вместо этого сделайте это:

NSData *plist_content = [NSData dataWithBytes: file_content.c_str()
length: file_content.size() ];

Существует также проблема с вашим readFile функция. Рассмотрим линию

content = std::string(buffer);

Как std :: string знает длину буфера? Он ищет байт NUL, но это неверно для двоичных данных. Вы можете заменить эту строку на

content.assign( buffer, len );

Или, если ваш путь абсолютный, вы можете избавиться от readFile и скажи

NSData *plist_content = [NSData dataWithContentsOfFile:
[NSString stringWithUTF8String: path.c_str() ];
1

Другие решения


По вопросам рекламы [email protected]