Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
lzstring.pro.user
/old/
/build/
1 change: 1 addition & 0 deletions .idea/.name

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 7 additions & 0 deletions .idea/misc.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions .idea/modules.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions .idea/qt-lzstring.iml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

71 changes: 71 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
cmake_minimum_required(VERSION 3.16)
project(qt_lzstring LANGUAGES CXX)

include(CTest)
enable_testing()

set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

# Enable Qt's automoc so test target with Q_OBJECT works when built (only affects Qt test target).
set(CMAKE_AUTOMOC ON)

# Core sources reused by main executable and (optionally) tests (Qt sources kept separate so non-Qt builds don't require Qt headers).
set(LZSTRING_SOURCES
src/lzstring.cpp
src/LZCore.cpp
src/StdLZPlatform.cpp
)
set(LZSTRING_HEADERS
src/ILZPlatform.h
src/LZCore.h
src/StdLZPlatform.h
src/lzstring.h
)

# Build the CLI without Qt dependency (forces use of std platform implementation)
add_executable(lzstring
${LZSTRING_SOURCES}
${LZSTRING_HEADERS}
src/main.cpp
)
# Only the CLI gets this define; tests (if enabled) can use Qt implementation.
target_compile_definitions(lzstring PRIVATE LZSTRING_NO_QT)

# Organize sources in IDEs (portable)
source_group(TREE ${CMAKE_SOURCE_DIR}/src PREFIX "Source" FILES ${LZSTRING_SOURCES} ${LZSTRING_HEADERS})

# -------------------------------------------------------------
# Optional Qt tests (converted from original qmake project)
# -------------------------------------------------------------
option(BUILD_QT_TESTS "Build Qt-based unit and benchmark tests" ON)
if(BUILD_QT_TESTS)
find_package(QT NAMES Qt6 Qt5 COMPONENTS Core Test QUIET)
if(QT_FOUND)
find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Core Test REQUIRED)
# Flag to let subdirectory know Qt is available.
set(LZSTRING_QT_AVAILABLE ON CACHE INTERNAL "Qt available for tests")
add_subdirectory(tests)
else()
message(STATUS "Qt not found; skipping BUILD_QT_TESTS")
endif()
endif()

# Non-Qt round-trip test exercising StdLZPlatform (always available, no Qt dependency)
add_executable(lzstring_std_test
tests/lzstring_test/std_roundtrip_test.cpp
${LZSTRING_SOURCES}
${LZSTRING_HEADERS}
)

target_compile_definitions(lzstring_std_test PRIVATE LZSTRING_NO_QT)

target_include_directories(lzstring_std_test PRIVATE ${CMAKE_SOURCE_DIR}/src)

add_test(NAME lzstring_std_test COMMAND lzstring_std_test)

# Register Qt test if it exists
if(BUILD_QT_TESTS AND TARGET lzstring_test)
add_test(NAME lzstring_test COMMAND lzstring_test)
set_tests_properties(lzstring_test PROPERTIES WORKING_DIRECTORY $<TARGET_FILE_DIR:lzstring_test>)
endif()
146 changes: 129 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,18 +1,130 @@
# qt-lzstring

<h2>Qt implementation of LZ-String, version 1.4.4.</h2>
<p>
Based on the LZ-String compression algorithm found here:<br/>
http://pieroxy.net/blog/pages/lz-string/index.html
</p>
<p>
WTFPL Licence<br/>
http://www.wtfpl.net/
</p>
Implemented functions:<br/>
<ul>
<li>compress() / decompress() - <b>YES</b></li>
<li>compressToUTF16() / decompressFromUTF16() - <b>YES</b></li>
<li>compressToBase64() / decompressFromBase64() - <b>YES</b></li>
<li>compressToUint8Array() / decompressFromUint8Array() - <b>NO</b></li>
<li>compressToEncodedURIComponent() / decompressFromEncodedURIComponent() - <b>NO</b></li>
</ul>
Qt implementation of LZ-String with a platform-agnostic core and a simple CLI.

Refactor highlights
- LZ core extracted to `src/LZCore.{h,cpp}`. It contains the compression/decompression logic and depends only on an abstract platform interface.
- New platform interface `src/ILZPlatform.h` encapsulates string/character operations the core needs.
- Two platform implementations:
- `src/QtLZPlatform.{h,cpp}` for Qt builds (uses QString/QChar/QHash).
- `src/StdLZPlatform.{h,cpp}` for non-Qt builds (uses std::string and simple containers).
- `src/lzstring.cpp` is a thin facade that selects the platform at compile time and delegates to `LZCore`.
- Build files (CMake and qmake .pri) updated to include the new sources.

Public API
- `LZString` public static methods are unchanged: `compress`, `compressToUTF16`, `compressToBase64`, and corresponding `decompress*` variants.

Notes
- The core does not depend on Qt; only the platform layer bridges to Qt or std. This improves separation of concerns and makes the LZ implementation reusable.
- Non-Qt mode (CMake default) is intended for simple CLI usage. For full Unicode fidelity and UTF‑16/Base64 behavior identical to the original Qt implementation, build/run the Qt test target which uses `QString` code units.

Installation (Linux)
- Prerequisites: a C++ compiler and either Qt (for the full-featured test suite) or just CMake (for the minimal non‑Qt CLI + std round‑trip tests).

