mirror of https://github.com/aria2/aria2
209 lines
5.3 KiB
C++
209 lines
5.3 KiB
C++
/* <!-- copyright */
|
|
/*
|
|
* aria2 - The high speed download utility
|
|
*
|
|
* Copyright (C) 2006 Tatsuhiro Tsujikawa
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
*
|
|
* In addition, as a special exception, the copyright holders give
|
|
* permission to link the code of portions of this program with the
|
|
* OpenSSL library under certain conditions as described in each
|
|
* individual source file, and distribute linked combinations
|
|
* including the two.
|
|
* You must obey the GNU General Public License in all respects
|
|
* for all of the code used other than OpenSSL. If you modify
|
|
* file(s) with this exception, you may extend this exception to your
|
|
* version of the file(s), but you are not obligated to do so. If you
|
|
* do not wish to do so, delete this exception statement from your
|
|
* version. If you delete this exception statement from all source
|
|
* files in the program, then also delete it here.
|
|
*/
|
|
/* copyright --> */
|
|
#include "MetaFileUtil.h"
|
|
#include "Data.h"
|
|
#include "Dictionary.h"
|
|
#include "List.h"
|
|
#include "File.h"
|
|
#include "DlAbortEx.h"
|
|
#include "message.h"
|
|
#include <cstring>
|
|
|
|
namespace aria2 {
|
|
|
|
MetaEntry* MetaFileUtil::parseMetaFile(const std::string& file) {
|
|
File f(file);
|
|
int32_t len = f.size();
|
|
char* buf = new char[len];
|
|
FILE* fp = fopen(file.c_str(), "r+b");
|
|
try {
|
|
if(fp == NULL) {
|
|
throw new DlAbortEx("cannot open metainfo file");
|
|
}
|
|
if(fread(buf, len, 1, fp) != 1) {
|
|
fclose(fp);
|
|
throw new DlAbortEx("cannot read metainfo");
|
|
}
|
|
fclose(fp);
|
|
fp = NULL;
|
|
MetaEntry* entry = bdecoding(buf, len);
|
|
delete [] buf;
|
|
return entry;
|
|
} catch(RecoverableException* ex) {
|
|
delete [] buf;
|
|
if(fp != NULL) {
|
|
fclose(fp);
|
|
}
|
|
throw;
|
|
}
|
|
}
|
|
|
|
MetaEntry* MetaFileUtil::bdecoding(const char* buf, int32_t len) {
|
|
MetaEntry* entry = NULL;
|
|
try{
|
|
const char* p = buf;
|
|
const char* end = buf+len;
|
|
entry = bdecodingR(&p, end);
|
|
return entry;
|
|
} catch(RecoverableException* ex) {
|
|
if(entry != NULL) {
|
|
delete entry;
|
|
}
|
|
throw;
|
|
}
|
|
}
|
|
|
|
MetaEntry* MetaFileUtil::bdecodingR(const char** pp, const char* end) {
|
|
if(*pp >= end) {
|
|
throw new 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 char** pp, const char* end) {
|
|
if(*pp >= end) {
|
|
throw new 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 char** pp, const char* end) {
|
|
if(*pp >= end) {
|
|
throw new 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 char** pp, const char* end) {
|
|
if(*pp >= end) {
|
|
throw new DlAbortEx(EX_MALFORMED_META_INFO);
|
|
}
|
|
char* endTerm = (char*)memchr(*pp, 'e', end-*pp);
|
|
// TODO if endTerm is null
|
|
if(endTerm == NULL) {
|
|
throw new DlAbortEx(EX_MALFORMED_META_INFO);
|
|
}
|
|
int32_t numSize = endTerm-*pp;
|
|
|
|
Data* data = new Data(*pp, numSize, true);
|
|
*pp += numSize+1;
|
|
return data;
|
|
}
|
|
|
|
Data* MetaFileUtil::decodeWord(const char** pp, const char* end) {
|
|
if(*pp >= end) {
|
|
throw new DlAbortEx("Malformed metainfo");
|
|
}
|
|
char* delim = (char*)memchr(*pp, ':', end-*pp);
|
|
// TODO if delim is null
|
|
if(delim == *pp || delim == NULL) {
|
|
throw new DlAbortEx(EX_MALFORMED_META_INFO);
|
|
}
|
|
int32_t numSize = delim-*pp;
|
|
char* temp = new char[numSize+1];
|
|
memcpy(temp, *pp, numSize);
|
|
temp[numSize] = '\0';
|
|
char* endptr;
|
|
int32_t size = strtol(temp, &endptr, 10);
|
|
if(*endptr != '\0') {
|
|
delete [] temp;
|
|
throw new DlAbortEx(EX_MALFORMED_META_INFO);
|
|
}
|
|
delete [] temp;
|
|
|
|
if(delim+1+size > end) {
|
|
throw new DlAbortEx(EX_MALFORMED_META_INFO);
|
|
}
|
|
|
|
Data* data = new Data(delim+1, size);
|
|
*pp = delim+1+size;
|
|
return data;
|
|
}
|
|
|
|
std::string MetaFileUtil::decodeWordAsString(const char** pp, const char* end) {
|
|
Data* data = decodeWord(pp, end);
|
|
std::string str = data->toString();
|
|
delete data;
|
|
return str;
|
|
}
|
|
|
|
} // namespace aria2
|