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