Debian/Ubuntu
```bash
sudo apt-get update
sudo apt-get install -y build-essential cmake
# For Qt tests (optional)
sudo apt-get install -y qtbase5-dev qtbase5-dev-tools
```

Fedora
```bash
sudo dnf install -y cmake make gcc-c++
# For Qt tests (optional)
sudo dnf install -y qt5-qtbase-devel
```

Build (CMake)
- Default (non-Qt CLI only):
- Windows (cmd.exe):
```cmd
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release -DBUILD_QT_TESTS=OFF
cmake --build build --config Release
```
- Linux/macOS:
```bash
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release -DBUILD_QT_TESTS=OFF
cmake --build build --config Release
```
- Binary: `lzstring` / `lzstring.exe` in the build tree.

- With Qt tests (auto-detect Qt5/Qt6):
```bash
cmake -S . -B build -DBUILD_QT_TESTS=ON
cmake --build build --target lzstring_test
ctest --test-dir build -V -R lzstring_test
```
If Qt isn't found, a status message is printed and the normal CLI plus non-Qt tests still build.

Tests (CMake)
- Always built: `lzstring_std_test` (non-Qt, exercises `StdLZPlatform`).
```bash
cmake -S . -B build -DBUILD_QT_TESTS=OFF
cmake --build build --target lzstring_std_test
ctest --test-dir build -V -R lzstring_std_test
```
- Optionally (with Qt): `lzstring_test` (original Qt/QString test + benchmarks). Data file `data.json` is auto-copied beside the test binary and the working directory set via CTest so relative open succeeds.

Build (qmake, legacy / optional)
- The `.pri` pulls in all sources; tests are under `tests/`.
- Linux/macOS:
```bash
qmake
make -j
```
- Windows (from a Qt command prompt):
```cmd
qmake
nmake
```

Getting the sources
```bash
git clone <REPO_URL>
cd qt-lzstring
```

Usage (CLI)
- The CLI reads from a file or stdin (`-`) and writes to a file or stdout (`-`).
- Binary name: `lzstring` (`.exe` on Windows)
- Operations:
- `--compress`
- `--compressToUTF16`
- `--compressToBase64`
- `--decompress`
- `--decompressFromUTF16`
- `--decompressFromBase64`
- `--test` (round‑trip checks for all codecs on the provided input; prints boolean results and exits)

Examples (Linux/macOS)
```bash
./lzstring --compress input.txt output.lz
./lzstring --compressToUTF16 input.txt output.lz16
./lzstring --compressToBase64 input.txt output.lz64
./lzstring --decompress input.lz output.txt
./lzstring --decompressFromUTF16 input.lz16 output.txt
./lzstring --decompressFromBase64 input.lz64 output.txt
./lzstring --test input.txt
cat input.txt | ./lzstring --compress - -
cat input.lz | ./lzstring --decompress - -
```

Examples (Windows cmd.exe)
```cmd
lzstring.exe --compress input.txt output.lz
lzstring.exe --decompress input.lz output.txt
lzstring.exe --test input.txt
:: Pipes
type input.txt | lzstring.exe --compress - -
type input.lz | lzstring.exe --decompress - -
```

Extending tests
- Add more corpus cases: modify `tests/std_roundtrip_test.cpp` or the Qt test's `test_data()` method.
- For performance comparisons, run the Qt benchmarks (they use `QBENCHMARK`).
- To disable the std test (e.g., in a packaging build), you can wrap its target creation in an option similar to `BUILD_QT_TESTS`.

License
- This project is licensed under the WTFPL: http://www.wtfpl.net/
12 changes: 10 additions & 2 deletions lzstring.pro
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@

TEMPLATE = subdirs
TEMPLATE = app
SUBDIRS += tests

#EDIT to fit you cofiguration
LIBS += -L/usr/lib/x86_64-linux-gnu -lQt5Core -lQt5Widgets
INCLUDEPATH += /usr/include/x86_64-linux-gnu/qt5/
QT += core widgets

include(src/lzstring.pri)

TARGET = lzstring

CONFIG = release console
32 changes: 32 additions & 0 deletions src/ILZPlatform.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
#ifndef ILZPLATFORM_H
#define ILZPLATFORM_H

#include "lzstring.h"

// Interface abstracting platform-specific string and character utilities
class ILZPlatform {
public:
virtual ~ILZPlatform() = default;

// String operations
virtual int length(const QString& s) const = 0;
virtual bool isEmpty(const QString& s) const = 0;
virtual QString slice(const QString& s, int pos, int len) const = 0;
virtual QString concat(const QString& a, const QString& b) const = 0;
virtual void append(QString& dst, const QString& src) const = 0;

// Character/code unit operations
virtual int charCodeAt(const QString& s, int index) const = 0; // 0..65535 (Qt) or 0..255 (std)
virtual QString charFromCode(int code) const = 0; // single-code-unit string

// Output mappers for compression writers
virtual void appendFromInt_Normal(QString& out, int code) const = 0; // 16-bit path uses code as-is
virtual void appendFromInt_UTF16(QString& out, int code) const = 0; // code + 32
virtual void appendFromInt_Base64(QString& out, int code) const = 0; // map using Base64 alphabet

// Reverse mapping for Base64 during decompression
virtual int base64ReverseIndex(int charCode) const = 0; // -1 if not found
};

#endif // ILZPLATFORM_H

Loading