Skip to content
Merged
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: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ on:
pull_request:

env:
DEVELOPER_DIR: /Applications/Xcode_16.4.app/Contents/Developer
DEVELOPER_DIR: /Applications/Xcode_26.3.app/Contents/Developer

jobs:
mac-tests:
Expand Down
48 changes: 24 additions & 24 deletions BitMatch.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -643,7 +643,7 @@
CODE_SIGN_ENTITLEMENTS = BitMatch/BitMatch.entitlements;
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 12;
CURRENT_PROJECT_VERSION = 14;
DEVELOPMENT_TEAM = "$(DEVELOPMENT_TEAM)";
ENABLE_HARDENED_RUNTIME = YES;
ENABLE_PREVIEWS = YES;
Expand All @@ -654,7 +654,7 @@
"$(inherited)",
"@executable_path/../Frameworks",
);
MARKETING_VERSION = 0.2.3;
MARKETING_VERSION = 0.2.4;
PRODUCT_BUNDLE_IDENTIFIER = BitMatchApp.BitMatch;
PRODUCT_NAME = "$(TARGET_NAME)";
REGISTER_APP_GROUPS = YES;
Expand All @@ -672,7 +672,7 @@
CODE_SIGN_ENTITLEMENTS = BitMatch/BitMatch.entitlements;
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 12;
CURRENT_PROJECT_VERSION = 14;
DEVELOPMENT_TEAM = "$(DEVELOPMENT_TEAM)";
ENABLE_HARDENED_RUNTIME = YES;
ENABLE_PREVIEWS = YES;
Expand All @@ -683,7 +683,7 @@
"$(inherited)",
"@executable_path/../Frameworks",
);
MARKETING_VERSION = 0.2.3;
MARKETING_VERSION = 0.2.4;
PRODUCT_BUNDLE_IDENTIFIER = BitMatchApp.BitMatch;
PRODUCT_NAME = "$(TARGET_NAME)";
REGISTER_APP_GROUPS = YES;
Expand All @@ -698,11 +698,11 @@
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 12;
CURRENT_PROJECT_VERSION = 14;
DEVELOPMENT_TEAM = "$(DEVELOPMENT_TEAM)";
GENERATE_INFOPLIST_FILE = YES;
MACOSX_DEPLOYMENT_TARGET = 15.5;
MARKETING_VERSION = 0.2.3;
MARKETING_VERSION = 0.2.4;
PRODUCT_BUNDLE_IDENTIFIER = BitMatchApp.BitMatchTests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_EMIT_LOC_STRINGS = NO;
Expand All @@ -716,11 +716,11 @@
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 12;
CURRENT_PROJECT_VERSION = 14;
DEVELOPMENT_TEAM = "$(DEVELOPMENT_TEAM)";
GENERATE_INFOPLIST_FILE = YES;
MACOSX_DEPLOYMENT_TARGET = 15.5;
MARKETING_VERSION = 0.2.3;
MARKETING_VERSION = 0.2.4;
PRODUCT_BUNDLE_IDENTIFIER = BitMatchApp.BitMatchTests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_EMIT_LOC_STRINGS = NO;
Expand All @@ -733,10 +733,10 @@
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 12;
CURRENT_PROJECT_VERSION = 14;
DEVELOPMENT_TEAM = "$(DEVELOPMENT_TEAM)";
GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 0.2.3;
MARKETING_VERSION = 0.2.4;
PRODUCT_BUNDLE_IDENTIFIER = BitMatchApp.BitMatchUITests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_EMIT_LOC_STRINGS = NO;
Expand All @@ -749,10 +749,10 @@
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 12;
CURRENT_PROJECT_VERSION = 14;
DEVELOPMENT_TEAM = "$(DEVELOPMENT_TEAM)";
GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 0.2.3;
MARKETING_VERSION = 0.2.4;
PRODUCT_BUNDLE_IDENTIFIER = BitMatchApp.BitMatchUITests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_EMIT_LOC_STRINGS = NO;
Expand All @@ -767,7 +767,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 12;
CURRENT_PROJECT_VERSION = 14;
DEVELOPMENT_TEAM = "$(DEVELOPMENT_TEAM)";
ENABLE_PREVIEWS = YES;
GENERATE_INFOPLIST_FILE = YES;
Expand All @@ -784,7 +784,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 0.2.3;
MARKETING_VERSION = 0.2.4;
MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = "BitMatchiOS.BitMatch-iPad";
PRODUCT_NAME = "$(TARGET_NAME)";
Expand All @@ -802,7 +802,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 12;
CURRENT_PROJECT_VERSION = 14;
DEVELOPMENT_TEAM = "$(DEVELOPMENT_TEAM)";
ENABLE_PREVIEWS = YES;
GENERATE_INFOPLIST_FILE = YES;
Expand All @@ -819,7 +819,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 0.2.3;
MARKETING_VERSION = 0.2.4;
MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = "BitMatchiOS.BitMatch-iPad";
PRODUCT_NAME = "$(TARGET_NAME)";
Expand All @@ -837,11 +837,11 @@
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 12;
CURRENT_PROJECT_VERSION = 14;
DEVELOPMENT_TEAM = "$(DEVELOPMENT_TEAM)";
GENERATE_INFOPLIST_FILE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 18.5;
MARKETING_VERSION = 0.2.3;
MARKETING_VERSION = 0.2.4;
MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = "BitMatchiOS.BitMatch-iPadTests";
PRODUCT_NAME = "$(TARGET_NAME)";
Expand All @@ -858,11 +858,11 @@
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 12;
CURRENT_PROJECT_VERSION = 14;
DEVELOPMENT_TEAM = "$(DEVELOPMENT_TEAM)";
GENERATE_INFOPLIST_FILE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 18.5;
MARKETING_VERSION = 0.2.3;
MARKETING_VERSION = 0.2.4;
MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = "BitMatchiOS.BitMatch-iPadTests";
PRODUCT_NAME = "$(TARGET_NAME)";
Expand All @@ -879,11 +879,11 @@
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 12;
CURRENT_PROJECT_VERSION = 14;
DEVELOPMENT_TEAM = "$(DEVELOPMENT_TEAM)";
GENERATE_INFOPLIST_FILE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 18.5;
MARKETING_VERSION = 0.2.3;
MARKETING_VERSION = 0.2.4;
MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = "BitMatchiOS.BitMatch-iPadUITests";
PRODUCT_NAME = "$(TARGET_NAME)";
Expand All @@ -899,11 +899,11 @@
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 12;
CURRENT_PROJECT_VERSION = 14;
DEVELOPMENT_TEAM = "$(DEVELOPMENT_TEAM)";
GENERATE_INFOPLIST_FILE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 18.5;
MARKETING_VERSION = 0.2.3;
MARKETING_VERSION = 0.2.4;
MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = "BitMatchiOS.BitMatch-iPadUITests";
PRODUCT_NAME = "$(TARGET_NAME)";
Expand Down
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,16 @@ All notable changes to this project will be documented in this file.

