From 86e3c18c33372a02ae2caafed6395ecf2e483f8d Mon Sep 17 00:00:00 2001 From: Gregory Hainaut Date: Sun, 17 May 2015 15:53:03 +0200 Subject: [PATCH] gsdx-linux: add code to read xz file Linux only to avoid the extra dependency on windows --- plugins/GSdx/CMakeLists.txt | 2 + plugins/GSdx/GSLzma.cpp | 162 ++++++++++++++++++++++++++++++++++++ plugins/GSdx/GSLzma.h | 87 +++++++++++++++++++ 3 files changed, 251 insertions(+) create mode 100644 plugins/GSdx/GSLzma.cpp create mode 100644 plugins/GSdx/GSLzma.h diff --git a/plugins/GSdx/CMakeLists.txt b/plugins/GSdx/CMakeLists.txt index 2e4c8b8a90..0ce2db6461 100644 --- a/plugins/GSdx/CMakeLists.txt +++ b/plugins/GSdx/CMakeLists.txt @@ -83,6 +83,7 @@ set(GSdxSources GSFunctionMap.cpp GSLinuxDialog.cpp GSLocalMemory.cpp + GSLzma.cpp GSPerfMon.cpp GSPng.cpp GSRasterizer.cpp @@ -203,6 +204,7 @@ set(GSdxFinalLibs ${GSdxFinalLibs} ${GTK2_LIBRARIES} ${LIBC_LIBRARIES} "-lpng" # yes it sucks + "-llzma" ) if(EGL_API AND EGL_FOUND) diff --git a/plugins/GSdx/GSLzma.cpp b/plugins/GSdx/GSLzma.cpp new file mode 100644 index 0000000000..9e171a25b7 --- /dev/null +++ b/plugins/GSdx/GSLzma.cpp @@ -0,0 +1,162 @@ +/* + * Copyright (C) 2015-2015 Gregory hainaut + * + * 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, 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 GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#include "stdafx.h" +#include "GSLzma.h" + +#ifdef __linux__ + +GSDumpFile::GSDumpFile(char* filename) { + m_fp = fopen(filename, "rb"); + if (m_fp == NULL) { + fprintf(stderr, "failed to open %s\n", filename); + throw "BAD"; // Just exit the program + } +} + +GSDumpFile::~GSDumpFile() { + if (m_fp) + fclose(m_fp); +} + +/******************************************************************/ +#ifdef LZMA_SUPPORTED + +GSDumpLzma::GSDumpLzma(char* filename) : GSDumpFile(filename) { + + memset(&m_strm, 0, sizeof(lzma_stream)); + + lzma_ret ret = lzma_stream_decoder(&m_strm, UINT32_MAX, LZMA_CONCATENATED); + + if (ret != LZMA_OK) { + fprintf(stderr, "Error initializing the decoder! (error code %u)\n", ret); + throw "BAD"; // Just exit the program + } + + m_buff_size = 1024*1024; + m_area = (uint8_t*)_aligned_malloc(m_buff_size, 32); + m_inbuf = (uint8_t*)_aligned_malloc(BUFSIZ, 32); + m_avail = 0; + m_start = 0; + m_eof = false; + + m_strm.avail_in = 0; + m_strm.next_in = m_inbuf; + + m_strm.avail_out = m_buff_size; + m_strm.next_out = m_area; +} + +void GSDumpLzma::Decompress() { + lzma_action action = LZMA_RUN; + + m_strm.next_out = m_area; + m_strm.avail_out = m_buff_size; + + // Nothing left in the input buffer. Read data from the file + if (m_strm.avail_in == 0 && !feof(m_fp)) { + m_strm.next_in = m_inbuf; + m_strm.avail_in = fread(m_inbuf, 1, BUFSIZ, m_fp); + + if (ferror(m_fp)) { + fprintf(stderr, "Read error: %s\n", strerror(errno)); + throw "BAD"; // Just exit the program + } + + if (feof(m_fp)) { + action = LZMA_FINISH; + m_eof = true; + } + } + + lzma_ret ret = lzma_code(&m_strm, action); + + if (ret != LZMA_OK) { + if (ret == LZMA_STREAM_END) + fprintf(stderr, "LZMA decoder finished without error\n\n"); + else { + fprintf(stderr, "Decoder error: (error code %u)\n", ret); + throw "BAD"; // Just exit the program + } + } + + m_start = 0; + m_avail = m_buff_size - m_strm.avail_out; +} + +bool GSDumpLzma::IsEof() { + return m_eof && (m_avail == 0); +} + +void GSDumpLzma::Read(void* ptr, size_t size) { + size_t off = 0; + uint8_t* dst = (uint8_t*)ptr; + while (size) { + if (m_avail == 0) { + Decompress(); + } + + size_t l = min(size, m_avail); + memcpy(dst + off, m_area+m_start, l); + m_avail -= l; + size -= l; + m_start += l; + off += l; + } +} + +GSDumpLzma::~GSDumpLzma() { + lzma_end(&m_strm); + + if (m_inbuf) + _aligned_free(m_inbuf); + if (m_area) + _aligned_free(m_area); +} + +#endif + +/******************************************************************/ + +GSDumpRaw::GSDumpRaw(char* filename) : GSDumpFile(filename) { +} + +GSDumpRaw::~GSDumpRaw() { +} + +bool GSDumpRaw::IsEof() { + return feof(m_fp); +} + +void GSDumpRaw::Read(void* ptr, size_t size) { + if (size == 1) { + // I don't know why but read of size 1 is not happy + int v = fgetc(m_fp); + memcpy(ptr, &v, 1); + } else { + size_t ret = fread(ptr, 1, size, m_fp); + if (ret != size) { + fprintf(stderr, "GSDumpRaw:: Read error\n"); + throw "BAD"; // Just exit the program + } + } +} + +#endif diff --git a/plugins/GSdx/GSLzma.h b/plugins/GSdx/GSLzma.h new file mode 100644 index 0000000000..c0c54fb3e6 --- /dev/null +++ b/plugins/GSdx/GSLzma.h @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2015-2015 Gregory hainaut + * + * 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, 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 GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#ifdef __linux__ + +#ifdef LZMA_SUPPORTED +#include +#endif + +class GSDumpFile { + protected: + FILE* m_fp; + + GSDumpFile(char* filename); + virtual ~GSDumpFile(); + + public: + virtual bool IsEof() = 0; + virtual void Read(void* ptr, size_t size) = 0; +}; + +#ifdef LZMA_SUPPORTED +class GSDumpLzma : public GSDumpFile { + + lzma_stream m_strm; + + size_t m_buff_size; + uint8_t* m_area; + uint8_t* m_inbuf; + + size_t m_avail; + size_t m_start; + bool m_eof; + + void Decompress(); + + public: + + GSDumpLzma(char* filename); + virtual ~GSDumpLzma(); + + bool IsEof(); + void Read(void* ptr, size_t size); +}; +#endif + +class GSDumpRaw : public GSDumpFile { + + lzma_stream m_strm; + + size_t m_buff_size; + uint8_t* m_area; + uint8_t* m_inbuf; + + size_t m_avail; + size_t m_start; + bool m_eof; + + void Decompress(); + + public: + + GSDumpRaw(char* filename); + virtual ~GSDumpRaw(); + + bool IsEof(); + void Read(void* ptr, size_t size); +}; + +#endif