OpenCPN Partial API docs
Loading...
Searching...
No Matches
chartdata_input_stream.cpp
1/******************************************************************************
2 *
3 * Project: OpenCPN
4 * Purpose: Support XZ compressed charts
5 * Author: Sean D'Epagnier
6 *
7 ***************************************************************************
8 * Copyright (C) 2016 by David S. Register *
9 * *
10 * This program is free software; you can redistribute it and/or modify *
11 * it under the terms of the GNU General Public License as published by *
12 * the Free Software Foundation; either version 2 of the License, or *
13 * (at your option) any later version. *
14 * *
15 * This program is distributed in the hope that it will be useful, *
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
18 * GNU General Public License for more details. *
19 * *
20 * You should have received a copy of the GNU General Public License *
21 * along with this program; if not, write to the *
22 * Free Software Foundation, Inc., *
23 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
24 ***************************************************************************
25 *
26 */
27
28// For compilers that support precompilation, includes "wx.h".
29#include <wx/wxprec.h>
30
31#ifndef WX_PRECOMP
32#include <wx/wx.h>
33#endif // precompiled headers
34
35#include <wx/filename.h>
36#include <wx/log.h>
37#include <wx/wfstream.h>
38
39#include "config.h"
40#include "chartdata_input_stream.h"
41
42#ifdef OCPN_USE_LZMA
43
44wxCompressedFFileInputStream::wxCompressedFFileInputStream(
45 const wxString &fileName) {
46 init_lzma();
47 m_file = new wxFFile(fileName, "rb");
48}
49
50wxCompressedFFileInputStream::~wxCompressedFFileInputStream() {
51 delete m_file;
52 lzma_end(&strm);
53}
54
55size_t wxCompressedFFileInputStream::OnSysRead(void *buffer, size_t size) {
56 lzma_action action = LZMA_RUN;
57
58 strm.next_out = (uint8_t *)buffer;
59 strm.avail_out = size;
60
61 for (;;) {
62 if (strm.avail_in == 0) {
63 if (!m_file->Eof()) {
64 strm.next_in = inbuf;
65 strm.avail_in = m_file->Read(inbuf, sizeof inbuf);
66
67 if (m_file->Error()) return 0;
68
69 } else
70 action = LZMA_FINISH;
71 }
72
73 lzma_ret ret = lzma_code(&strm, action);
74
75 if (strm.avail_out == 0 || ret == LZMA_STREAM_END)
76 return size - strm.avail_out;
77
78 if (ret != LZMA_OK) {
79 m_lasterror = wxSTREAM_READ_ERROR;
80 return 0;
81 }
82 }
83 return 0;
84}
85
86wxFileOffset wxCompressedFFileInputStream::OnSysSeek(wxFileOffset pos,
87 wxSeekMode mode) {
88 // rewind to start is possible
89 if (pos == 0 && mode == wxFromStart) {
90 lzma_end(&strm);
91 init_lzma();
92 return m_file->Seek(pos, mode);
93 }
94
95 return wxInvalidOffset;
96}
97
98wxFileOffset wxCompressedFFileInputStream::OnSysTell() const {
99 return strm.total_out;
100}
101
102void wxCompressedFFileInputStream::init_lzma() {
103 lzma_stream s = LZMA_STREAM_INIT;
104 memcpy(&strm, &s, sizeof s);
105 lzma_ret ret = lzma_stream_decoder(&strm, UINT64_MAX, LZMA_CONCATENATED);
106
107 if (ret != LZMA_OK) m_lasterror = wxSTREAM_READ_ERROR;
108}
109
110ChartDataNonSeekableInputStream::ChartDataNonSeekableInputStream(
111 const wxString &fileName) {
112 if (fileName.Upper().EndsWith("XZ"))
113 m_stream = new wxCompressedFFileInputStream(fileName);
114 else
115 m_stream = new wxFFileInputStream(fileName);
116}
117
118ChartDataNonSeekableInputStream::~ChartDataNonSeekableInputStream() {
119 delete m_stream;
120}
121
122size_t ChartDataNonSeekableInputStream::OnSysRead(void *buffer, size_t size) {
123 m_stream->Read(buffer, size);
124 return m_stream->LastRead();
125}
126
127wxFileOffset ChartDataNonSeekableInputStream::OnSysSeek(wxFileOffset pos,
128 wxSeekMode mode) {
129 return m_stream->SeekI(pos, mode);
130}
131
132wxFileOffset ChartDataNonSeekableInputStream::OnSysTell() const {
133 return m_stream->TellI();
134}
135
136ChartDataInputStream::ChartDataInputStream(const wxString &fileName) {
137 if (fileName.Upper().EndsWith("XZ")) {
138 // decompress to temp file to allow seeking
139 m_tempfilename =
140 wxFileName::CreateTempFileName(wxFileName(fileName).GetFullName());
141 wxCompressedFFileInputStream stream(fileName);
142 wxFFileOutputStream tmp(m_tempfilename);
143
144 char buffer[8192];
145 int len;
146 do {
147 stream.Read(buffer, sizeof buffer);
148 len = stream.LastRead();
149 tmp.Write(buffer, len);
150 } while (len == sizeof buffer);
151
152 // do some error checking here?
153
154 tmp.Close();
155 m_stream = new wxFFileInputStream(m_tempfilename);
156 } else
157 m_stream = new wxFFileInputStream(fileName);
158}
159
160ChartDataInputStream::~ChartDataInputStream() {
161 // close it
162 delete m_stream;
163 // delete the temp file, how do we remove temp files if the program crashed?
164 if (!m_tempfilename.empty()) wxRemoveFile(m_tempfilename);
165}
166
167size_t ChartDataInputStream::OnSysRead(void *buffer, size_t size) {
168 m_stream->Read(buffer, size);
169 return m_stream->LastRead();
170}
171
172wxFileOffset ChartDataInputStream::OnSysSeek(wxFileOffset pos,
173 wxSeekMode mode) {
174 return m_stream->SeekI(pos, mode);
175}
176
177wxFileOffset ChartDataInputStream::OnSysTell() const {
178 return m_stream->TellI();
179}
180
181bool DecompressXZFile(const wxString &input_path, const wxString &output_path) {
182 if (!wxFileExists(input_path)) {
183 return false;
184 }
185 wxCompressedFFileInputStream in(input_path);
186 wxFFileOutputStream out(output_path);
187
188 char buffer[8192];
189 int len;
190 do {
191 in.Read(buffer, sizeof buffer);
192 len = in.LastRead();
193 out.Write(buffer, len);
194 } while (len == sizeof buffer);
195
196 return in.GetLastError() != wxSTREAM_READ_ERROR;
197}
198
199#else // OCPN_USE_LZMA
200
201bool DecompressXZFile(const wxString &input_path, const wxString &output_path) {
202 wxLogMessage(_T("Failed to decompress: ") + input_path);
203 wxLogMessage(_T("OpenCPN compiled without liblzma support"));
204
205 return false;
206}
207
208#endif // OCPN_USE_LZMA