## [Unreleased]

## [0.2.4] - 2026-10-04

A reliability update for large-file verification.

- Fixed temporary read buffers building up in memory while checking large files. BitMatch now releases them after each chunk.
- Diagnostics now show which numbered file and destination were being checked, how far the read got, and how much memory BitMatch was using. Footage names and paths remain private.
- Verification diagnostics distinguish a matching copy, a mismatch, an error and cancellation, making an interrupted transfer easier to investigate.

Tested with two 45 GB files verifying together, with memory staying flat, plus a signed-app copy, cancellation, retry, ASC MHL and report walkthrough. Synthetic tests do not reproduce every drive or camera setup; the exact cause of the interruption in issue #10 remains unconfirmed. If it happens again, use **History → Export diagnostics** after reopening BitMatch and attach the file to the issue.

## [0.2.3] - 2026-10-01

A reliability update for transfers and reports.
Expand Down
4 changes: 2 additions & 2 deletions DEVELOPMENT.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ Read [docs/THESIS.md](docs/THESIS.md) for what BitMatch promises and the current

## Building

- Xcode 16 or newer; CI uses Xcode 16.4. Open `BitMatch.xcodeproj`.
- Use Xcode 26.3 or newer for the app concurrency settings; CI selects Xcode 26.3. Open `BitMatch.xcodeproj`.
- Schemes:
- `BitMatch`: the macOS app (macOS 15.5 or newer).
- `BitMatch-iPad`: the iPhone and iPad app (iOS/iPadOS 18.5 or newer). Despite the name it targets both device families.
Expand Down Expand Up @@ -53,7 +53,7 @@ bash test.sh release-builds # macOS and iOS simulator Release builds

