You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
QR-Code-generator/csharp/PORTING.md

174 lines
7.7 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

### Porting Summary: Java → C# QR Code Generator
#### Scope
- Ported the core QR Code generator from the Java implementation (`java/src/main/java/io/nayuki/qrcodegen/`) to C#.
- Implemented a class library `QrCodeGen` and a minimal console demo `QrCodeGen.Demo`.
#### Goals
- Maintain functional parity with the Java reference (encoding pipeline, EC levels, masking, penalties, ReedSolomon ECC, layout drawing).
- Provide idiomatic and safe C# while preserving algorithmic behavior and outputs.
#### Note
- This PR is 100% generated by JetBrains Junie Pro AI code assistant.
- QR Code Generate Demo console app is a minimal port of the Java demo and working.
---
### Repository Layout (Relevant to this PR)
- `csharp/QR-Code-generator.sln` — Solution file containing two projects.
- `csharp/QrCodeGen/` — Class library (C# port of the Java library):
- `BitBuffer.cs`
- `DataTooLongException.cs`
- `QrSegment.cs`
- `QrSegmentAdvanced.cs` (simplified vs. Java; see Feature Parity section)
- `QrCode.cs`
- `csharp/QrCodeGen.Demo/` — Console demo app (depends on `QrCodeGen`).
---
### Class-by-Class Mapping
- Java `BitBuffer` → C# `BitBuffer`
- API preserved: append bits, append buffer, length, get bit, cloning.
- Implementation uses `List<bool>` and explicit bounds checks like Javas `BitSet`/length pair.
- Java `DataTooLongException` → C# `DataTooLongException`
- Extends `ArgumentException` (close analog to Javas `IllegalArgumentException`).
- Java `QrSegment` → C# `QrSegment`
- Static factories: `MakeBytes`, `MakeNumeric`, `MakeAlphanumeric`, `MakeEci`.
- Helpers: `IsNumeric`, `IsAlphanumeric` via regexes mirroring Java patterns.
- Mode enum and character-count bits mapping provided via extension methods.
- `GetTotalBits()` faithfully ported.
- Java `QrSegmentAdvanced` → C# `QrSegmentAdvanced`
- Included as an optional module. Current implementation mirrors the default segmentation path (numeric/alphanumeric/byte) and returns reasonably optimal segments for common inputs, but does not implement full DP-based optimal segmentation and Kanji mode. See Feature Parity and Future Work.
- Java `QrCode` → C# `QrCode`
- High-level APIs: `EncodeText`, `EncodeBinary`.
- Mid-level API: `EncodeSegments` with `minVersion`, `maxVersion`, `mask`, and `boostEcl` parameters.
- Constructor path builds function patterns, computes ECC, interleaves, draws codewords, applies mask, and computes penalties identically.
- Tables `ECC_CODEWORDS_PER_BLOCK` and `NUM_ERROR_CORRECTION_BLOCKS` ported exactly. Signed `sbyte` used to allow `-1` sentinels.
- All penalty and mask rules implemented verbatim.
---
### Feature Parity
- Achieved parity:
- Version selection by capacity.
- Error correction level boosting (when it doesnt increase version).
- Data stream building, terminator and padding, interleaving across ECC blocks.
- Drawing: finder, timing, alignment patterns; format and version information.
- Mask application and penalty scoring (N1N4 rules) with identical logic.
- ReedSolomon divisor/remainder algorithms and multiplication over GF(2^8/0x11D).
- Intentional differences / limitations:
- `QrSegmentAdvanced` does not implement:
- Full dynamic-programming optimal segmentation across all modes.
- Kanji segment encoding.
- The default path still matches Javas `QrSegment.makeSegments()` selection (numeric/alphanumeric/byte) and therefore preserves functional outputs for typical text.
- Behavioral equivalence expectations:
- For inputs limited to numeric/alphanumeric/byte, outputs should match Java for the same chosen mask (or mask-agnostic when mask=-1) and ECL.
---
### Notable C#-Specific Decisions
- `sbyte[][]` tables for ECC metadata to accommodate `-1` sentinel (Java byte is signed; C# byte is unsigned).
- Enum helpers via extension methods for mapping to mode bits and character-count bits.
- `BitBuffer` cloning implemented to maintain immutability of exposed data as in Java.
- Exceptions aligned to .NET conventions (e.g., `ArgumentException`, `ArgumentOutOfRangeException`).
---
### Build and Run Instructions
- Target frameworks: `net8.0` (both projects). If your machine only has .NET 9, either install .NET 8 or retarget both projects to `net9.0`.
Commands from repo root:
```sh
dotnet restore csharp/QR-Code-generator.sln
dotnet build csharp/QR-Code-generator.sln -c Debug
# Run demo
dotnet run --project csharp/QrCodeGen.Demo
```
Rider/VS:
- Open `csharp/QR-Code-generator.sln` and build. Ensure your IDE uses the Microsoft .NET SDK (not Homebrews) and that the installed SDK matches `net8.0` or update TFM to `net9.0`.
---
### Verification Performed
- Build succeeded locally after addressing initial compile issues (sbyte tables, enum constructor, finder pattern drawing, bit-buffer bounds).
- Demo run prints QR metadata and ASCII rendering for “Hello, world!”.
- Corrected a runtime bug where data bytes were read beyond `BitBuffer` length; now we read `numDataBytes = bb.BitLength / 8` and then apply 0xEC/0x11 padding.
---
### Reviewer Checklist
- API Parity:
- QrCode: factory methods, mid-level encode, mask selection, ECC boosting.
- QrSegment: mode mapping, regex correctness, bit-length calculations.
- BitBuffer: bounds checks, append semantics, cloning.
- Tables: Verify ECC and block count tables match Java constants exactly.
- Masking/Penalties: Confirm penalty `N1..N4` and zigzag codeword placement logic mirror Java.
- Error Paths: Proper exceptions for out-of-range versions/masks/lengths.
- Padding: Verify 0xEC/0x11 alternating pad applied after real bytes from `BitBuffer`.
- Public API surface: Namespaces and visibility appropriate for a library; no leaking internals.
---
### Known Gaps / Future Work
- Implement full `QrSegmentAdvanced`:
- DP-based optimal segmentation across modes.
- Kanji mode encoding per the Java version.
- Add unit tests:
- Cross-verify bitwise outputs vs. Java for a fixed mask across sample inputs.
- Randomized round-trips using known test vectors.
- Add simple image renderer (PNG/SVG) for easier visual verification.
- Performance: Consider bit-packing in `BitBuffer` to reduce allocations for very large payloads.
---
### Migration Risks and Mitigations
- SDK Mismatch (net8.0 vs installed SDK): Documented; either install .NET 8 or retarget to `net9.0` in both `.csproj` files.
- Environment: Ensure the IDE uses Microsofts SDK at `/usr/local/share/dotnet`; avoid Homebrews SDK confusion.
- Behavior Drift: The simplified `QrSegmentAdvanced` may produce larger bitstreams for mixed-content strings vs. Javas optimal splitter. This does not affect correctness, only compactness.
---
### File List (Added/Modified)
- Added:
- `csharp/QR-Code-generator.sln`
- `csharp/QrCodeGen/QrCodeGen.csproj`
- `csharp/QrCodeGen/BitBuffer.cs`
- `csharp/QrCodeGen/DataTooLongException.cs`
- `csharp/QrCodeGen/QrSegment.cs`
- `csharp/QrCodeGen/QrSegmentAdvanced.cs`
- `csharp/QrCodeGen/QrCode.cs`
- `csharp/QrCodeGen.Demo/QrCodeGen.Demo.csproj`
- `csharp/QrCodeGen.Demo/Program.cs`
---
### How Reviewers Can Reproduce
- Build and run demo as above.
- Optionally compare module patterns vs. Java output with a fixed mask (pass `mask` in `EncodeSegments`) over several sample strings.
---
### License Alignment
- The C# port continues to follow the MIT License consistent with the Java version and includes the original copyright attribution.
---
### Appendix: Usage Example
```csharp
using Io.Nayuki.QrCodeGen;
var qr = QrCode.EncodeText("Hello, world!", QrCode.Ecc.MEDIUM);
for (int y = 0; y < qr.Size; y++) {
for (int x = 0; x < qr.Size; x++) {
bool dark = qr.GetModule(x, y);
// render module
}
}
```