1 #include "archivefile.h"
2 
ArchiveFile(QString fileName,bool sequential,bool deflate,QObject * parent)3 ArchiveFile::ArchiveFile(QString fileName, bool sequential, bool deflate, QObject *parent) :
4 	QObject(parent),
5 	m_archive(0),
6 	m_entry(0),
7 	m_fileName(fileName),
8 	m_sequential(sequential),
9 	m_deflate(deflate),
10 	m_openMode(QIODevice::ReadOnly)
11 {
12 }
13 
~ArchiveFile()14 ArchiveFile::~ArchiveFile()
15 {
16 	if ( isOpen() )
17 		close();
18 }
19 
open(QIODevice::OpenMode openMode,QString fileName)20 bool ArchiveFile::open(QIODevice::OpenMode openMode, QString fileName)
21 {
22 	if ( isOpen() )
23 		close();
24 	if ( !fileName.isEmpty() )
25 		m_fileName = fileName;
26 	m_openMode = openMode;
27 	m_entry = 0;
28 	int result = 0;
29 	switch ( m_openMode ) {
30 		case QIODevice::WriteOnly:
31 			m_archive = archive_write_new();
32 			archive_write_set_format_zip(m_archive);
33 			if ( m_deflate )
34 				archive_write_set_options(m_archive, "compression=deflate");
35 			else
36 				archive_write_set_options(m_archive, "compression=store");
37 			result = archive_write_open_filename(m_archive, m_fileName.toUtf8().constData());
38 			if ( result != ARCHIVE_OK) {
39 				archive_write_free(m_archive);
40 				m_archive = 0;
41 				return false;
42 			} else
43 				return true;
44 		case QIODevice::ReadOnly:
45 		default:
46 			m_archive = archive_read_new();
47 			archive_read_support_filter_all(m_archive);
48 			archive_read_support_format_all(m_archive);
49 			result = archive_read_open_filename(m_archive, m_fileName.toUtf8().constData(), QMC2_ARCHIVE_BLOCK_SIZE);
50 			if ( result != ARCHIVE_OK) {
51 				archive_read_free(m_archive);
52 				m_archive = 0;
53 				return false;
54 			} else {
55 				if ( !m_sequential )
56 					createEntryList();
57 				return true;
58 			}
59 	}
60 }
61 
close()62 void ArchiveFile::close()
63 {
64 	entryList().clear();
65 	m_nameToIndexCache.clear();
66 	if ( isOpen() ) {
67 		switch ( m_openMode ) {
68 			case QIODevice::WriteOnly:
69 				archive_write_close(m_archive);
70 				archive_write_free(m_archive);
71 				break;
72 			case QIODevice::ReadOnly:
73 			default:
74 				archive_read_close(m_archive);
75 				archive_read_free(m_archive);
76 				break;
77 		}
78 		m_archive = 0;
79 		m_entry = 0;
80 	}
81 }
82 
reopen()83 void ArchiveFile::reopen()
84 {
85 	archive_read_free(m_archive);
86 	m_archive = archive_read_new();
87 	archive_read_support_filter_all(m_archive);
88 	archive_read_support_format_all(m_archive);
89 	archive_read_open_filename(m_archive, m_fileName.toUtf8().constData(), QMC2_ARCHIVE_BLOCK_SIZE);
90 }
91 
writeEntryDataBig(const BigByteArray & buffer)92 qint64 ArchiveFile::writeEntryDataBig(const BigByteArray &buffer)
93 {
94 	qint64 len = 0;
95 	for (int i = 0; i < buffer.chunks(); i++)
96 		len += writeEntryData(buffer.chunk(i));
97 	return len;
98 }
99 
seekNextEntry(ArchiveEntryMetaData * metaData,bool * reset)100 bool ArchiveFile::seekNextEntry(ArchiveEntryMetaData *metaData, bool *reset)
101 {
102 	if ( !isOpen() )
103 		return false;
104 	if ( !m_sequential ) {
105 		if ( reset != 0 && *reset ) {
106 			reopen();
107 			*reset = false;
108 		}
109 	}
110 	if ( archive_read_next_header(m_archive, &m_entry) == ARCHIVE_OK ) {
111 		*metaData = ArchiveEntryMetaData(archive_entry_pathname(m_entry), archive_entry_size(m_entry), QDateTime::fromTime_t(archive_entry_mtime(m_entry)));
112 		return true;
113 	} else
114 		return false;
115 }
116 
seekEntry(uint index)117 bool ArchiveFile::seekEntry(uint index)
118 {
119 	if ( !isOpen() )
120 		return false;
121 	ArchiveEntryMetaData metadata = entryList()[index];
122 	archive_read_free(m_archive);
123 	m_archive = archive_read_new();
124 	archive_read_support_filter_all(m_archive);
125 	archive_read_support_format_all(m_archive);
126 	archive_read_open_filename(m_archive, m_fileName.toUtf8().constData(), QMC2_ARCHIVE_BLOCK_SIZE);
127 	while ( archive_read_next_header(m_archive, &m_entry) == ARCHIVE_OK )
128 		if ( metadata.name().compare(archive_entry_pathname(m_entry), Qt::CaseSensitive) == 0 )
129 			return true;
130 	return false;
131 }
132 
readEntry(QByteArray & buffer)133 qint64 ArchiveFile::readEntry(QByteArray &buffer)
134 {
135 	if ( !isOpen() || writeMode() )
136 		return 0;
137 #if defined(QMC2_OS_WIN)
138 	__int64 size = archive_entry_size(m_entry);
139 #else
140 	int64_t size = archive_entry_size(m_entry);
141 #endif
142 	if ( size > 0 ) {
143 		char *data = new char[size];
144 #if defined(QMC2_OS_WIN) && defined(_MSC_VER)
145 		SSIZE_T len = archive_read_data(m_archive, data, size);
146 #else
147 		ssize_t len = archive_read_data(m_archive, data, size);
148 #endif
149 		if ( len > 0 ) {
150 			buffer = QByteArray(data, len);
151 			delete [] data;
152 			return len;
153 		}
154 		delete [] data;
155 	}
156 	return 0;
157 }
158 
createEntry(QString name,size_t size)159 bool ArchiveFile::createEntry(QString name, size_t size)
160 {
161 	m_entry = archive_entry_new();
162 	archive_entry_set_pathname(m_entry, name.toUtf8().constData());
163 	archive_entry_set_size(m_entry, size);
164 	archive_entry_set_filetype(m_entry, AE_IFREG);
165 	archive_entry_set_perm(m_entry, 0644);
166 	archive_entry_set_mtime(m_entry, QDateTime::currentDateTime().toTime_t(), 0);
167 	archive_write_header(m_archive, m_entry);
168 	return !hasError();
169 }
170 
closeEntry()171 void ArchiveFile::closeEntry()
172 {
173 	archive_write_finish_entry(m_archive);
174 	archive_entry_free(m_entry);
175 }
176 
createEntryList()177 void ArchiveFile::createEntryList()
178 {
179 	entryList().clear();
180 	m_nameToIndexCache.clear();
181 	if ( !isOpen() )
182 		return;
183 	struct archive_entry *entry;
184 	int counter = 0;
185 	while ( archive_read_next_header(m_archive, &entry) == ARCHIVE_OK ) {
186 		QString entryName(archive_entry_pathname(entry));
187 		entryList() << ArchiveEntryMetaData(entryName, archive_entry_size(entry), QDateTime::fromTime_t(archive_entry_mtime(entry)));
188 		m_nameToIndexCache.insert(entryName, counter++);
189 		archive_read_data_skip(m_archive);
190 	}
191 }
192