`ipad-test` refuses to guess a simulator; set `IOS_SIMULATOR_DESTINATION` to one installed on your machine. Set `DERIVED_DATA_ROOT` to reuse a build folder (default `.derived-data/`).

`.github/workflows/ci.yml` defines `mac-test` and `ipad-build` jobs on push and pull request. The README notes that GitHub Actions is currently disabled for the repository, so run both locally before submitting changes.
`.github/workflows/ci.yml` defines Mac tests, the iPad/iPhone build and engine tests on push and pull request. Run the required checks locally before submitting changes; record any host or toolchain failures separately from passing tests.

### Change workflow

Expand Down
39 changes: 21 additions & 18 deletions Packages/BitMatchEngine/Sources/BitMatchEngine/ChecksumEngine.swift
Original file line number Diff line number Diff line change
Expand Up @@ -251,12 +251,14 @@ public final class ChecksumEngine: ChecksumService, Sendable {
await Task.yield()
try Task.checkCancellation()
try await PauseGate.waitIfCurrentIsPaused()
let data = try fileHandle.read(upToCount: chunkSize) ?? Data()
if data.isEmpty { break }
autoreleasepool {
hasher.update(data: data)
// Include the read so temporary Foundation buffers drain per chunk.
let count = try autoreleasepool { () throws -> Int in
let data = try fileHandle.read(upToCount: chunkSize) ?? Data()
if !data.isEmpty { hasher.update(data: data) }
return data.count
}
bytesProcessed += Int64(data.count)
if count == 0 { break }
bytesProcessed += Int64(count)
let progress = Double(bytesProcessed) / Double(initial.size)
progressCallback?(progress, "Computing MD5 (legacy)...")
}
Expand Down Expand Up @@ -289,13 +291,14 @@ public final class ChecksumEngine: ChecksumService, Sendable {
await Task.yield()
try Task.checkCancellation()
try await PauseGate.waitIfCurrentIsPaused()
let data = try fileHandle.read(upToCount: chunkSize) ?? Data()
if data.isEmpty { break }

autoreleasepool {
hasher.update(data: data)
// Include the read so temporary Foundation buffers drain per chunk.
let count = try autoreleasepool { () throws -> Int in
let data = try fileHandle.read(upToCount: chunkSize) ?? Data()
if !data.isEmpty { hasher.update(data: data) }
return data.count
}
bytesProcessed += Int64(data.count)
if count == 0 { break }
bytesProcessed += Int64(count)

// Update progress
let progress = Double(bytesProcessed) / Double(initial.size)
Expand Down Expand Up @@ -330,14 +333,14 @@ public final class ChecksumEngine: ChecksumService, Sendable {
await Task.yield()
try Task.checkCancellation()
try await PauseGate.waitIfCurrentIsPaused()
let data = try fileHandle.read(upToCount: chunkSize) ?? Data()
if data.isEmpty { break }

autoreleasepool {
hasher.update(data: data)
// Include the read so temporary Foundation buffers drain per chunk.
let count = try autoreleasepool { () throws -> Int in
let data = try fileHandle.read(upToCount: chunkSize) ?? Data()
if !data.isEmpty { hasher.update(data: data) }
return data.count
}

bytesProcessed += Int64(data.count)
if count == 0 { break }
bytesProcessed += Int64(count)

// Update progress
let progress = Double(bytesProcessed) / Double(initial.size)
Expand Down
Loading
Loading