/* */ #include "MetaFileUtil.h" #include "Data.h" #include "Dictionary.h" #include "List.h" #include "File.h" #include "DlAbortEx.h" #include "message.h" #include #include // <-- TODO remove this if strtoul is replaced with Util::parseUInt() namespace aria2 { MetaEntry* MetaFileUtil::parseMetaFile(const std::string& file) { File f(file); size_t len = f.size(); unsigned char* buf = new unsigned char[len]; FILE* fp = fopen(file.c_str(), "r+b"); try { if(!fp) { throw DlAbortEx("cannot open metainfo file"); } if(fread(buf, len, 1, fp) != 1) { fclose(fp); throw DlAbortEx("cannot read metainfo"); } fclose(fp); fp = 0; MetaEntry* entry = bdecoding(buf, len); delete [] buf; return entry; } catch(RecoverableException& ex) { delete [] buf; if(fp) { fclose(fp); } throw; } } MetaEntry* MetaFileUtil::bdecoding(const unsigned char* buf, size_t len) { const unsigned char* p = buf; const unsigned char* end = buf+len; return bdecodingR(&p, end); } MetaEntry* MetaFileUtil::bdecodingR(const unsigned char** pp, const unsigned char* end) { if(*pp >= end) { throw DlAbortEx("Malformed metainfo"); } MetaEntry* e; switch(**pp) { case 'd': (*pp)++; e = parseDictionaryTree(pp, end); break; case 'l': (*pp)++; e = parseListTree(pp, end); break; case 'i': (*pp)++; e = decodeInt(pp, end); break; default: e = decodeWord(pp, end); } return e; } Dictionary* MetaFileUtil::parseDictionaryTree(const unsigned char** pp, const unsigned char* end) { if(*pp >= end) { throw DlAbortEx("Malformed metainfo"); } Dictionary* dic = new Dictionary(); try { while(1) { if(**pp == 'e') { (*pp)++; break; } std::string name = decodeWordAsString(pp, end); MetaEntry* e = bdecodingR(pp, end); dic->put(name, e); } return dic; } catch(RecoverableException& ex) { delete dic; throw; } } List* MetaFileUtil::parseListTree(const unsigned char** pp, const unsigned char* end) { if(*pp >= end) { throw DlAbortEx("Malformed metainfo"); } List* lis = new List(); try { while(1) { if(**pp == 'e') { (*pp)++; break; } MetaEntry* e = bdecodingR(pp, end); lis->add(e); } return lis; } catch(RecoverableException& ex) { delete lis; throw; } } Data* MetaFileUtil::decodeInt(const unsigned char** pp, const unsigned char* end) { if(*pp >= end) { throw DlAbortEx(EX_MALFORMED_META_INFO); } unsigned char* endTerm = reinterpret_cast(memchr(*pp, 'e', end-*pp)); // TODO if endTerm is null if(!endTerm) { throw DlAbortEx(EX_MALFORMED_META_INFO); } size_t numSize = endTerm-*pp; Data* data = new Data(*pp, numSize, true); *pp += numSize+1; return data; } Data* MetaFileUtil::decodeWord(const unsigned char** pp, const unsigned char* end) { if(*pp >= end) { throw DlAbortEx("Malformed metainfo"); } unsigned char* delim = reinterpret_cast(memchr(*pp, ':', end-*pp)); // TODO if delim is null if(delim == *pp || !delim) { throw DlAbortEx(EX_MALFORMED_META_INFO); } size_t numSize = delim-*pp; unsigned char* temp = new unsigned char[numSize+1]; memcpy(temp, *pp, numSize); temp[numSize] = '\0'; char* endptr; unsigned long int size = strtoul(reinterpret_cast(temp), &endptr, 10); if(*endptr != '\0') { delete [] temp; throw DlAbortEx(EX_MALFORMED_META_INFO); } delete [] temp; if(delim+1+size > end) { throw DlAbortEx(EX_MALFORMED_META_INFO); } Data* data = new Data(delim+1, size); *pp = delim+1+size; return data; } std::string MetaFileUtil::decodeWordAsString(const unsigned char** pp, const unsigned char* end) { Data* data = decodeWord(pp, end); std::string str = data->toString(); delete data; return str; } } // namespace aria2