124 Commits
Author SHA1 Message Date
Gustave Monce d270cace79 Fix: device being null 2026-04-22 18:36:50 +02:00
Gustave Monce af61c9ad29 Preliminary support for UFP 2026-04-16 18:46:00 +02:00
Gustave Monce de4d5e577a Add preliminary SimpleIO support 2026-04-16 18:11:13 +02:00
Gustave Monce df02025a31 Update timebomb 2026-01-03 23:26:37 +01:00
Gustave Monce ad92ecdab3 Restructure assets into their own dedicated folders 2025-11-01 11:06:33 +01:00
Gustave Monce b3b037a3c8 Remove deprecated download command line options 2025-11-01 11:06:17 +01:00
Gustave Monce be15155c39 Deprecate MSR download fully as the MSR and repair avoidance services are fully deprecated as of 2025 2025-11-01 11:06:02 +01:00
Gustave Monce a17dae3931 Update project structure 2025-11-01 09:44:23 +01:00
Gustave Monce 7646e3fc76 Bump timebomb date 2025-11-01 09:42:59 +01:00
Gustave Monce 933e9e53b6 Migrate DiscUtils fat code to a standalone project dependency 2025-11-01 09:42:52 +01:00
Gustave Monce e838168127 Migrate 7zip code to a standalone project dependency 2025-11-01 09:31:14 +01:00
Gustave Monce 058cde0d91 Migrate WinUSBNet code to a standalone project dependency 2025-11-01 09:28:08 +01:00
Gustave Monce 1cc7a5cee4 Update Timebomb 2024-12-23 15:14:30 +01:00
Gustave Monce 132e21e58a Patcher: fix: broken go to labels in script engine 2024-10-22 21:22:30 +02:00
Gustave Monce 1e5da5452b Small fixes 2024-10-21 23:52:08 +02:00
Gustave Monce 6992ed3f70 Remove references to dead website 2024-10-21 23:30:50 +02:00
Gustave Monce bb9702a3c3 Patcher: fix compilation with dotnet 8 2024-10-21 23:25:50 +02:00
Gustave Monce 3c66688303 Add Patcher Project
The other Patcher repository is locked from future modifications
2024-10-21 08:57:39 +02:00
Gustave Monce bc77e8b589 Fixes 2024-10-21 08:56:11 +02:00
Gustave Monce 6be24faee0 Update ci.yml 2024-10-13 00:26:53 +02:00
Gustave Monce e078bb10ed Fixes for Spec A unlocking
In memories of the cyan RM-821 from a fellow care center

Rest in peace, 12th of October 2024
2024-10-13 00:25:01 +02:00
Gustave Monce 605b19aede Fixes 2024-10-12 21:22:07 +02:00
Gustave Monce d9da49915e Some changes 2024-10-12 19:44:11 +02:00
Gustave Monce 7c18a168fa Various Fixes 2024-10-12 19:15:41 +02:00
Gustave Monce 303c2d4b5a Some cleanup 2024-10-12 18:38:39 +02:00
Gustave Monce d700ae5911 Add the ability to add Secure WIMs to the store 2024-10-12 17:19:47 +02:00
Gustave Monce 14bf607111 Remove Defunct MSR Downloads 2024-10-12 17:14:06 +02:00
Gustave Monce 57c9595d86 Some cleanup 2024-10-12 16:56:36 +02:00
Gustave Monce 7fc332e912 Cleanup using directives 2024-10-12 13:46:34 +02:00
Gustave Monce bcec0a72e6 Nokia Flash Model -> Nokia UEFI Model 2024-10-12 13:45:51 +02:00
Gustave Monce 00407d6f24 Cleanup 2024-10-12 13:40:24 +02:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2d5b0fd3db Bump System.Text.Json from 8.0.4 to 8.0.5 in /WPinternals (#79)
Bumps [System.Text.Json](https://github.com/dotnet/runtime) from 8.0.4 to 8.0.5.
- [Release notes](https://github.com/dotnet/runtime/releases)
- [Commits](https://github.com/dotnet/runtime/compare/v8.0.4...v8.0.5)

---
updated-dependencies:
- dependency-name: System.Text.Json
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-10-09 09:03:31 +02:00
Gustave Monce a982c119fb Bump timebomb 2024-09-09 21:08:35 +02:00
Gustave Monce c6dee3fe33 workaround older phone fw issues when retrieving via json rpc and gpt get function failures 2024-09-01 16:49:36 +02:00
Gustave Monce 91961b0e7b fix issues with downloading files 2024-09-01 12:45:46 +02:00
Gustave Monce 29c6ab06d4 fix: Download issues with ENOSW 2024-09-01 10:38:47 +02:00
Gustave Monce b03b561724 fix a few TODOs 2024-08-31 23:17:34 +02:00
Gustave Monce 91f534a7c3 fix: Merge issues from previous commit 2024-08-31 21:58:23 +02:00
Gustave Monce f0f3268924 Split phone info structures for each app type 2024-08-31 21:52:20 +02:00
Gustave Monce c269cfe839 Enable downloading ENOSW via Download Page 2024-08-31 19:45:24 +02:00
Gustave Monce 7d8aad0e88 fix: Modern Flash App Label mode switching 2024-08-31 18:31:56 +02:00
Gustave Monce 310d0b97c5 fix: Mode change detection on specb
resolves a few issues but not all due to the combined app
2024-08-31 17:50:18 +02:00
Gustave Monce 8e50c46357 wip: Refactor FlashApp Logic to account for the 3 split app states 2024-08-31 16:39:44 +02:00
Gustave Monce e6555741b0 fix: PhoneInfo app handling + label parsing issues 2024-08-31 11:00:04 +02:00
Gustave Monce c21692491d fix: Log all silent exceptions 2024-08-30 21:43:30 +02:00
Gustave Monce 350b6e8f1e fix: add missing raise can execute changed for unlock v1 with supported ffu field 2024-08-30 20:42:52 +02:00
Gustave Monce 0101477830 fix: Handle empty flash part list
This is used to clear the red flashing status we need to handle this differently for spec A
2024-08-30 20:42:37 +02:00
Gustave Monce a6c017986b fix: Handle loaders with new lines at the top instead of intel hex style right at the start 2024-08-30 20:42:16 +02:00
Gustave Monce 0174fc8b30 QCParts: Check if signatures are available 2024-08-30 20:41:57 +02:00
Gustave Monce c6f6ef4429 Rework Qualcomm Partition to also work with modern day ed loaders 2024-08-27 10:08:47 +02:00
Gustave Monce ab0c35e879 fix: revert qualcomm partition code changes to account for older ed payloads 2024-08-27 09:55:52 +02:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
676a95dd97 Bump System.Text.Json from 8.0.0 to 8.0.4 in /WPinternals (#74)
Bumps System.Text.Json from 8.0.0 to 8.0.4.

---
updated-dependencies:
- dependency-name: System.Text.Json
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-13 14:53:12 +02:00
Gustave Monce 8981fd02e9 Enable Preview Build 2023-11-26 18:50:46 +01:00
Gustave Monce 16d3f95971 WPinternals v3.0 2023-11-26 18:39:49 +01:00
Gustave Monce 293c649edb Refactor Qualcomm Sahara and Qualcomm Firehose code 2023-11-26 18:37:14 +01:00
Gustave Monce 88efc77887 Cleanup Sahara Implementation 2023-11-26 18:08:50 +01:00
Gustave Monce dc6085f185 Sahara: Implement getting the RKH 2023-11-26 16:51:29 +01:00
Gustave Monce e2cbb9c6fc Alter the list of OS partitions 2023-11-26 14:19:05 +01:00
Gustave Monce 4b7b9621b4 Rebuild the Backup to Custom ROM zip functionality to handle more partitions and be more flexible 2023-11-26 14:04:13 +01:00
Gustave Monce 96c42a29b5 Adopt new C# syntax for array init 2023-11-26 14:03:46 +01:00
Gustave Monce 742c89b9bf CI: Use .NET 8 SDK 2023-11-26 13:09:49 +01:00
Gustave Monce dbd303fd07 Add new feature to generate a GPT xml file from a binary or backup 2023-11-26 13:08:33 +01:00
Gustave Monce 8d35be447a Project: Update to .NET 8 2023-11-26 12:25:14 +01:00
Gustave Monce 83c09bdc81 Improve RKH Reading from Qualcomm Images 2023-03-09 21:40:23 +01:00
Gustave MonceandGitHub 93a5064751 Merge pull request #47 from ungeskriptet/fix-typo 2022-12-23 09:31:24 +01:00
David Wronek ef6a962a01 Fix typo in MassStorageView 2022-12-19 20:35:47 +01:00
Gustave Monce d32788198d Project: Migrate to .NET 7 2022-11-11 02:26:45 -08:00
Gustave Monce 7798dd1c34 RKH: Fix an issue retrieving modern day RKH 2022-11-11 02:22:17 -08:00
Gustave Monce 57cd052d61 About: Show Build and Revision in the version field 2021-11-15 15:06:13 +01:00
Gustave Monce 5eb523530c Remove the Lumia 535 from the supported phone list 2021-11-15 14:53:34 +01:00
Gustave Monce 8a17b05398 Project: Update to .NET 6 2021-11-15 14:47:29 +01:00
Gustave Monce dc5ac1e7d4 CI: Make CI always fetch latest .NET 5 SDK 2021-08-26 09:09:47 +02:00
Gustave Monce 1d14d79fab Flash: Custom ROM: Fix incorrect unlocked check for EFIESP 2021-08-16 11:40:58 +02:00
Gustave Monce 846ea41883 Project: Add SDK 2021-08-14 11:24:02 +02:00
Gustave Monce 452393aaa7 Project: Add RootAccessTestUWP 2021-08-14 11:14:56 +02:00
Gustave Monce 17bc763761 Project: Move WPinternals code to a WPinternals folder 2021-08-14 11:04:37 +02:00
Gustave Monce 668a9b7fe2 Fix an issue with incorrect logging of secure boot state 2021-08-13 13:21:15 +02:00
Gustave Monce 8293c18406 Merge branch 'master' of https://github.com/ReneLergner/WPinternals 2021-08-12 17:43:45 +02:00
Gustave Monce 48fbfa77df Project: remove references to hijacked website/domain to prevent potential malicious activity due to us not controlling the domain anymore. 2021-08-12 17:43:38 +02:00
Gustave MonceandGitHub 709c91cec5 Create bug_report.yml 2021-08-12 08:59:16 +02:00
Gustave MonceandGitHub 611ad122f9 Create README.md 2021-08-12 08:52:54 +02:00
Gustave Monce d8fd0aa516 Fix more hyperlink issues 2021-08-12 08:37:20 +02:00
Gustave Monce 7f3c8b1777 Merge branch 'master' of https://github.com/ReneLergner/WPinternals 2021-08-12 08:32:27 +02:00
Gustave Monce 087457fa0d FIx an issue with hyperlinks 2021-08-12 08:31:36 +02:00
Gustave MonceandGitHub bb9f614e82 CI: Use .NET 5.0.9 SDK 2021-08-11 18:43:57 +02:00
Gustave Monce f4a5e63d25 Download: Improve download reliability 2021-08-11 15:58:47 +02:00
Gustave Monce c5fcb1ec8d Implement Qualcomm Sahara VIP and fix a few bugs
* Qualcomm Sahara VIP
* Project Cleanup
* Allow unlocking an already unlocked phone
2021-08-11 14:33:49 +02:00
Gustave Monce 9f4c92f437 DiscUtils: Fat: Merge more upstream changes 2021-08-11 11:18:26 +02:00
Gustave Monce 62fa3844f9 DiscUtils: Fat: Merge more upstream changes related to encoding registration 2021-08-11 11:11:46 +02:00
Gustave Monce efc81332f9 DiscUtils: Fat: Fix an issue with no long path name support in the upstream library 2021-08-11 11:09:38 +02:00
Gustave Monce 847ce0506d Project Maintenance 2021-08-09 20:21:09 +02:00
Gustave Monce 9865ef7f79 Migrate from Newtonsoft.Json.NET to System.Text.Json 2021-08-09 19:38:34 +02:00
Gus 9ba1333edf CI: Disable trimming 2021-02-08 18:37:04 +01:00
Gustave MonceandGitHub 49b87d6f24 Merge pull request #15 from luk1337/master
Add support for OS version 10.0.15254.603
2021-02-08 18:19:14 +01:00
Gustave MonceandGitHub ad96465e16 Merge pull request #16 from ReneLergner/feature/modernize
Modernize WPinternals
2021-02-08 18:17:43 +01:00
Gus f7ab5fa6f2 Project: Fix CI 2021-02-08 18:13:29 +01:00
Gus 759cb53f64 Project: Setup CI 2021-02-08 17:57:02 +01:00
Gus 0ea33ff35c Project: Convert to .NET 5.0 2021-02-08 17:50:27 +01:00
Gus 8630a89553 WinUSB: Merge upstream changes 2021-02-08 17:08:46 +01:00
LuK1337 a24998c6ee Add support for OS version 10.0.15254.603 2021-02-04 23:30:06 +01:00
Gustave Monce f438d0dd71 Switch to the new blob storage server for Software Repository 2020-04-09 11:35:04 +02:00
Gustave Monce 019c47ad40 Make loader path mandatory only for non unlocked devices 2020-03-29 10:49:30 +02:00
Gustave Monce 1d6af81253 Add support for engineering devices in the unlock v1 routines 2020-01-14 15:42:23 +01:00
Gustave Monce 9734077bb1 Fix an issue with MainOS drive letter recognition 2020-01-14 15:32:29 +01:00
Gustave Monce 3e6529119f Support sending V1 FFU payloads in the custom flash v3 algorithm 2020-01-14 15:16:02 +01:00
Gustave Monce db81853e07 Cleanup of old project files 2020-01-12 16:44:48 +01:00
Gustave Monce f6ad0c98b7 Disable re-unlocking functionality for Spec B 2020-01-12 15:46:40 +01:00
Gustave Monce 774ff9956f Implemented the new flashing hack
This new flashing hack exploits a bug in flash app where it will not properly check the integrity of catalog files used in FFU files
2020-01-12 15:43:56 +01:00
Gustave Monce a3f323259a Added listening for the HID interface (charging) and bug fixing 2019-12-30 16:51:25 +01:00
Gus 81145ed0e9 Enhancements
- Improved error messages
- Added shutdown functionality from mass stoage
- Fixed an issue where 9006 would incorrectly be used for rebooting from mass storage
- Added support for gathering security information from older flash apps
- Added a new indicator in the empty view when a phone in bootloader mode is detected
- Fixed an issue where interrupting the bootloader may fail
- Added more checks to some functions
- Started to work on a bootloader view
- Fixed an issue where x50 phones in label mode would not get detected once being disconnected
- Added logging for Qualcomm Emergency Charging mode
- General bug fixes
2019-12-28 09:39:02 +01:00
Gustave Monce fa896b7c39 Fixing Sahara issues & .NET Framework project files 2019-12-25 13:41:06 +01:00
Gustave Monce b8d63d1a11 Fixed an issue regarding ACLs and Sahara handling 2019-12-24 08:36:20 +01:00
Gustave Monce a57896c429 Fixed typo 2019-12-22 15:53:25 +01:00
Gustave Monce 17e2dc2984 Fixed the UI for phone shut down 2019-12-22 13:34:03 +01:00
Gustave Monce 2371274ac9 Fix issue with label mode and Terminal commands 2019-12-22 13:23:53 +01:00
Gustave Monce 8d3a010bd4 Fix MMOS support for x50 devices 2019-12-22 12:54:23 +01:00
Gustave Monce a34904a4d4 Fix an issue with empty payloads 2019-12-22 12:37:47 +01:00
Gustave Monce c6459c694a Remove duplicate instructions. 2019-12-22 12:31:40 +01:00
Gustave Monce a2a1c2302b Code cleanup 2019-12-22 12:25:48 +01:00
Gustave Monce 0e6f905809 Implement the ability to re-unlock an already unlocked phone
+ Start to work on a better UI for reset
2019-12-22 12:23:46 +01:00
Gus 126429227e Added ability to backup device provisioned partitions 2019-07-28 10:27:08 +02:00
Gus bf7b09d551 Fixed issue regarding missing encoders for DiscUtils fat filesystem parsing 2019-07-27 09:48:08 +02:00
Gus b56595ac27 Fixed charging status indicator reporting incorrect current values 2019-07-27 09:35:02 +02:00
Gus 5dae1da560 Code update
- WPinternals is now a .NET Core 3.0 application
- Implemented new unlock process for Spec A devices
- Updated logic for unlocking Spec B devices
- Implemented MMOS support for Spec B devices
- Implemented battery status in Flash Mode
- Implemented Fuse configuration information in Flash Mode
- Implemented Reboot from mass storage for Spec A and some Spec B devices
- Implemented shutdown from flash mode (preliminary)
- Fixed label mode support for Spec B
2019-07-26 17:15:20 +02:00
698 changed files with 81433 additions and 160371 deletions
+60
View File
@@ -0,0 +1,60 @@
name: Bug Report
description: Create a bug report to help improve WPinternals
labels: [bug]
body:
- type: textarea
attributes:
label: Description
description: A clear and concise description of what the bug is.
validations:
required: true
- type: textarea
attributes:
label: Steps To Reproduce
description: Steps to reproduce the behavior.
placeholder: |
1. Go to '....'
2. Click on '....'
3. Scroll down to '....'
4. See the error
validations:
required: false
- type: textarea
attributes:
label: Expected behavior
description: A clear and concise description of what you expected to happen.
validations:
required: true
- type: input
id: wpi-version
attributes:
label: WPinternals Version
description: What version of WPinternals are you using?
placeholder: v2.9.2
validations:
required: true
- type: input
attributes:
label: Windows Version
description: What version of Windows are you using? Press <kbd>Win</kbd> + <kbd>Pause/Break</kbd> and copy.
placeholder: e.g. Windows 11 21H2 22000.132
validations:
required: true
- type: input
attributes:
label: Phone model
description: What phone model did you reproduce the bug on (if applicable)
placeholder: e.g. Lumia 950 XL (RM-1085)
validations:
required: false
- type: textarea
attributes:
label: Relevant Assets
description: |
A list of assets (logs, screenshots) relevant to this bug.
Tip: You can attach images or log files by clicking this area to highlight it and then dragging files in.
placeholder: |
To upload the log
- Copy the `WPinternals.log` files from `%ALLUSERSPROFILE%\WPinternals`
- Drag and drop them into this text area.
+37
View File
@@ -0,0 +1,37 @@
name: CI
on:
push:
branches: [master]
pull_request:
branches: [master]
jobs:
build:
runs-on: windows-latest
strategy:
matrix:
architecture: [x86, x64, arm64]
platform: [win]
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Install .NET SDK
uses: actions/setup-dotnet@v1
with:
dotnet-version: "8.0.x"
- name: Add MSBuild to PATH
uses: microsoft/setup-msbuild@v1.0.2
- name: Build utilities
shell: pwsh
run: |
msbuild /m /t:restore,wpinternals:publish /p:Platform=${{ matrix.architecture }} /p:RuntimeIdentifier=${{ matrix.platform }}-${{ matrix.architecture }} /p:PublishDir=${{ github.workspace }}/artifacts/${{ matrix.platform }}-${{ matrix.architecture }} /p:PublishSingleFile=true /p:PublishTrimmed=false WPinternals.sln
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: ${{ matrix.platform }}-${{ matrix.architecture }}
path: ${{ github.workspace }}/artifacts/${{ matrix.platform }}-${{ matrix.architecture }}
+334
View File
@@ -0,0 +1,334 @@
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
##
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
# User-specific files
*.rsuser
*.suo
# *.user
*.userosscache
*.sln.docstates
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
bld/
[Bb]in/
[Oo]bj/
[Ll]og/
# Visual Studio 2015/2017 cache/options directory
.vs/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/
# Visual Studio 2017 auto generated files
Generated\ Files/
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
# NUNIT
*.VisualState.xml
TestResult.xml
# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c
# Benchmark Results
BenchmarkDotNet.Artifacts/
# .NET Core
project.lock.json
project.fragment.lock.json
artifacts/
# StyleCop
StyleCopReport.xml
# Files built by Visual Studio
*_i.c
*_p.c
*_h.h
*.ilk
*.meta
*.obj
*.iobj
*.pch
*.pdb
*.ipdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*_wpftmp.csproj
*.log
*.vspscc
*.vssscc
.builds
*.pidb
*.svclog
*.scc
# Chutzpah Test files
_Chutzpah*
# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opendb
*.opensdf
*.sdf
*.cachefile
*.VC.db
*.VC.VC.opendb
# Visual Studio profiler
*.psess
*.vsp
*.vspx
*.sap
# Visual Studio Trace Files
*.e2e
# TFS 2012 Local Workspace
$tf/
# Guidance Automation Toolkit
*.gpState
# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user
# JustCode is a .NET coding add-in
.JustCode
# TeamCity is a build add-in
_TeamCity*
# DotCover is a Code Coverage Tool
*.dotCover
# AxoCover is a Code Coverage Tool
.axoCover/*
!.axoCover/settings.json
# Visual Studio code coverage results
*.coverage
*.coveragexml
# NCrunch
_NCrunch_*
.*crunch*.local.xml
nCrunchTemp_*
# MightyMoose
*.mm.*
AutoTest.Net/
# Web workbench (sass)
.sass-cache/
# Installshield output folder
[Ee]xpress/
# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html
# Click-Once directory
publish/
# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
# Note: Comment the next line if you want to checkin your web deploy settings,
# but database connection strings (with potential passwords) will be unencrypted
*.pubxml
*.publishproj
# Microsoft Azure Web App publish settings. Comment the next line if you want to
# checkin your Azure Web App publish settings, but sensitive information contained
# in these scripts will be unencrypted
PublishScripts/
# NuGet Packages
*.nupkg
# The packages folder can be ignored because of Package Restore
**/[Pp]ackages/*
# except build/, which is used as an MSBuild target.
!**/[Pp]ackages/build/
# Uncomment if necessary however generally it will be regenerated when needed
#!**/[Pp]ackages/repositories.config
# NuGet v3's project.json files produces more ignorable files
*.nuget.props
*.nuget.targets
# Microsoft Azure Build Output
csx/
*.build.csdef
# Microsoft Azure Emulator
ecf/
rcf/
# Windows Store app package directories and files
AppPackages/
BundleArtifacts/
Package.StoreAssociation.xml
_pkginfo.txt
*.appx
# Visual Studio cache files
# files ending in .cache can be ignored
*.[Cc]ache
# but keep track of directories ending in .cache
!*.[Cc]ache/
# Others
ClientBin/
~$*
*~
*.dbmdl
*.dbproj.schemaview
*.jfm
*.pfx
*.publishsettings
orleans.codegen.cs
# Including strong name files can present a security risk
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
#*.snk
# Since there are multiple workflows, uncomment next line to ignore bower_components
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
#bower_components/
# RIA/Silverlight projects
Generated_Code/
# Backup & report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
ServiceFabricBackup/
*.rptproj.bak
# SQL Server files
*.mdf
*.ldf
*.ndf
# Business Intelligence projects
*.rdl.data
*.bim.layout
*.bim_*.settings
*.rptproj.rsuser
# Microsoft Fakes
FakesAssemblies/
# GhostDoc plugin setting file
*.GhostDoc.xml
# Node.js Tools for Visual Studio
.ntvs_analysis.dat
node_modules/
# Visual Studio 6 build log
*.plg
# Visual Studio 6 workspace options file
*.opt
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
*.vbw
# Visual Studio LightSwitch build output
**/*.HTMLClient/GeneratedArtifacts
**/*.DesktopClient/GeneratedArtifacts
**/*.DesktopClient/ModelManifest.xml
**/*.Server/GeneratedArtifacts
**/*.Server/ModelManifest.xml
_Pvt_Extensions
# Paket dependency manager
.paket/paket.exe
paket-files/
# FAKE - F# Make
.fake/
# JetBrains Rider
.idea/
*.sln.iml
# CodeRush personal settings
.cr/personal
# Python Tools for Visual Studio (PTVS)
__pycache__/
*.pyc
# Cake - Uncomment if you are using it
# tools/**
# !tools/packages.config
# Tabs Studio
*.tss
# Telerik's JustMock configuration file
*.jmconfig
# BizTalk build output
*.btp.cs
*.btm.cs
*.odx.cs
*.xsd.cs
# OpenCover UI analysis results
OpenCover/
# Azure Stream Analytics local run output
ASALocalRun/
# MSBuild Binary and Structured Log
*.binlog
# NVidia Nsight GPU debugger configuration file
*.nvuser
# MFractors (Xamarin productivity tool) working folder
.mfractor/
# Local History for Visual Studio
.localhistory/
+10
View File
@@ -0,0 +1,10 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<RootNamespace>_7zip</RootNamespace>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>
+64 -55
View File
@@ -1,55 +1,64 @@
// Common/CRC.cs // Common/CRC.cs
namespace SevenZip namespace SevenZip
{ {
class CRC internal class CRC
{ {
public static readonly uint[] Table; public static readonly uint[] Table;
static CRC() static CRC()
{ {
Table = new uint[256]; Table = new uint[256];
const uint kPoly = 0xEDB88320; const uint kPoly = 0xEDB88320;
for (uint i = 0; i < 256; i++) for (uint i = 0; i < 256; i++)
{ {
uint r = i; uint r = i;
for (int j = 0; j < 8; j++) for (int j = 0; j < 8; j++)
if ((r & 1) != 0) {
r = (r >> 1) ^ kPoly; if ((r & 1) != 0)
else {
r >>= 1; r = (r >> 1) ^ kPoly;
Table[i] = r; }
} else
} {
r >>= 1;
uint _value = 0xFFFFFFFF; }
}
public void Init() { _value = 0xFFFFFFFF; }
Table[i] = r;
public void UpdateByte(byte b) }
{ }
_value = Table[(((byte)(_value)) ^ b)] ^ (_value >> 8);
} private uint _value = 0xFFFFFFFF;
public void Update(byte[] data, uint offset, uint size) public void Init() { _value = 0xFFFFFFFF; }
{
for (uint i = 0; i < size; i++) public void UpdateByte(byte b)
_value = Table[(((byte)(_value)) ^ data[offset + i])] ^ (_value >> 8); {
} _value = Table[((byte)_value) ^ b] ^ (_value >> 8);
}
public uint GetDigest() { return _value ^ 0xFFFFFFFF; }
public void Update(byte[] data, uint offset, uint size)
static uint CalculateDigest(byte[] data, uint offset, uint size) {
{ for (uint i = 0; i < size; i++)
CRC crc = new CRC(); {
// crc.Init(); _value = Table[((byte)_value) ^ data[offset + i]] ^ (_value >> 8);
crc.Update(data, offset, size); }
return crc.GetDigest(); }
}
public uint GetDigest() { return _value ^ 0xFFFFFFFF; }
static bool VerifyDigest(uint digest, byte[] data, uint offset, uint size)
{ private static uint CalculateDigest(byte[] data, uint offset, uint size)
return (CalculateDigest(data, offset, size) == digest); {
} CRC crc = new();
} // crc.Init();
} crc.Update(data, offset, size);
return crc.GetDigest();
}
private static bool VerifyDigest(uint digest, byte[] data, uint offset, uint size)
{
return CalculateDigest(data, offset, size) == digest;
}
}
}
+325 -274
View File
@@ -1,274 +1,325 @@
// CommandLineParser.cs // CommandLineParser.cs
using System; using System;
using System.Collections; using System.Collections;
namespace SevenZip.CommandLineParser namespace SevenZip.CommandLineParser
{ {
public enum SwitchType public enum SwitchType
{ {
Simple, Simple,
PostMinus, PostMinus,
LimitedPostString, LimitedPostString,
UnLimitedPostString, UnLimitedPostString,
PostChar PostChar
} }
public class SwitchForm public class SwitchForm
{ {
public string IDString; public string IDString;
public SwitchType Type; public SwitchType Type;
public bool Multi; public bool Multi;
public int MinLen; public int MinLen;
public int MaxLen; public int MaxLen;
public string PostCharSet; public string PostCharSet;
public SwitchForm(string idString, SwitchType type, bool multi, public SwitchForm(string idString, SwitchType type, bool multi,
int minLen, int maxLen, string postCharSet) int minLen, int maxLen, string postCharSet)
{ {
IDString = idString; IDString = idString;
Type = type; Type = type;
Multi = multi; Multi = multi;
MinLen = minLen; MinLen = minLen;
MaxLen = maxLen; MaxLen = maxLen;
PostCharSet = postCharSet; PostCharSet = postCharSet;
} }
public SwitchForm(string idString, SwitchType type, bool multi, int minLen): public SwitchForm(string idString, SwitchType type, bool multi, int minLen) :
this(idString, type, multi, minLen, 0, "") this(idString, type, multi, minLen, 0, "")
{ {
} }
public SwitchForm(string idString, SwitchType type, bool multi): public SwitchForm(string idString, SwitchType type, bool multi) :
this(idString, type, multi, 0) this(idString, type, multi, 0)
{ {
} }
} }
public class SwitchResult public class SwitchResult
{ {
public bool ThereIs; public bool ThereIs;
public bool WithMinus; public bool WithMinus;
public ArrayList PostStrings = new ArrayList(); public ArrayList PostStrings = [];
public int PostCharIndex; public int PostCharIndex;
public SwitchResult() public SwitchResult()
{ {
ThereIs = false; ThereIs = false;
} }
} }
public class Parser public class Parser
{ {
public ArrayList NonSwitchStrings = new ArrayList(); public ArrayList NonSwitchStrings = [];
SwitchResult[] _switches; private readonly SwitchResult[] _switches;
public Parser(int numSwitches) public Parser(int numSwitches)
{ {
_switches = new SwitchResult[numSwitches]; _switches = new SwitchResult[numSwitches];
for (int i = 0; i < numSwitches; i++) for (int i = 0; i < numSwitches; i++)
_switches[i] = new SwitchResult(); {
} _switches[i] = new SwitchResult();
}
bool ParseString(string srcString, SwitchForm[] switchForms) }
{
int len = srcString.Length; private bool ParseString(string srcString, SwitchForm[] switchForms)
if (len == 0) {
return false; int len = srcString.Length;
int pos = 0; if (len == 0)
if (!IsItSwitchChar(srcString[pos])) {
return false; return false;
while (pos < len) }
{
if (IsItSwitchChar(srcString[pos])) int pos = 0;
pos++; if (!IsItSwitchChar(srcString[pos]))
const int kNoLen = -1; {
int matchedSwitchIndex = 0; return false;
int maxLen = kNoLen; }
for (int switchIndex = 0; switchIndex < _switches.Length; switchIndex++)
{ while (pos < len)
int switchLen = switchForms[switchIndex].IDString.Length; {
if (switchLen <= maxLen || pos + switchLen > len) if (IsItSwitchChar(srcString[pos]))
continue; {
if (String.Compare(switchForms[switchIndex].IDString, 0, pos++;
srcString, pos, switchLen, true) == 0) }
{
matchedSwitchIndex = switchIndex; const int kNoLen = -1;
maxLen = switchLen; int matchedSwitchIndex = 0;
} int maxLen = kNoLen;
} for (int switchIndex = 0; switchIndex < _switches.Length; switchIndex++)
if (maxLen == kNoLen) {
throw new Exception("maxLen == kNoLen"); int switchLen = switchForms[switchIndex].IDString.Length;
SwitchResult matchedSwitch = _switches[matchedSwitchIndex]; if (switchLen <= maxLen || pos + switchLen > len)
SwitchForm switchForm = switchForms[matchedSwitchIndex]; {
if ((!switchForm.Multi) && matchedSwitch.ThereIs) continue;
throw new Exception("switch must be single"); }
matchedSwitch.ThereIs = true;
pos += maxLen; if (String.Compare(switchForms[switchIndex].IDString, 0,
int tailSize = len - pos; srcString, pos, switchLen, true) == 0)
SwitchType type = switchForm.Type; {
switch (type) matchedSwitchIndex = switchIndex;
{ maxLen = switchLen;
case SwitchType.PostMinus: }
{ }
if (tailSize == 0) if (maxLen == kNoLen)
matchedSwitch.WithMinus = false; {
else throw new Exception("maxLen == kNoLen");
{ }
matchedSwitch.WithMinus = (srcString[pos] == kSwitchMinus);
if (matchedSwitch.WithMinus) SwitchResult matchedSwitch = _switches[matchedSwitchIndex];
pos++; SwitchForm switchForm = switchForms[matchedSwitchIndex];
} if ((!switchForm.Multi) && matchedSwitch.ThereIs)
break; {
} throw new Exception("switch must be single");
case SwitchType.PostChar: }
{
if (tailSize < switchForm.MinLen) matchedSwitch.ThereIs = true;
throw new Exception("switch is not full"); pos += maxLen;
string charSet = switchForm.PostCharSet; int tailSize = len - pos;
const int kEmptyCharValue = -1; SwitchType type = switchForm.Type;
if (tailSize == 0) switch (type)
matchedSwitch.PostCharIndex = kEmptyCharValue; {
else case SwitchType.PostMinus:
{ {
int index = charSet.IndexOf(srcString[pos]); if (tailSize == 0)
if (index < 0) {
matchedSwitch.PostCharIndex = kEmptyCharValue; matchedSwitch.WithMinus = false;
else }
{ else
matchedSwitch.PostCharIndex = index; {
pos++; matchedSwitch.WithMinus = srcString[pos] == kSwitchMinus;
} if (matchedSwitch.WithMinus)
} {
break; pos++;
} }
case SwitchType.LimitedPostString: }
case SwitchType.UnLimitedPostString: break;
{ }
int minLen = switchForm.MinLen; case SwitchType.PostChar:
if (tailSize < minLen) {
throw new Exception("switch is not full"); if (tailSize < switchForm.MinLen)
if (type == SwitchType.UnLimitedPostString) {
{ throw new Exception("switch is not full");
matchedSwitch.PostStrings.Add(srcString.Substring(pos)); }
return true;
} string charSet = switchForm.PostCharSet;
String stringSwitch = srcString.Substring(pos, minLen); const int kEmptyCharValue = -1;
pos += minLen; if (tailSize == 0)
for (int i = minLen; i < switchForm.MaxLen && pos < len; i++, pos++) {
{ matchedSwitch.PostCharIndex = kEmptyCharValue;
char c = srcString[pos]; }
if (IsItSwitchChar(c)) else
break; {
stringSwitch += c; int index = charSet.IndexOf(srcString[pos]);
} if (index < 0)
matchedSwitch.PostStrings.Add(stringSwitch); {
break; matchedSwitch.PostCharIndex = kEmptyCharValue;
} }
} else
} {
return true; matchedSwitch.PostCharIndex = index;
pos++;
} }
}
public void ParseStrings(SwitchForm[] switchForms, string[] commandStrings) break;
{ }
int numCommandStrings = commandStrings.Length; case SwitchType.LimitedPostString:
bool stopSwitch = false; case SwitchType.UnLimitedPostString:
for (int i = 0; i < numCommandStrings; i++) {
{ int minLen = switchForm.MinLen;
string s = commandStrings[i]; if (tailSize < minLen)
if (stopSwitch) {
NonSwitchStrings.Add(s); throw new Exception("switch is not full");
else }
if (s == kStopSwitchParsing)
stopSwitch = true; if (type == SwitchType.UnLimitedPostString)
else {
if (!ParseString(s, switchForms)) matchedSwitch.PostStrings.Add(srcString[pos..]);
NonSwitchStrings.Add(s); return true;
} }
} String stringSwitch = srcString.Substring(pos, minLen);
pos += minLen;
public SwitchResult this[int index] { get { return _switches[index]; } } for (int i = minLen; i < switchForm.MaxLen && pos < len; i++, pos++)
{
public static int ParseCommand(CommandForm[] commandForms, string commandString, char c = srcString[pos];
out string postString) if (IsItSwitchChar(c))
{ {
for (int i = 0; i < commandForms.Length; i++) break;
{ }
string id = commandForms[i].IDString;
if (commandForms[i].PostStringMode) stringSwitch += c;
{ }
if (commandString.IndexOf(id) == 0) matchedSwitch.PostStrings.Add(stringSwitch);
{ break;
postString = commandString.Substring(id.Length); }
return i; }
} }
} return true;
else }
if (commandString == id)
{ public void ParseStrings(SwitchForm[] switchForms, string[] commandStrings)
postString = ""; {
return i; int numCommandStrings = commandStrings.Length;
} bool stopSwitch = false;
} for (int i = 0; i < numCommandStrings; i++)
postString = ""; {
return -1; string s = commandStrings[i];
} if (stopSwitch)
{
static bool ParseSubCharsCommand(int numForms, CommandSubCharsSet[] forms, NonSwitchStrings.Add(s);
string commandString, ArrayList indices) }
{ else
indices.Clear(); if (s == kStopSwitchParsing)
int numUsedChars = 0; {
for (int i = 0; i < numForms; i++) stopSwitch = true;
{ }
CommandSubCharsSet charsSet = forms[i]; else
int currentIndex = -1; if (!ParseString(s, switchForms))
int len = charsSet.Chars.Length; {
for (int j = 0; j < len; j++) NonSwitchStrings.Add(s);
{ }
char c = charsSet.Chars[j]; }
int newIndex = commandString.IndexOf(c); }
if (newIndex >= 0)
{ public SwitchResult this[int index] { get { return _switches[index]; } }
if (currentIndex >= 0)
return false; public static int ParseCommand(CommandForm[] commandForms, string commandString,
if (commandString.IndexOf(c, newIndex + 1) >= 0) out string postString)
return false; {
currentIndex = j; for (int i = 0; i < commandForms.Length; i++)
numUsedChars++; {
} string id = commandForms[i].IDString;
} if (commandForms[i].PostStringMode)
if (currentIndex == -1 && !charsSet.EmptyAllowed) {
return false; if (commandString.IndexOf(id) == 0)
indices.Add(currentIndex); {
} postString = commandString[id.Length..];
return (numUsedChars == commandString.Length); return i;
} }
const char kSwitchID1 = '-'; }
const char kSwitchID2 = '/'; else
if (commandString == id)
const char kSwitchMinus = '-'; {
const string kStopSwitchParsing = "--"; postString = "";
return i;
static bool IsItSwitchChar(char c) }
{ }
return (c == kSwitchID1 || c == kSwitchID2); postString = "";
} return -1;
} }
public class CommandForm private static bool ParseSubCharsCommand(int numForms, CommandSubCharsSet[] forms,
{ string commandString, ArrayList indices)
public string IDString = ""; {
public bool PostStringMode = false; indices.Clear();
public CommandForm(string idString, bool postStringMode) int numUsedChars = 0;
{ for (int i = 0; i < numForms; i++)
IDString = idString; {
PostStringMode = postStringMode; CommandSubCharsSet charsSet = forms[i];
} int currentIndex = -1;
} int len = charsSet.Chars.Length;
for (int j = 0; j < len; j++)
class CommandSubCharsSet {
{ char c = charsSet.Chars[j];
public string Chars = ""; int newIndex = commandString.IndexOf(c);
public bool EmptyAllowed = false; if (newIndex >= 0)
} {
} if (currentIndex >= 0)
{
return false;
}
if (commandString.IndexOf(c, newIndex + 1) >= 0)
{
return false;
}
currentIndex = j;
numUsedChars++;
}
}
if (currentIndex == -1 && !charsSet.EmptyAllowed)
{
return false;
}
indices.Add(currentIndex);
}
return numUsedChars == commandString.Length;
}
private const char kSwitchID1 = '-';
private const char kSwitchID2 = '/';
private const char kSwitchMinus = '-';
private const string kStopSwitchParsing = "--";
private static bool IsItSwitchChar(char c)
{
return c == kSwitchID1 || c == kSwitchID2;
}
}
public class CommandForm
{
public string IDString = "";
public bool PostStringMode = false;
public CommandForm(string idString, bool postStringMode)
{
IDString = idString;
PostStringMode = postStringMode;
}
}
internal class CommandSubCharsSet
{
public string Chars = "";
public bool EmptyAllowed = false;
}
}
+78 -72
View File
@@ -1,72 +1,78 @@
// InBuffer.cs // InBuffer.cs
namespace SevenZip.Buffer namespace SevenZip.Buffer
{ {
public class InBuffer public class InBuffer
{ {
byte[] m_Buffer; private readonly byte[] m_Buffer;
uint m_Pos; private uint m_Pos;
uint m_Limit; private uint m_Limit;
uint m_BufferSize; private readonly uint m_BufferSize;
System.IO.Stream m_Stream; private System.IO.Stream m_Stream;
bool m_StreamWasExhausted; private bool m_StreamWasExhausted;
ulong m_ProcessedSize; private ulong m_ProcessedSize;
public InBuffer(uint bufferSize) public InBuffer(uint bufferSize)
{ {
m_Buffer = new byte[bufferSize]; m_Buffer = new byte[bufferSize];
m_BufferSize = bufferSize; m_BufferSize = bufferSize;
} }
public void Init(System.IO.Stream stream) public void Init(System.IO.Stream stream)
{ {
m_Stream = stream; m_Stream = stream;
m_ProcessedSize = 0; m_ProcessedSize = 0;
m_Limit = 0; m_Limit = 0;
m_Pos = 0; m_Pos = 0;
m_StreamWasExhausted = false; m_StreamWasExhausted = false;
} }
public bool ReadBlock() public bool ReadBlock()
{ {
if (m_StreamWasExhausted) if (m_StreamWasExhausted)
return false; {
m_ProcessedSize += m_Pos; return false;
int aNumProcessedBytes = m_Stream.Read(m_Buffer, 0, (int)m_BufferSize); }
m_Pos = 0;
m_Limit = (uint)aNumProcessedBytes; m_ProcessedSize += m_Pos;
m_StreamWasExhausted = (aNumProcessedBytes == 0); int aNumProcessedBytes = m_Stream.Read(m_Buffer, 0, (int)m_BufferSize);
return (!m_StreamWasExhausted); m_Pos = 0;
} m_Limit = (uint)aNumProcessedBytes;
m_StreamWasExhausted = aNumProcessedBytes == 0;
return !m_StreamWasExhausted;
public void ReleaseStream() }
{
// m_Stream.Close(); public void ReleaseStream()
m_Stream = null; {
} // m_Stream.Close();
m_Stream = null;
public bool ReadByte(byte b) // check it }
{
if (m_Pos >= m_Limit) public bool ReadByte(byte b) // check it
if (!ReadBlock()) {
return false; if (m_Pos >= m_Limit && !ReadBlock())
b = m_Buffer[m_Pos++]; {
return true; return false;
} }
public byte ReadByte() b = m_Buffer[m_Pos++];
{ return true;
// return (byte)m_Stream.ReadByte(); }
if (m_Pos >= m_Limit)
if (!ReadBlock()) public byte ReadByte()
return 0xFF; {
return m_Buffer[m_Pos++]; // return (byte)m_Stream.ReadByte();
} if (m_Pos >= m_Limit && !ReadBlock())
{
public ulong GetProcessedSize() return 0xFF;
{ }
return m_ProcessedSize + m_Pos;
} return m_Buffer[m_Pos++];
} }
}
public ulong GetProcessedSize()
{
return m_ProcessedSize + m_Pos;
}
}
}
+52 -47
View File
@@ -1,47 +1,52 @@
// OutBuffer.cs // OutBuffer.cs
namespace SevenZip.Buffer namespace SevenZip.Buffer
{ {
public class OutBuffer public class OutBuffer
{ {
byte[] m_Buffer; private readonly byte[] m_Buffer;
uint m_Pos; private uint m_Pos;
uint m_BufferSize; private readonly uint m_BufferSize;
System.IO.Stream m_Stream; private System.IO.Stream m_Stream;
ulong m_ProcessedSize; private ulong m_ProcessedSize;
public OutBuffer(uint bufferSize) public OutBuffer(uint bufferSize)
{ {
m_Buffer = new byte[bufferSize]; m_Buffer = new byte[bufferSize];
m_BufferSize = bufferSize; m_BufferSize = bufferSize;
} }
public void SetStream(System.IO.Stream stream) { m_Stream = stream; } public void SetStream(System.IO.Stream stream) { m_Stream = stream; }
public void FlushStream() { m_Stream.Flush(); } public void FlushStream() { m_Stream.Flush(); }
public void CloseStream() { m_Stream.Close(); } public void CloseStream() { m_Stream.Close(); }
public void ReleaseStream() { m_Stream = null; } public void ReleaseStream() { m_Stream = null; }
public void Init() public void Init()
{ {
m_ProcessedSize = 0; m_ProcessedSize = 0;
m_Pos = 0; m_Pos = 0;
} }
public void WriteByte(byte b) public void WriteByte(byte b)
{ {
m_Buffer[m_Pos++] = b; m_Buffer[m_Pos++] = b;
if (m_Pos >= m_BufferSize) if (m_Pos >= m_BufferSize)
FlushData(); {
} FlushData();
}
public void FlushData() }
{
if (m_Pos == 0) public void FlushData()
return; {
m_Stream.Write(m_Buffer, 0, (int)m_Pos); if (m_Pos == 0)
m_Pos = 0; {
} return;
}
public ulong GetProcessedSize() { return m_ProcessedSize + m_Pos; }
} m_Stream.Write(m_Buffer, 0, (int)m_Pos);
} m_Pos = 0;
}
public ulong GetProcessedSize() { return m_ProcessedSize + m_Pos; }
}
}
+24 -24
View File
@@ -1,24 +1,24 @@
// IMatchFinder.cs // IMatchFinder.cs
using System; using System;
namespace SevenZip.Compression.LZ namespace SevenZip.Compression.LZ
{ {
interface IInWindowStream internal interface IInWindowStream
{ {
void SetStream(System.IO.Stream inStream); void SetStream(System.IO.Stream inStream);
void Init(); void Init();
void ReleaseStream(); void ReleaseStream();
Byte GetIndexByte(Int32 index); Byte GetIndexByte(Int32 index);
UInt32 GetMatchLen(Int32 index, UInt32 distance, UInt32 limit); UInt32 GetMatchLen(Int32 index, UInt32 distance, UInt32 limit);
UInt32 GetNumAvailableBytes(); UInt32 GetNumAvailableBytes();
} }
interface IMatchFinder : IInWindowStream internal interface IMatchFinder : IInWindowStream
{ {
void Create(UInt32 historySize, UInt32 keepAddBufferBefore, void Create(UInt32 historySize, UInt32 keepAddBufferBefore,
UInt32 matchMaxLen, UInt32 keepAddBufferAfter); UInt32 matchMaxLen, UInt32 keepAddBufferAfter);
UInt32 GetMatches(UInt32[] distances); UInt32 GetMatches(UInt32[] distances);
void Skip(UInt32 num); void Skip(UInt32 num);
} }
} }
+408 -367
View File
@@ -1,367 +1,408 @@
// LzBinTree.cs // LzBinTree.cs
using System; using System;
namespace SevenZip.Compression.LZ namespace SevenZip.Compression.LZ
{ {
public class BinTree : InWindow, IMatchFinder public class BinTree : InWindow, IMatchFinder
{ {
UInt32 _cyclicBufferPos; private UInt32 _cyclicBufferPos;
UInt32 _cyclicBufferSize = 0; private UInt32 _cyclicBufferSize = 0;
UInt32 _matchMaxLen; private UInt32 _matchMaxLen;
UInt32[] _son; private UInt32[] _son;
UInt32[] _hash; private UInt32[] _hash;
UInt32 _cutValue = 0xFF; private UInt32 _cutValue = 0xFF;
UInt32 _hashMask; private UInt32 _hashMask;
UInt32 _hashSizeSum = 0; private UInt32 _hashSizeSum = 0;
bool HASH_ARRAY = true; private bool HASH_ARRAY = true;
const UInt32 kHash2Size = 1 << 10; private const UInt32 kHash2Size = 1 << 10;
const UInt32 kHash3Size = 1 << 16; private const UInt32 kHash3Size = 1 << 16;
const UInt32 kBT2HashSize = 1 << 16; private const UInt32 kBT2HashSize = 1 << 16;
const UInt32 kStartMaxLen = 1; private const UInt32 kStartMaxLen = 1;
const UInt32 kHash3Offset = kHash2Size; private const UInt32 kHash3Offset = kHash2Size;
const UInt32 kEmptyHashValue = 0; private const UInt32 kEmptyHashValue = 0;
const UInt32 kMaxValForNormalize = ((UInt32)1 << 31) - 1; private const UInt32 kMaxValForNormalize = ((UInt32)1 << 31) - 1;
UInt32 kNumHashDirectBytes = 0; private UInt32 kNumHashDirectBytes = 0;
UInt32 kMinMatchCheck = 4; private UInt32 kMinMatchCheck = 4;
UInt32 kFixHashSize = kHash2Size + kHash3Size; private UInt32 kFixHashSize = kHash2Size + kHash3Size;
public void SetType(int numHashBytes) public void SetType(int numHashBytes)
{ {
HASH_ARRAY = (numHashBytes > 2); HASH_ARRAY = numHashBytes > 2;
if (HASH_ARRAY) if (HASH_ARRAY)
{ {
kNumHashDirectBytes = 0; kNumHashDirectBytes = 0;
kMinMatchCheck = 4; kMinMatchCheck = 4;
kFixHashSize = kHash2Size + kHash3Size; kFixHashSize = kHash2Size + kHash3Size;
} }
else else
{ {
kNumHashDirectBytes = 2; kNumHashDirectBytes = 2;
kMinMatchCheck = 2 + 1; kMinMatchCheck = 2 + 1;
kFixHashSize = 0; kFixHashSize = 0;
} }
} }
public new void SetStream(System.IO.Stream stream) { base.SetStream(stream); } public new void SetStream(System.IO.Stream stream) { base.SetStream(stream); }
public new void ReleaseStream() { base.ReleaseStream(); } public new void ReleaseStream() { base.ReleaseStream(); }
public new void Init() public new void Init()
{ {
base.Init(); base.Init();
for (UInt32 i = 0; i < _hashSizeSum; i++) for (UInt32 i = 0; i < _hashSizeSum; i++)
_hash[i] = kEmptyHashValue; {
_cyclicBufferPos = 0; _hash[i] = kEmptyHashValue;
ReduceOffsets(-1); }
}
_cyclicBufferPos = 0;
public new void MovePos() ReduceOffsets(-1);
{ }
if (++_cyclicBufferPos >= _cyclicBufferSize)
_cyclicBufferPos = 0; public new void MovePos()
base.MovePos(); {
if (_pos == kMaxValForNormalize) if (++_cyclicBufferPos >= _cyclicBufferSize)
Normalize(); {
} _cyclicBufferPos = 0;
}
public new Byte GetIndexByte(Int32 index) { return base.GetIndexByte(index); }
base.MovePos();
public new UInt32 GetMatchLen(Int32 index, UInt32 distance, UInt32 limit) if (_pos == kMaxValForNormalize)
{ return base.GetMatchLen(index, distance, limit); } {
Normalize();
public new UInt32 GetNumAvailableBytes() { return base.GetNumAvailableBytes(); } }
}
public void Create(UInt32 historySize, UInt32 keepAddBufferBefore,
UInt32 matchMaxLen, UInt32 keepAddBufferAfter) public new Byte GetIndexByte(Int32 index) { return base.GetIndexByte(index); }
{
if (historySize > kMaxValForNormalize - 256) public new UInt32 GetMatchLen(Int32 index, UInt32 distance, UInt32 limit)
throw new Exception(); { return base.GetMatchLen(index, distance, limit); }
_cutValue = 16 + (matchMaxLen >> 1);
public new UInt32 GetNumAvailableBytes() { return base.GetNumAvailableBytes(); }
UInt32 windowReservSize = (historySize + keepAddBufferBefore +
matchMaxLen + keepAddBufferAfter) / 2 + 256; public void Create(UInt32 historySize, UInt32 keepAddBufferBefore,
UInt32 matchMaxLen, UInt32 keepAddBufferAfter)
base.Create(historySize + keepAddBufferBefore, matchMaxLen + keepAddBufferAfter, windowReservSize); {
if (historySize > kMaxValForNormalize - 256)
_matchMaxLen = matchMaxLen; {
throw new Exception();
UInt32 cyclicBufferSize = historySize + 1; }
if (_cyclicBufferSize != cyclicBufferSize)
_son = new UInt32[(_cyclicBufferSize = cyclicBufferSize) * 2]; _cutValue = 16 + (matchMaxLen >> 1);
UInt32 hs = kBT2HashSize; UInt32 windowReservSize = ((historySize + keepAddBufferBefore +
matchMaxLen + keepAddBufferAfter) / 2) + 256;
if (HASH_ARRAY)
{ Create(historySize + keepAddBufferBefore, matchMaxLen + keepAddBufferAfter, windowReservSize);
hs = historySize - 1;
hs |= (hs >> 1); _matchMaxLen = matchMaxLen;
hs |= (hs >> 2);
hs |= (hs >> 4); UInt32 cyclicBufferSize = historySize + 1;
hs |= (hs >> 8); if (_cyclicBufferSize != cyclicBufferSize)
hs >>= 1; {
hs |= 0xFFFF; _son = new UInt32[(_cyclicBufferSize = cyclicBufferSize) * 2];
if (hs > (1 << 24)) }
hs >>= 1;
_hashMask = hs; UInt32 hs = kBT2HashSize;
hs++;
hs += kFixHashSize; if (HASH_ARRAY)
} {
if (hs != _hashSizeSum) hs = historySize - 1;
_hash = new UInt32[_hashSizeSum = hs]; hs |= hs >> 1;
} hs |= hs >> 2;
hs |= hs >> 4;
public UInt32 GetMatches(UInt32[] distances) hs |= hs >> 8;
{ hs >>= 1;
UInt32 lenLimit; hs |= 0xFFFF;
if (_pos + _matchMaxLen <= _streamPos) if (hs > (1 << 24))
lenLimit = _matchMaxLen; {
else hs >>= 1;
{ }
lenLimit = _streamPos - _pos;
if (lenLimit < kMinMatchCheck) _hashMask = hs;
{ hs++;
MovePos(); hs += kFixHashSize;
return 0; }
} if (hs != _hashSizeSum)
} {
_hash = new UInt32[_hashSizeSum = hs];
UInt32 offset = 0; }
UInt32 matchMinPos = (_pos > _cyclicBufferSize) ? (_pos - _cyclicBufferSize) : 0; }
UInt32 cur = _bufferOffset + _pos;
UInt32 maxLen = kStartMaxLen; // to avoid items for len < hashSize; public UInt32 GetMatches(UInt32[] distances)
UInt32 hashValue, hash2Value = 0, hash3Value = 0; {
UInt32 lenLimit;
if (HASH_ARRAY) if (_pos + _matchMaxLen <= _streamPos)
{ {
UInt32 temp = CRC.Table[_bufferBase[cur]] ^ _bufferBase[cur + 1]; lenLimit = _matchMaxLen;
hash2Value = temp & (kHash2Size - 1); }
temp ^= ((UInt32)(_bufferBase[cur + 2]) << 8); else
hash3Value = temp & (kHash3Size - 1); {
hashValue = (temp ^ (CRC.Table[_bufferBase[cur + 3]] << 5)) & _hashMask; lenLimit = _streamPos - _pos;
} if (lenLimit < kMinMatchCheck)
else {
hashValue = _bufferBase[cur] ^ ((UInt32)(_bufferBase[cur + 1]) << 8); MovePos();
return 0;
UInt32 curMatch = _hash[kFixHashSize + hashValue]; }
if (HASH_ARRAY) }
{
UInt32 curMatch2 = _hash[hash2Value]; UInt32 offset = 0;
UInt32 curMatch3 = _hash[kHash3Offset + hash3Value]; UInt32 matchMinPos = (_pos > _cyclicBufferSize) ? (_pos - _cyclicBufferSize) : 0;
_hash[hash2Value] = _pos; UInt32 cur = _bufferOffset + _pos;
_hash[kHash3Offset + hash3Value] = _pos; UInt32 maxLen = kStartMaxLen; // to avoid items for len < hashSize;
if (curMatch2 > matchMinPos) UInt32 hashValue, hash2Value = 0, hash3Value = 0;
if (_bufferBase[_bufferOffset + curMatch2] == _bufferBase[cur])
{ if (HASH_ARRAY)
distances[offset++] = maxLen = 2; {
distances[offset++] = _pos - curMatch2 - 1; UInt32 temp = CRC.Table[_bufferBase[cur]] ^ _bufferBase[cur + 1];
} hash2Value = temp & (kHash2Size - 1);
if (curMatch3 > matchMinPos) temp ^= (UInt32)_bufferBase[cur + 2] << 8;
if (_bufferBase[_bufferOffset + curMatch3] == _bufferBase[cur]) hash3Value = temp & (kHash3Size - 1);
{ hashValue = (temp ^ (CRC.Table[_bufferBase[cur + 3]] << 5)) & _hashMask;
if (curMatch3 == curMatch2) }
offset -= 2; else
distances[offset++] = maxLen = 3; {
distances[offset++] = _pos - curMatch3 - 1; hashValue = _bufferBase[cur] ^ ((UInt32)_bufferBase[cur + 1] << 8);
curMatch2 = curMatch3; }
}
if (offset != 0 && curMatch2 == curMatch) UInt32 curMatch = _hash[kFixHashSize + hashValue];
{ if (HASH_ARRAY)
offset -= 2; {
maxLen = kStartMaxLen; UInt32 curMatch2 = _hash[hash2Value];
} UInt32 curMatch3 = _hash[kHash3Offset + hash3Value];
} _hash[hash2Value] = _pos;
_hash[kHash3Offset + hash3Value] = _pos;
_hash[kFixHashSize + hashValue] = _pos; if (curMatch2 > matchMinPos && _bufferBase[_bufferOffset + curMatch2] == _bufferBase[cur])
{
UInt32 ptr0 = (_cyclicBufferPos << 1) + 1; distances[offset++] = maxLen = 2;
UInt32 ptr1 = (_cyclicBufferPos << 1); distances[offset++] = _pos - curMatch2 - 1;
}
UInt32 len0, len1;
len0 = len1 = kNumHashDirectBytes; if (curMatch3 > matchMinPos && _bufferBase[_bufferOffset + curMatch3] == _bufferBase[cur])
{
if (kNumHashDirectBytes != 0) if (curMatch3 == curMatch2)
{ {
if (curMatch > matchMinPos) offset -= 2;
{ }
if (_bufferBase[_bufferOffset + curMatch + kNumHashDirectBytes] !=
_bufferBase[cur + kNumHashDirectBytes]) distances[offset++] = maxLen = 3;
{ distances[offset++] = _pos - curMatch3 - 1;
distances[offset++] = maxLen = kNumHashDirectBytes; curMatch2 = curMatch3;
distances[offset++] = _pos - curMatch - 1; }
}
} if (offset != 0 && curMatch2 == curMatch)
} {
offset -= 2;
UInt32 count = _cutValue; maxLen = kStartMaxLen;
}
while(true) }
{
if(curMatch <= matchMinPos || count-- == 0) _hash[kFixHashSize + hashValue] = _pos;
{
_son[ptr0] = _son[ptr1] = kEmptyHashValue; UInt32 ptr0 = (_cyclicBufferPos << 1) + 1;
break; UInt32 ptr1 = _cyclicBufferPos << 1;
}
UInt32 delta = _pos - curMatch; UInt32 len0, len1;
UInt32 cyclicPos = ((delta <= _cyclicBufferPos) ? len0 = len1 = kNumHashDirectBytes;
(_cyclicBufferPos - delta) :
(_cyclicBufferPos - delta + _cyclicBufferSize)) << 1; if (kNumHashDirectBytes != 0 && curMatch > matchMinPos)
{
UInt32 pby1 = _bufferOffset + curMatch; if (_bufferBase[_bufferOffset + curMatch + kNumHashDirectBytes] !=
UInt32 len = Math.Min(len0, len1); _bufferBase[cur + kNumHashDirectBytes])
if (_bufferBase[pby1 + len] == _bufferBase[cur + len]) {
{ distances[offset++] = maxLen = kNumHashDirectBytes;
while(++len != lenLimit) distances[offset++] = _pos - curMatch - 1;
if (_bufferBase[pby1 + len] != _bufferBase[cur + len]) }
break; }
if (maxLen < len)
{ UInt32 count = _cutValue;
distances[offset++] = maxLen = len;
distances[offset++] = delta - 1; while (true)
if (len == lenLimit) {
{ if (curMatch <= matchMinPos || count-- == 0)
_son[ptr1] = _son[cyclicPos]; {
_son[ptr0] = _son[cyclicPos + 1]; _son[ptr0] = _son[ptr1] = kEmptyHashValue;
break; break;
} }
} UInt32 delta = _pos - curMatch;
} UInt32 cyclicPos = ((delta <= _cyclicBufferPos) ?
if (_bufferBase[pby1 + len] < _bufferBase[cur + len]) (_cyclicBufferPos - delta) :
{ (_cyclicBufferPos - delta + _cyclicBufferSize)) << 1;
_son[ptr1] = curMatch;
ptr1 = cyclicPos + 1; UInt32 pby1 = _bufferOffset + curMatch;
curMatch = _son[ptr1]; UInt32 len = Math.Min(len0, len1);
len1 = len; if (_bufferBase[pby1 + len] == _bufferBase[cur + len])
} {
else while (++len != lenLimit)
{ {
_son[ptr0] = curMatch; if (_bufferBase[pby1 + len] != _bufferBase[cur + len])
ptr0 = cyclicPos; {
curMatch = _son[ptr0]; break;
len0 = len; }
} }
}
MovePos(); if (maxLen < len)
return offset; {
} distances[offset++] = maxLen = len;
distances[offset++] = delta - 1;
public void Skip(UInt32 num) if (len == lenLimit)
{ {
do _son[ptr1] = _son[cyclicPos];
{ _son[ptr0] = _son[cyclicPos + 1];
UInt32 lenLimit; break;
if (_pos + _matchMaxLen <= _streamPos) }
lenLimit = _matchMaxLen; }
else }
{ if (_bufferBase[pby1 + len] < _bufferBase[cur + len])
lenLimit = _streamPos - _pos; {
if (lenLimit < kMinMatchCheck) _son[ptr1] = curMatch;
{ ptr1 = cyclicPos + 1;
MovePos(); curMatch = _son[ptr1];
continue; len1 = len;
} }
} else
{
UInt32 matchMinPos = (_pos > _cyclicBufferSize) ? (_pos - _cyclicBufferSize) : 0; _son[ptr0] = curMatch;
UInt32 cur = _bufferOffset + _pos; ptr0 = cyclicPos;
curMatch = _son[ptr0];
UInt32 hashValue; len0 = len;
}
if (HASH_ARRAY) }
{ MovePos();
UInt32 temp = CRC.Table[_bufferBase[cur]] ^ _bufferBase[cur + 1]; return offset;
UInt32 hash2Value = temp & (kHash2Size - 1); }
_hash[hash2Value] = _pos;
temp ^= ((UInt32)(_bufferBase[cur + 2]) << 8); public void Skip(UInt32 num)
UInt32 hash3Value = temp & (kHash3Size - 1); {
_hash[kHash3Offset + hash3Value] = _pos; do
hashValue = (temp ^ (CRC.Table[_bufferBase[cur + 3]] << 5)) & _hashMask; {
} UInt32 lenLimit;
else if (_pos + _matchMaxLen <= _streamPos)
hashValue = _bufferBase[cur] ^ ((UInt32)(_bufferBase[cur + 1]) << 8); {
lenLimit = _matchMaxLen;
UInt32 curMatch = _hash[kFixHashSize + hashValue]; }
_hash[kFixHashSize + hashValue] = _pos; else
{
UInt32 ptr0 = (_cyclicBufferPos << 1) + 1; lenLimit = _streamPos - _pos;
UInt32 ptr1 = (_cyclicBufferPos << 1); if (lenLimit < kMinMatchCheck)
{
UInt32 len0, len1; MovePos();
len0 = len1 = kNumHashDirectBytes; continue;
}
UInt32 count = _cutValue; }
while (true)
{ UInt32 matchMinPos = (_pos > _cyclicBufferSize) ? (_pos - _cyclicBufferSize) : 0;
if (curMatch <= matchMinPos || count-- == 0) UInt32 cur = _bufferOffset + _pos;
{
_son[ptr0] = _son[ptr1] = kEmptyHashValue; UInt32 hashValue;
break;
} if (HASH_ARRAY)
{
UInt32 delta = _pos - curMatch; UInt32 temp = CRC.Table[_bufferBase[cur]] ^ _bufferBase[cur + 1];
UInt32 cyclicPos = ((delta <= _cyclicBufferPos) ? UInt32 hash2Value = temp & (kHash2Size - 1);
(_cyclicBufferPos - delta) : _hash[hash2Value] = _pos;
(_cyclicBufferPos - delta + _cyclicBufferSize)) << 1; temp ^= (UInt32)_bufferBase[cur + 2] << 8;
UInt32 hash3Value = temp & (kHash3Size - 1);
UInt32 pby1 = _bufferOffset + curMatch; _hash[kHash3Offset + hash3Value] = _pos;
UInt32 len = Math.Min(len0, len1); hashValue = (temp ^ (CRC.Table[_bufferBase[cur + 3]] << 5)) & _hashMask;
if (_bufferBase[pby1 + len] == _bufferBase[cur + len]) }
{ else
while (++len != lenLimit) {
if (_bufferBase[pby1 + len] != _bufferBase[cur + len]) hashValue = _bufferBase[cur] ^ ((UInt32)_bufferBase[cur + 1] << 8);
break; }
if (len == lenLimit)
{ UInt32 curMatch = _hash[kFixHashSize + hashValue];
_son[ptr1] = _son[cyclicPos]; _hash[kFixHashSize + hashValue] = _pos;
_son[ptr0] = _son[cyclicPos + 1];
break; UInt32 ptr0 = (_cyclicBufferPos << 1) + 1;
} UInt32 ptr1 = _cyclicBufferPos << 1;
}
if (_bufferBase[pby1 + len] < _bufferBase[cur + len]) UInt32 len0, len1;
{ len0 = len1 = kNumHashDirectBytes;
_son[ptr1] = curMatch;
ptr1 = cyclicPos + 1; UInt32 count = _cutValue;
curMatch = _son[ptr1]; while (true)
len1 = len; {
} if (curMatch <= matchMinPos || count-- == 0)
else {
{ _son[ptr0] = _son[ptr1] = kEmptyHashValue;
_son[ptr0] = curMatch; break;
ptr0 = cyclicPos; }
curMatch = _son[ptr0];
len0 = len; UInt32 delta = _pos - curMatch;
} UInt32 cyclicPos = ((delta <= _cyclicBufferPos) ?
} (_cyclicBufferPos - delta) :
MovePos(); (_cyclicBufferPos - delta + _cyclicBufferSize)) << 1;
}
while (--num != 0); UInt32 pby1 = _bufferOffset + curMatch;
} UInt32 len = Math.Min(len0, len1);
if (_bufferBase[pby1 + len] == _bufferBase[cur + len])
void NormalizeLinks(UInt32[] items, UInt32 numItems, UInt32 subValue) {
{ while (++len != lenLimit)
for (UInt32 i = 0; i < numItems; i++) {
{ if (_bufferBase[pby1 + len] != _bufferBase[cur + len])
UInt32 value = items[i]; {
if (value <= subValue) break;
value = kEmptyHashValue; }
else }
value -= subValue;
items[i] = value; if (len == lenLimit)
} {
} _son[ptr1] = _son[cyclicPos];
_son[ptr0] = _son[cyclicPos + 1];
void Normalize() break;
{ }
UInt32 subValue = _pos - _cyclicBufferSize; }
NormalizeLinks(_son, _cyclicBufferSize * 2, subValue); if (_bufferBase[pby1 + len] < _bufferBase[cur + len])
NormalizeLinks(_hash, _hashSizeSum, subValue); {
ReduceOffsets((Int32)subValue); _son[ptr1] = curMatch;
} ptr1 = cyclicPos + 1;
curMatch = _son[ptr1];
public void SetCutValue(UInt32 cutValue) { _cutValue = cutValue; } len1 = len;
} }
} else
{
_son[ptr0] = curMatch;
ptr0 = cyclicPos;
curMatch = _son[ptr0];
len0 = len;
}
}
MovePos();
}
while (--num != 0);
}
private void NormalizeLinks(UInt32[] items, UInt32 numItems, UInt32 subValue)
{
for (UInt32 i = 0; i < numItems; i++)
{
UInt32 value = items[i];
if (value <= subValue)
{
value = kEmptyHashValue;
}
else
{
value -= subValue;
}
items[i] = value;
}
}
private void Normalize()
{
UInt32 subValue = _pos - _cyclicBufferSize;
NormalizeLinks(_son, _cyclicBufferSize * 2, subValue);
NormalizeLinks(_hash, _hashSizeSum, subValue);
ReduceOffsets((Int32)subValue);
}
public void SetCutValue(UInt32 cutValue) { _cutValue = cutValue; }
}
}
+155 -132
View File
@@ -1,132 +1,155 @@
// LzInWindow.cs // LzInWindow.cs
using System; using System;
namespace SevenZip.Compression.LZ namespace SevenZip.Compression.LZ
{ {
public class InWindow public class InWindow
{ {
public Byte[] _bufferBase = null; // pointer to buffer with data public Byte[] _bufferBase = null; // pointer to buffer with data
System.IO.Stream _stream; private System.IO.Stream _stream;
UInt32 _posLimit; // offset (from _buffer) of first byte when new block reading must be done private UInt32 _posLimit; // offset (from _buffer) of first byte when new block reading must be done
bool _streamEndWasReached; // if (true) then _streamPos shows real end of stream private bool _streamEndWasReached; // if (true) then _streamPos shows real end of stream
UInt32 _pointerToLastSafePosition; private UInt32 _pointerToLastSafePosition;
public UInt32 _bufferOffset; public UInt32 _bufferOffset;
public UInt32 _blockSize; // Size of Allocated memory block public UInt32 _blockSize; // Size of Allocated memory block
public UInt32 _pos; // offset (from _buffer) of curent byte public UInt32 _pos; // offset (from _buffer) of curent byte
UInt32 _keepSizeBefore; // how many BYTEs must be kept in buffer before _pos private UInt32 _keepSizeBefore; // how many BYTEs must be kept in buffer before _pos
UInt32 _keepSizeAfter; // how many BYTEs must be kept buffer after _pos private UInt32 _keepSizeAfter; // how many BYTEs must be kept buffer after _pos
public UInt32 _streamPos; // offset (from _buffer) of first not read byte from Stream public UInt32 _streamPos; // offset (from _buffer) of first not read byte from Stream
public void MoveBlock() public void MoveBlock()
{ {
UInt32 offset = (UInt32)(_bufferOffset) + _pos - _keepSizeBefore; UInt32 offset = _bufferOffset + _pos - _keepSizeBefore;
// we need one additional byte, since MovePos moves on 1 byte. // we need one additional byte, since MovePos moves on 1 byte.
if (offset > 0) if (offset > 0)
offset--; {
offset--;
UInt32 numBytes = (UInt32)(_bufferOffset) + _streamPos - offset; }
// check negative offset ???? UInt32 numBytes = _bufferOffset + _streamPos - offset;
for (UInt32 i = 0; i < numBytes; i++)
_bufferBase[i] = _bufferBase[offset + i]; // check negative offset ????
_bufferOffset -= offset; for (UInt32 i = 0; i < numBytes; i++)
} {
_bufferBase[i] = _bufferBase[offset + i];
public virtual void ReadBlock() }
{
if (_streamEndWasReached) _bufferOffset -= offset;
return; }
while (true)
{ public virtual void ReadBlock()
int size = (int)((0 - _bufferOffset) + _blockSize - _streamPos); {
if (size == 0) if (_streamEndWasReached)
return; {
int numReadBytes = _stream.Read(_bufferBase, (int)(_bufferOffset + _streamPos), size); return;
if (numReadBytes == 0) }
{
_posLimit = _streamPos; while (true)
UInt32 pointerToPostion = _bufferOffset + _posLimit; {
if (pointerToPostion > _pointerToLastSafePosition) int size = (int)(0 - _bufferOffset + _blockSize - _streamPos);
_posLimit = (UInt32)(_pointerToLastSafePosition - _bufferOffset); if (size == 0)
{
_streamEndWasReached = true; return;
return; }
}
_streamPos += (UInt32)numReadBytes; int numReadBytes = _stream.Read(_bufferBase, (int)(_bufferOffset + _streamPos), size);
if (_streamPos >= _pos + _keepSizeAfter) if (numReadBytes == 0)
_posLimit = _streamPos - _keepSizeAfter; {
} _posLimit = _streamPos;
} UInt32 pointerToPostion = _bufferOffset + _posLimit;
if (pointerToPostion > _pointerToLastSafePosition)
void Free() { _bufferBase = null; } {
_posLimit = _pointerToLastSafePosition - _bufferOffset;
public void Create(UInt32 keepSizeBefore, UInt32 keepSizeAfter, UInt32 keepSizeReserv) }
{
_keepSizeBefore = keepSizeBefore; _streamEndWasReached = true;
_keepSizeAfter = keepSizeAfter; return;
UInt32 blockSize = keepSizeBefore + keepSizeAfter + keepSizeReserv; }
if (_bufferBase == null || _blockSize != blockSize) _streamPos += (UInt32)numReadBytes;
{ if (_streamPos >= _pos + _keepSizeAfter)
Free(); {
_blockSize = blockSize; _posLimit = _streamPos - _keepSizeAfter;
_bufferBase = new Byte[_blockSize]; }
} }
_pointerToLastSafePosition = _blockSize - keepSizeAfter; }
}
private void Free() { _bufferBase = null; }
public void SetStream(System.IO.Stream stream) { _stream = stream; }
public void ReleaseStream() { _stream = null; } public void Create(UInt32 keepSizeBefore, UInt32 keepSizeAfter, UInt32 keepSizeReserv)
{
public void Init() _keepSizeBefore = keepSizeBefore;
{ _keepSizeAfter = keepSizeAfter;
_bufferOffset = 0; UInt32 blockSize = keepSizeBefore + keepSizeAfter + keepSizeReserv;
_pos = 0; if (_bufferBase == null || _blockSize != blockSize)
_streamPos = 0; {
_streamEndWasReached = false; Free();
ReadBlock(); _blockSize = blockSize;
} _bufferBase = new Byte[_blockSize];
}
public void MovePos() _pointerToLastSafePosition = _blockSize - keepSizeAfter;
{ }
_pos++;
if (_pos > _posLimit) public void SetStream(System.IO.Stream stream) { _stream = stream; }
{ public void ReleaseStream() { _stream = null; }
UInt32 pointerToPostion = _bufferOffset + _pos;
if (pointerToPostion > _pointerToLastSafePosition) public void Init()
MoveBlock(); {
ReadBlock(); _bufferOffset = 0;
} _pos = 0;
} _streamPos = 0;
_streamEndWasReached = false;
public Byte GetIndexByte(Int32 index) { return _bufferBase[_bufferOffset + _pos + index]; } ReadBlock();
}
// index + limit have not to exceed _keepSizeAfter;
public UInt32 GetMatchLen(Int32 index, UInt32 distance, UInt32 limit) public void MovePos()
{ {
if (_streamEndWasReached) _pos++;
if ((_pos + index) + limit > _streamPos) if (_pos > _posLimit)
limit = _streamPos - (UInt32)(_pos + index); {
distance++; UInt32 pointerToPostion = _bufferOffset + _pos;
// Byte *pby = _buffer + (size_t)_pos + index; if (pointerToPostion > _pointerToLastSafePosition)
UInt32 pby = _bufferOffset + _pos + (UInt32)index; {
MoveBlock();
UInt32 i; }
for (i = 0; i < limit && _bufferBase[pby + i] == _bufferBase[pby + i - distance]; i++);
return i; ReadBlock();
} }
}
public UInt32 GetNumAvailableBytes() { return _streamPos - _pos; }
public Byte GetIndexByte(Int32 index) { return _bufferBase[_bufferOffset + _pos + index]; }
public void ReduceOffsets(Int32 subValue)
{ // index + limit have not to exceed _keepSizeAfter;
_bufferOffset += (UInt32)subValue; public UInt32 GetMatchLen(Int32 index, UInt32 distance, UInt32 limit)
_posLimit -= (UInt32)subValue; {
_pos -= (UInt32)subValue; if (_streamEndWasReached && _pos + index + limit > _streamPos)
_streamPos -= (UInt32)subValue; {
} limit = _streamPos - (UInt32)(_pos + index);
} }
}
distance++;
// Byte *pby = _buffer + (size_t)_pos + index;
UInt32 pby = _bufferOffset + _pos + (UInt32)index;
UInt32 i;
for (i = 0; i < limit && _bufferBase[pby + i] == _bufferBase[pby + i - distance]; i++)
{
}
return i;
}
public UInt32 GetNumAvailableBytes() { return _streamPos - _pos; }
public void ReduceOffsets(Int32 subValue)
{
_bufferOffset += (UInt32)subValue;
_posLimit -= (UInt32)subValue;
_pos -= (UInt32)subValue;
_streamPos -= (UInt32)subValue;
}
}
}
+137 -110
View File
@@ -1,110 +1,137 @@
// LzOutWindow.cs // LzOutWindow.cs
namespace SevenZip.Compression.LZ namespace SevenZip.Compression.LZ
{ {
public class OutWindow public class OutWindow
{ {
byte[] _buffer = null; private byte[] _buffer = null;
uint _pos; private uint _pos;
uint _windowSize = 0; private uint _windowSize = 0;
uint _streamPos; private uint _streamPos;
System.IO.Stream _stream; private System.IO.Stream _stream;
public uint TrainSize = 0; public uint TrainSize = 0;
public void Create(uint windowSize) public void Create(uint windowSize)
{ {
if (_windowSize != windowSize) if (_windowSize != windowSize)
{ {
// System.GC.Collect(); // System.GC.Collect();
_buffer = new byte[windowSize]; _buffer = new byte[windowSize];
} }
_windowSize = windowSize; _windowSize = windowSize;
_pos = 0; _pos = 0;
_streamPos = 0; _streamPos = 0;
} }
public void Init(System.IO.Stream stream, bool solid) public void Init(System.IO.Stream stream, bool solid)
{ {
ReleaseStream(); ReleaseStream();
_stream = stream; _stream = stream;
if (!solid) if (!solid)
{ {
_streamPos = 0; _streamPos = 0;
_pos = 0; _pos = 0;
TrainSize = 0; TrainSize = 0;
} }
} }
public bool Train(System.IO.Stream stream) public bool Train(System.IO.Stream stream)
{ {
long len = stream.Length; long len = stream.Length;
uint size = (len < _windowSize) ? (uint)len : _windowSize; uint size = (len < _windowSize) ? (uint)len : _windowSize;
TrainSize = size; TrainSize = size;
stream.Position = len - size; stream.Position = len - size;
_streamPos = _pos = 0; _streamPos = _pos = 0;
while (size > 0) while (size > 0)
{ {
uint curSize = _windowSize - _pos; uint curSize = _windowSize - _pos;
if (size < curSize) if (size < curSize)
curSize = size; {
int numReadBytes = stream.Read(_buffer, (int)_pos, (int)curSize); curSize = size;
if (numReadBytes == 0) }
return false;
size -= (uint)numReadBytes; int numReadBytes = stream.Read(_buffer, (int)_pos, (int)curSize);
_pos += (uint)numReadBytes; if (numReadBytes == 0)
_streamPos += (uint)numReadBytes; {
if (_pos == _windowSize) return false;
_streamPos = _pos = 0; }
}
return true; size -= (uint)numReadBytes;
} _pos += (uint)numReadBytes;
_streamPos += (uint)numReadBytes;
public void ReleaseStream() if (_pos == _windowSize)
{ {
Flush(); _streamPos = _pos = 0;
_stream = null; }
} }
return true;
public void Flush() }
{
uint size = _pos - _streamPos; public void ReleaseStream()
if (size == 0) {
return; Flush();
_stream.Write(_buffer, (int)_streamPos, (int)size); _stream = null;
if (_pos >= _windowSize) }
_pos = 0;
_streamPos = _pos; public void Flush()
} {
uint size = _pos - _streamPos;
public void CopyBlock(uint distance, uint len) if (size == 0)
{ {
uint pos = _pos - distance - 1; return;
if (pos >= _windowSize) }
pos += _windowSize;
for (; len > 0; len--) _stream.Write(_buffer, (int)_streamPos, (int)size);
{ if (_pos >= _windowSize)
if (pos >= _windowSize) {
pos = 0; _pos = 0;
_buffer[_pos++] = _buffer[pos++]; }
if (_pos >= _windowSize)
Flush(); _streamPos = _pos;
} }
}
public void CopyBlock(uint distance, uint len)
public void PutByte(byte b) {
{ uint pos = _pos - distance - 1;
_buffer[_pos++] = b; if (pos >= _windowSize)
if (_pos >= _windowSize) {
Flush(); pos += _windowSize;
} }
public byte GetByte(uint distance) for (; len > 0; len--)
{ {
uint pos = _pos - distance - 1; if (pos >= _windowSize)
if (pos >= _windowSize) {
pos += _windowSize; pos = 0;
return _buffer[pos]; }
}
} _buffer[_pos++] = _buffer[pos++];
} if (_pos >= _windowSize)
{
Flush();
}
}
}
public void PutByte(byte b)
{
_buffer[_pos++] = b;
if (_pos >= _windowSize)
{
Flush();
}
}
public byte GetByte(uint distance)
{
uint pos = _pos - distance - 1;
if (pos >= _windowSize)
{
pos += _windowSize;
}
return _buffer[pos];
}
}
}
+88 -76
View File
@@ -1,76 +1,88 @@
// LzmaBase.cs // LzmaBase.cs
namespace SevenZip.Compression.LZMA namespace SevenZip.Compression.LZMA
{ {
internal abstract class Base internal abstract class Base
{ {
public const uint kNumRepDistances = 4; public const uint kNumRepDistances = 4;
public const uint kNumStates = 12; public const uint kNumStates = 12;
// static byte []kLiteralNextStates = {0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 4, 5}; // static byte []kLiteralNextStates = {0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 4, 5};
// static byte []kMatchNextStates = {7, 7, 7, 7, 7, 7, 7, 10, 10, 10, 10, 10}; // static byte []kMatchNextStates = {7, 7, 7, 7, 7, 7, 7, 10, 10, 10, 10, 10};
// static byte []kRepNextStates = {8, 8, 8, 8, 8, 8, 8, 11, 11, 11, 11, 11}; // static byte []kRepNextStates = {8, 8, 8, 8, 8, 8, 8, 11, 11, 11, 11, 11};
// static byte []kShortRepNextStates = {9, 9, 9, 9, 9, 9, 9, 11, 11, 11, 11, 11}; // static byte []kShortRepNextStates = {9, 9, 9, 9, 9, 9, 9, 11, 11, 11, 11, 11};
public struct State public struct State
{ {
public uint Index; public uint Index;
public void Init() { Index = 0; } public void Init() { Index = 0; }
public void UpdateChar() public void UpdateChar()
{ {
if (Index < 4) Index = 0; if (Index < 4)
else if (Index < 10) Index -= 3; {
else Index -= 6; Index = 0;
} }
public void UpdateMatch() { Index = (uint)(Index < 7 ? 7 : 10); } else if (Index < 10)
public void UpdateRep() { Index = (uint)(Index < 7 ? 8 : 11); } {
public void UpdateShortRep() { Index = (uint)(Index < 7 ? 9 : 11); } Index -= 3;
public bool IsCharState() { return Index < 7; } }
} else
{
public const int kNumPosSlotBits = 6; Index -= 6;
public const int kDicLogSizeMin = 0; }
// public const int kDicLogSizeMax = 30; }
// public const uint kDistTableSizeMax = kDicLogSizeMax * 2; public void UpdateMatch() { Index = (uint)(Index < 7 ? 7 : 10); }
public void UpdateRep() { Index = (uint)(Index < 7 ? 8 : 11); }
public const int kNumLenToPosStatesBits = 2; // it's for speed optimization public void UpdateShortRep() { Index = (uint)(Index < 7 ? 9 : 11); }
public const uint kNumLenToPosStates = 1 << kNumLenToPosStatesBits; public bool IsCharState() { return Index < 7; }
}
public const uint kMatchMinLen = 2;
public const int kNumPosSlotBits = 6;
public static uint GetLenToPosState(uint len) public const int kDicLogSizeMin = 0;
{ // public const int kDicLogSizeMax = 30;
len -= kMatchMinLen; // public const uint kDistTableSizeMax = kDicLogSizeMax * 2;
if (len < kNumLenToPosStates)
return len; public const int kNumLenToPosStatesBits = 2; // it's for speed optimization
return (uint)(kNumLenToPosStates - 1); public const uint kNumLenToPosStates = 1 << kNumLenToPosStatesBits;
}
public const uint kMatchMinLen = 2;
public const int kNumAlignBits = 4;
public const uint kAlignTableSize = 1 << kNumAlignBits; public static uint GetLenToPosState(uint len)
public const uint kAlignMask = (kAlignTableSize - 1); {
len -= kMatchMinLen;
public const uint kStartPosModelIndex = 4; if (len < kNumLenToPosStates)
public const uint kEndPosModelIndex = 14; {
public const uint kNumPosModels = kEndPosModelIndex - kStartPosModelIndex; return len;
}
public const uint kNumFullDistances = 1 << ((int)kEndPosModelIndex / 2);
return kNumLenToPosStates - 1;
public const uint kNumLitPosStatesBitsEncodingMax = 4; }
public const uint kNumLitContextBitsMax = 8;
public const int kNumAlignBits = 4;
public const int kNumPosStatesBitsMax = 4; public const uint kAlignTableSize = 1 << kNumAlignBits;
public const uint kNumPosStatesMax = (1 << kNumPosStatesBitsMax); public const uint kAlignMask = kAlignTableSize - 1;
public const int kNumPosStatesBitsEncodingMax = 4;
public const uint kNumPosStatesEncodingMax = (1 << kNumPosStatesBitsEncodingMax); public const uint kStartPosModelIndex = 4;
public const uint kEndPosModelIndex = 14;
public const int kNumLowLenBits = 3; public const uint kNumPosModels = kEndPosModelIndex - kStartPosModelIndex;
public const int kNumMidLenBits = 3;
public const int kNumHighLenBits = 8; public const uint kNumFullDistances = 1 << ((int)kEndPosModelIndex / 2);
public const uint kNumLowLenSymbols = 1 << kNumLowLenBits;
public const uint kNumMidLenSymbols = 1 << kNumMidLenBits; public const uint kNumLitPosStatesBitsEncodingMax = 4;
public const uint kNumLenSymbols = kNumLowLenSymbols + kNumMidLenSymbols + public const uint kNumLitContextBitsMax = 8;
(1 << kNumHighLenBits);
public const uint kMatchMaxLen = kMatchMinLen + kNumLenSymbols - 1; public const int kNumPosStatesBitsMax = 4;
} public const uint kNumPosStatesMax = 1 << kNumPosStatesBitsMax;
} public const int kNumPosStatesBitsEncodingMax = 4;
public const uint kNumPosStatesEncodingMax = 1 << kNumPosStatesBitsEncodingMax;
public const int kNumLowLenBits = 3;
public const int kNumMidLenBits = 3;
public const int kNumHighLenBits = 8;
public const uint kNumLowLenSymbols = 1 << kNumLowLenBits;
public const uint kNumMidLenSymbols = 1 << kNumMidLenBits;
public const uint kNumLenSymbols = kNumLowLenSymbols + kNumMidLenSymbols +
(1 << kNumHighLenBits);
public const uint kMatchMaxLen = kMatchMinLen + kNumLenSymbols - 1;
}
}
+465 -398
View File
@@ -1,398 +1,465 @@
// LzmaDecoder.cs // LzmaDecoder.cs
using System; using System;
namespace SevenZip.Compression.LZMA namespace SevenZip.Compression.LZMA
{ {
using RangeCoder; using RangeCoder;
using System.Threading;
public class Decoder : ICoder, ISetDecoderProperties // ,System.IO.Stream
{ public class Decoder : ICoder, ISetDecoderProperties // ,System.IO.Stream
class LenDecoder {
{ private class LenDecoder
BitDecoder m_Choice = new BitDecoder(); {
BitDecoder m_Choice2 = new BitDecoder(); private BitDecoder m_Choice = new();
BitTreeDecoder[] m_LowCoder = new BitTreeDecoder[Base.kNumPosStatesMax]; private BitDecoder m_Choice2 = new();
BitTreeDecoder[] m_MidCoder = new BitTreeDecoder[Base.kNumPosStatesMax]; private readonly BitTreeDecoder[] m_LowCoder = new BitTreeDecoder[Base.kNumPosStatesMax];
BitTreeDecoder m_HighCoder = new BitTreeDecoder(Base.kNumHighLenBits); private readonly BitTreeDecoder[] m_MidCoder = new BitTreeDecoder[Base.kNumPosStatesMax];
uint m_NumPosStates = 0; private readonly BitTreeDecoder m_HighCoder = new(Base.kNumHighLenBits);
private uint m_NumPosStates = 0;
public void Create(uint numPosStates)
{ public void Create(uint numPosStates)
for (uint posState = m_NumPosStates; posState < numPosStates; posState++) {
{ for (uint posState = m_NumPosStates; posState < numPosStates; posState++)
m_LowCoder[posState] = new BitTreeDecoder(Base.kNumLowLenBits); {
m_MidCoder[posState] = new BitTreeDecoder(Base.kNumMidLenBits); m_LowCoder[posState] = new BitTreeDecoder(Base.kNumLowLenBits);
} m_MidCoder[posState] = new BitTreeDecoder(Base.kNumMidLenBits);
m_NumPosStates = numPosStates; }
} m_NumPosStates = numPosStates;
}
public void Init()
{ public void Init()
m_Choice.Init(); {
for (uint posState = 0; posState < m_NumPosStates; posState++) m_Choice.Init();
{ for (uint posState = 0; posState < m_NumPosStates; posState++)
m_LowCoder[posState].Init(); {
m_MidCoder[posState].Init(); m_LowCoder[posState].Init();
} m_MidCoder[posState].Init();
m_Choice2.Init(); }
m_HighCoder.Init(); m_Choice2.Init();
} m_HighCoder.Init();
}
public uint Decode(RangeCoder.Decoder rangeDecoder, uint posState)
{ public uint Decode(RangeCoder.Decoder rangeDecoder, uint posState)
if (m_Choice.Decode(rangeDecoder) == 0) {
return m_LowCoder[posState].Decode(rangeDecoder); if (m_Choice.Decode(rangeDecoder) == 0)
else {
{ return m_LowCoder[posState].Decode(rangeDecoder);
uint symbol = Base.kNumLowLenSymbols; }
if (m_Choice2.Decode(rangeDecoder) == 0) else
symbol += m_MidCoder[posState].Decode(rangeDecoder); {
else uint symbol = Base.kNumLowLenSymbols;
{ if (m_Choice2.Decode(rangeDecoder) == 0)
symbol += Base.kNumMidLenSymbols; {
symbol += m_HighCoder.Decode(rangeDecoder); symbol += m_MidCoder[posState].Decode(rangeDecoder);
} }
return symbol; else
} {
} symbol += Base.kNumMidLenSymbols;
} symbol += m_HighCoder.Decode(rangeDecoder);
}
class LiteralDecoder return symbol;
{ }
struct Decoder2 }
{ }
BitDecoder[] m_Decoders;
public void Create() { m_Decoders = new BitDecoder[0x300]; } private class LiteralDecoder
public void Init() { for (int i = 0; i < 0x300; i++) m_Decoders[i].Init(); } {
private struct Decoder2
public byte DecodeNormal(RangeCoder.Decoder rangeDecoder) {
{ private BitDecoder[] m_Decoders;
uint symbol = 1; public void Create() { m_Decoders = new BitDecoder[0x300]; }
do public void Init() { for (int i = 0; i < 0x300; i++)
symbol = (symbol << 1) | m_Decoders[symbol].Decode(rangeDecoder); {
while (symbol < 0x100); m_Decoders[i].Init();
return (byte)symbol; }
} }
public byte DecodeWithMatchByte(RangeCoder.Decoder rangeDecoder, byte matchByte) public byte DecodeNormal(RangeCoder.Decoder rangeDecoder)
{ {
uint symbol = 1; uint symbol = 1;
do do
{ {
uint matchBit = (uint)(matchByte >> 7) & 1; symbol = (symbol << 1) | m_Decoders[symbol].Decode(rangeDecoder);
matchByte <<= 1; }
uint bit = m_Decoders[((1 + matchBit) << 8) + symbol].Decode(rangeDecoder); while (symbol < 0x100);
symbol = (symbol << 1) | bit; return (byte)symbol;
if (matchBit != bit) }
{
while (symbol < 0x100) public byte DecodeWithMatchByte(RangeCoder.Decoder rangeDecoder, byte matchByte)
symbol = (symbol << 1) | m_Decoders[symbol].Decode(rangeDecoder); {
break; uint symbol = 1;
} do
} {
while (symbol < 0x100); uint matchBit = (uint)(matchByte >> 7) & 1;
return (byte)symbol; matchByte <<= 1;
} uint bit = m_Decoders[((1 + matchBit) << 8) + symbol].Decode(rangeDecoder);
} symbol = (symbol << 1) | bit;
if (matchBit != bit)
Decoder2[] m_Coders; {
int m_NumPrevBits; while (symbol < 0x100)
int m_NumPosBits; {
uint m_PosMask; symbol = (symbol << 1) | m_Decoders[symbol].Decode(rangeDecoder);
}
public void Create(int numPosBits, int numPrevBits)
{ break;
if (m_Coders != null && m_NumPrevBits == numPrevBits && }
m_NumPosBits == numPosBits) }
return; while (symbol < 0x100);
m_NumPosBits = numPosBits; return (byte)symbol;
m_PosMask = ((uint)1 << numPosBits) - 1; }
m_NumPrevBits = numPrevBits; }
uint numStates = (uint)1 << (m_NumPrevBits + m_NumPosBits);
m_Coders = new Decoder2[numStates]; private Decoder2[] m_Coders;
for (uint i = 0; i < numStates; i++) private int m_NumPrevBits;
m_Coders[i].Create(); private int m_NumPosBits;
} private uint m_PosMask;
public void Init() public void Create(int numPosBits, int numPrevBits)
{ {
uint numStates = (uint)1 << (m_NumPrevBits + m_NumPosBits); if (m_Coders != null && m_NumPrevBits == numPrevBits &&
for (uint i = 0; i < numStates; i++) m_NumPosBits == numPosBits)
m_Coders[i].Init(); {
} return;
}
uint GetState(uint pos, byte prevByte)
{ return ((pos & m_PosMask) << m_NumPrevBits) + (uint)(prevByte >> (8 - m_NumPrevBits)); } m_NumPosBits = numPosBits;
m_PosMask = ((uint)1 << numPosBits) - 1;
public byte DecodeNormal(RangeCoder.Decoder rangeDecoder, uint pos, byte prevByte) m_NumPrevBits = numPrevBits;
{ return m_Coders[GetState(pos, prevByte)].DecodeNormal(rangeDecoder); } uint numStates = (uint)1 << (m_NumPrevBits + m_NumPosBits);
m_Coders = new Decoder2[numStates];
public byte DecodeWithMatchByte(RangeCoder.Decoder rangeDecoder, uint pos, byte prevByte, byte matchByte) for (uint i = 0; i < numStates; i++)
{ return m_Coders[GetState(pos, prevByte)].DecodeWithMatchByte(rangeDecoder, matchByte); } {
}; m_Coders[i].Create();
}
LZ.OutWindow m_OutWindow = new LZ.OutWindow(); }
RangeCoder.Decoder m_RangeDecoder = new RangeCoder.Decoder();
public void Init()
BitDecoder[] m_IsMatchDecoders = new BitDecoder[Base.kNumStates << Base.kNumPosStatesBitsMax]; {
BitDecoder[] m_IsRepDecoders = new BitDecoder[Base.kNumStates]; uint numStates = (uint)1 << (m_NumPrevBits + m_NumPosBits);
BitDecoder[] m_IsRepG0Decoders = new BitDecoder[Base.kNumStates]; for (uint i = 0; i < numStates; i++)
BitDecoder[] m_IsRepG1Decoders = new BitDecoder[Base.kNumStates]; {
BitDecoder[] m_IsRepG2Decoders = new BitDecoder[Base.kNumStates]; m_Coders[i].Init();
BitDecoder[] m_IsRep0LongDecoders = new BitDecoder[Base.kNumStates << Base.kNumPosStatesBitsMax]; }
}
BitTreeDecoder[] m_PosSlotDecoder = new BitTreeDecoder[Base.kNumLenToPosStates];
BitDecoder[] m_PosDecoders = new BitDecoder[Base.kNumFullDistances - Base.kEndPosModelIndex]; private uint GetState(uint pos, byte prevByte)
{ return ((pos & m_PosMask) << m_NumPrevBits) + (uint)(prevByte >> (8 - m_NumPrevBits)); }
BitTreeDecoder m_PosAlignDecoder = new BitTreeDecoder(Base.kNumAlignBits);
public byte DecodeNormal(RangeCoder.Decoder rangeDecoder, uint pos, byte prevByte)
LenDecoder m_LenDecoder = new LenDecoder(); { return m_Coders[GetState(pos, prevByte)].DecodeNormal(rangeDecoder); }
LenDecoder m_RepLenDecoder = new LenDecoder();
public byte DecodeWithMatchByte(RangeCoder.Decoder rangeDecoder, uint pos, byte prevByte, byte matchByte)
LiteralDecoder m_LiteralDecoder = new LiteralDecoder(); { return m_Coders[GetState(pos, prevByte)].DecodeWithMatchByte(rangeDecoder, matchByte); }
};
uint m_DictionarySize;
uint m_DictionarySizeCheck; private readonly LZ.OutWindow m_OutWindow = new();
private readonly RangeCoder.Decoder m_RangeDecoder = new();
uint m_PosStateMask;
private readonly BitDecoder[] m_IsMatchDecoders = new BitDecoder[Base.kNumStates << Base.kNumPosStatesBitsMax];
public Decoder() private readonly BitDecoder[] m_IsRepDecoders = new BitDecoder[Base.kNumStates];
{ private readonly BitDecoder[] m_IsRepG0Decoders = new BitDecoder[Base.kNumStates];
m_DictionarySize = 0xFFFFFFFF; private readonly BitDecoder[] m_IsRepG1Decoders = new BitDecoder[Base.kNumStates];
for (int i = 0; i < Base.kNumLenToPosStates; i++) private readonly BitDecoder[] m_IsRepG2Decoders = new BitDecoder[Base.kNumStates];
m_PosSlotDecoder[i] = new BitTreeDecoder(Base.kNumPosSlotBits); private readonly BitDecoder[] m_IsRep0LongDecoders = new BitDecoder[Base.kNumStates << Base.kNumPosStatesBitsMax];
}
private readonly BitTreeDecoder[] m_PosSlotDecoder = new BitTreeDecoder[Base.kNumLenToPosStates];
void SetDictionarySize(uint dictionarySize) private readonly BitDecoder[] m_PosDecoders = new BitDecoder[Base.kNumFullDistances - Base.kEndPosModelIndex];
{
if (m_DictionarySize != dictionarySize) private readonly BitTreeDecoder m_PosAlignDecoder = new(Base.kNumAlignBits);
{
m_DictionarySize = dictionarySize; private readonly LenDecoder m_LenDecoder = new();
m_DictionarySizeCheck = Math.Max(m_DictionarySize, 1); private readonly LenDecoder m_RepLenDecoder = new();
uint blockSize = Math.Max(m_DictionarySizeCheck, (1 << 12));
m_OutWindow.Create(blockSize); private readonly LiteralDecoder m_LiteralDecoder = new();
}
} private uint m_DictionarySize;
private uint m_DictionarySizeCheck;
void SetLiteralProperties(int lp, int lc)
{ private uint m_PosStateMask;
if (lp > 8)
throw new InvalidParamException(); public Decoder()
if (lc > 8) {
throw new InvalidParamException(); m_DictionarySize = 0xFFFFFFFF;
m_LiteralDecoder.Create(lp, lc); for (int i = 0; i < Base.kNumLenToPosStates; i++)
} {
m_PosSlotDecoder[i] = new BitTreeDecoder(Base.kNumPosSlotBits);
void SetPosBitsProperties(int pb) }
{ }
if (pb > Base.kNumPosStatesBitsMax)
throw new InvalidParamException(); private void SetDictionarySize(uint dictionarySize)
uint numPosStates = (uint)1 << pb; {
m_LenDecoder.Create(numPosStates); if (m_DictionarySize != dictionarySize)
m_RepLenDecoder.Create(numPosStates); {
m_PosStateMask = numPosStates - 1; m_DictionarySize = dictionarySize;
} m_DictionarySizeCheck = Math.Max(m_DictionarySize, 1);
uint blockSize = Math.Max(m_DictionarySizeCheck, 1 << 12);
bool _solid = false; m_OutWindow.Create(blockSize);
void Init(System.IO.Stream inStream, System.IO.Stream outStream) }
{ }
m_RangeDecoder.Init(inStream);
m_OutWindow.Init(outStream, _solid); private void SetLiteralProperties(int lp, int lc)
{
uint i; if (lp > 8)
for (i = 0; i < Base.kNumStates; i++) {
{ throw new InvalidParamException();
for (uint j = 0; j <= m_PosStateMask; j++) }
{
uint index = (i << Base.kNumPosStatesBitsMax) + j; if (lc > 8)
m_IsMatchDecoders[index].Init(); {
m_IsRep0LongDecoders[index].Init(); throw new InvalidParamException();
} }
m_IsRepDecoders[i].Init();
m_IsRepG0Decoders[i].Init(); m_LiteralDecoder.Create(lp, lc);
m_IsRepG1Decoders[i].Init(); }
m_IsRepG2Decoders[i].Init();
} private void SetPosBitsProperties(int pb)
{
m_LiteralDecoder.Init(); if (pb > Base.kNumPosStatesBitsMax)
for (i = 0; i < Base.kNumLenToPosStates; i++) {
m_PosSlotDecoder[i].Init(); throw new InvalidParamException();
// m_PosSpecDecoder.Init(); }
for (i = 0; i < Base.kNumFullDistances - Base.kEndPosModelIndex; i++)
m_PosDecoders[i].Init(); uint numPosStates = (uint)1 << pb;
m_LenDecoder.Create(numPosStates);
m_LenDecoder.Init(); m_RepLenDecoder.Create(numPosStates);
m_RepLenDecoder.Init(); m_PosStateMask = numPosStates - 1;
m_PosAlignDecoder.Init(); }
}
private bool _solid = false;
public void Code(System.IO.Stream inStream, System.IO.Stream outStream, private void Init(System.IO.Stream inStream, System.IO.Stream outStream)
Int64 inSize, Int64 outSize, ICodeProgress progress) {
{ m_RangeDecoder.Init(inStream);
Init(inStream, outStream); m_OutWindow.Init(outStream, _solid);
Base.State state = new Base.State(); uint i;
state.Init(); for (i = 0; i < Base.kNumStates; i++)
uint rep0 = 0, rep1 = 0, rep2 = 0, rep3 = 0; {
for (uint j = 0; j <= m_PosStateMask; j++)
UInt64 nowPos64 = 0; {
UInt64 outSize64 = (UInt64)outSize; uint index = (i << Base.kNumPosStatesBitsMax) + j;
if (nowPos64 < outSize64) m_IsMatchDecoders[index].Init();
{ m_IsRep0LongDecoders[index].Init();
if (m_IsMatchDecoders[state.Index << Base.kNumPosStatesBitsMax].Decode(m_RangeDecoder) != 0) }
throw new DataErrorException(); m_IsRepDecoders[i].Init();
state.UpdateChar(); m_IsRepG0Decoders[i].Init();
byte b = m_LiteralDecoder.DecodeNormal(m_RangeDecoder, 0, 0); m_IsRepG1Decoders[i].Init();
m_OutWindow.PutByte(b); m_IsRepG2Decoders[i].Init();
nowPos64++; }
}
while (nowPos64 < outSize64) m_LiteralDecoder.Init();
{ for (i = 0; i < Base.kNumLenToPosStates; i++)
// UInt64 next = Math.Min(nowPos64 + (1 << 18), outSize64); {
// while(nowPos64 < next) m_PosSlotDecoder[i].Init();
{ }
uint posState = (uint)nowPos64 & m_PosStateMask; // m_PosSpecDecoder.Init();
if (m_IsMatchDecoders[(state.Index << Base.kNumPosStatesBitsMax) + posState].Decode(m_RangeDecoder) == 0) for (i = 0; i < Base.kNumFullDistances - Base.kEndPosModelIndex; i++)
{ {
byte b; m_PosDecoders[i].Init();
byte prevByte = m_OutWindow.GetByte(0); }
if (!state.IsCharState())
b = m_LiteralDecoder.DecodeWithMatchByte(m_RangeDecoder, m_LenDecoder.Init();
(uint)nowPos64, prevByte, m_OutWindow.GetByte(rep0)); m_RepLenDecoder.Init();
else m_PosAlignDecoder.Init();
b = m_LiteralDecoder.DecodeNormal(m_RangeDecoder, (uint)nowPos64, prevByte); }
m_OutWindow.PutByte(b);
state.UpdateChar(); public void Code(System.IO.Stream inStream, System.IO.Stream outStream,
nowPos64++; Int64 inSize, Int64 outSize, ICodeProgress progress, CancellationToken? token = null)
} {
else Init(inStream, outStream);
{
uint len; Base.State state = new();
if (m_IsRepDecoders[state.Index].Decode(m_RangeDecoder) == 1) state.Init();
{ uint rep0 = 0, rep1 = 0, rep2 = 0, rep3 = 0;
if (m_IsRepG0Decoders[state.Index].Decode(m_RangeDecoder) == 0)
{ UInt64 nowPos64 = 0;
if (m_IsRep0LongDecoders[(state.Index << Base.kNumPosStatesBitsMax) + posState].Decode(m_RangeDecoder) == 0) UInt64 outSize64 = (UInt64)outSize;
{ if (nowPos64 < outSize64)
state.UpdateShortRep(); {
m_OutWindow.PutByte(m_OutWindow.GetByte(rep0)); if (m_IsMatchDecoders[state.Index << Base.kNumPosStatesBitsMax].Decode(m_RangeDecoder) != 0)
nowPos64++; {
continue; throw new DataErrorException();
} }
}
else state.UpdateChar();
{ byte b = m_LiteralDecoder.DecodeNormal(m_RangeDecoder, 0, 0);
UInt32 distance; m_OutWindow.PutByte(b);
if (m_IsRepG1Decoders[state.Index].Decode(m_RangeDecoder) == 0) nowPos64++;
{ }
distance = rep1;
} try
else {
{ while (nowPos64 < outSize64)
if (m_IsRepG2Decoders[state.Index].Decode(m_RangeDecoder) == 0) {
distance = rep2; token?.ThrowIfCancellationRequested();
else
{ // UInt64 next = Math.Min(nowPos64 + (1 << 18), outSize64);
distance = rep3; // while(nowPos64 < next)
rep3 = rep2; {
} uint posState = (uint)nowPos64 & m_PosStateMask;
rep2 = rep1; if (m_IsMatchDecoders[(state.Index << Base.kNumPosStatesBitsMax) + posState].Decode(m_RangeDecoder) == 0)
} {
rep1 = rep0; byte b;
rep0 = distance; byte prevByte = m_OutWindow.GetByte(0);
} b = !state.IsCharState()
len = m_RepLenDecoder.Decode(m_RangeDecoder, posState) + Base.kMatchMinLen; ? m_LiteralDecoder.DecodeWithMatchByte(m_RangeDecoder,
state.UpdateRep(); (uint)nowPos64, prevByte, m_OutWindow.GetByte(rep0))
} : m_LiteralDecoder.DecodeNormal(m_RangeDecoder, (uint)nowPos64, prevByte);
else
{ m_OutWindow.PutByte(b);
rep3 = rep2; state.UpdateChar();
rep2 = rep1; nowPos64++;
rep1 = rep0; }
len = Base.kMatchMinLen + m_LenDecoder.Decode(m_RangeDecoder, posState); else
state.UpdateMatch(); {
uint posSlot = m_PosSlotDecoder[Base.GetLenToPosState(len)].Decode(m_RangeDecoder); uint len;
if (posSlot >= Base.kStartPosModelIndex) if (m_IsRepDecoders[state.Index].Decode(m_RangeDecoder) == 1)
{ {
int numDirectBits = (int)((posSlot >> 1) - 1); if (m_IsRepG0Decoders[state.Index].Decode(m_RangeDecoder) == 0)
rep0 = ((2 | (posSlot & 1)) << numDirectBits); {
if (posSlot < Base.kEndPosModelIndex) if (m_IsRep0LongDecoders[(state.Index << Base.kNumPosStatesBitsMax) + posState].Decode(m_RangeDecoder) == 0)
rep0 += BitTreeDecoder.ReverseDecode(m_PosDecoders, {
rep0 - posSlot - 1, m_RangeDecoder, numDirectBits); state.UpdateShortRep();
else m_OutWindow.PutByte(m_OutWindow.GetByte(rep0));
{ nowPos64++;
rep0 += (m_RangeDecoder.DecodeDirectBits( continue;
numDirectBits - Base.kNumAlignBits) << Base.kNumAlignBits); }
rep0 += m_PosAlignDecoder.ReverseDecode(m_RangeDecoder); }
} else
} {
else UInt32 distance;
rep0 = posSlot; if (m_IsRepG1Decoders[state.Index].Decode(m_RangeDecoder) == 0)
} {
if (rep0 >= m_OutWindow.TrainSize + nowPos64 || rep0 >= m_DictionarySizeCheck) distance = rep1;
{ }
if (rep0 == 0xFFFFFFFF) else
break; {
throw new DataErrorException(); if (m_IsRepG2Decoders[state.Index].Decode(m_RangeDecoder) == 0)
} {
m_OutWindow.CopyBlock(rep0, len); distance = rep2;
nowPos64 += len; }
} else
} {
} distance = rep3;
m_OutWindow.Flush(); rep3 = rep2;
m_OutWindow.ReleaseStream(); }
m_RangeDecoder.ReleaseStream(); rep2 = rep1;
} }
rep1 = rep0;
public void SetDecoderProperties(byte[] properties) rep0 = distance;
{ }
if (properties.Length < 5) len = m_RepLenDecoder.Decode(m_RangeDecoder, posState) + Base.kMatchMinLen;
throw new InvalidParamException(); state.UpdateRep();
int lc = properties[0] % 9; }
int remainder = properties[0] / 9; else
int lp = remainder % 5; {
int pb = remainder / 5; rep3 = rep2;
if (pb > Base.kNumPosStatesBitsMax) rep2 = rep1;
throw new InvalidParamException(); rep1 = rep0;
UInt32 dictionarySize = 0; len = Base.kMatchMinLen + m_LenDecoder.Decode(m_RangeDecoder, posState);
for (int i = 0; i < 4; i++) state.UpdateMatch();
dictionarySize += ((UInt32)(properties[1 + i])) << (i * 8); uint posSlot = m_PosSlotDecoder[Base.GetLenToPosState(len)].Decode(m_RangeDecoder);
SetDictionarySize(dictionarySize); if (posSlot >= Base.kStartPosModelIndex)
SetLiteralProperties(lp, lc); {
SetPosBitsProperties(pb); int numDirectBits = (int)((posSlot >> 1) - 1);
} rep0 = (2 | (posSlot & 1)) << numDirectBits;
if (posSlot < Base.kEndPosModelIndex)
public bool Train(System.IO.Stream stream) {
{ rep0 += BitTreeDecoder.ReverseDecode(m_PosDecoders,
_solid = true; rep0 - posSlot - 1, m_RangeDecoder, numDirectBits);
return m_OutWindow.Train(stream); }
} else
{
/* rep0 += m_RangeDecoder.DecodeDirectBits(
public override bool CanRead { get { return true; }} numDirectBits - Base.kNumAlignBits) << Base.kNumAlignBits;
public override bool CanWrite { get { return true; }} rep0 += m_PosAlignDecoder.ReverseDecode(m_RangeDecoder);
public override bool CanSeek { get { return true; }} }
public override long Length { get { return 0; }} }
public override long Position else
{ {
get { return 0; } rep0 = posSlot;
set { } }
} }
public override void Flush() { } if (rep0 >= m_OutWindow.TrainSize + nowPos64 || rep0 >= m_DictionarySizeCheck)
public override int Read(byte[] buffer, int offset, int count) {
{ if (rep0 == 0xFFFFFFFF)
return 0; {
} break;
public override void Write(byte[] buffer, int offset, int count) }
{
} throw new DataErrorException();
public override long Seek(long offset, System.IO.SeekOrigin origin) }
{ m_OutWindow.CopyBlock(rep0, len);
return 0; nowPos64 += len;
} }
public override void SetLength(long value) {} }
*/ }
} }
} catch (OperationCanceledException)
{
}
m_OutWindow.Flush();
m_OutWindow.ReleaseStream();
m_RangeDecoder.ReleaseStream();
}
public void SetDecoderProperties(byte[] properties)
{
if (properties.Length < 5)
{
throw new InvalidParamException();
}
int lc = properties[0] % 9;
int remainder = properties[0] / 9;
int lp = remainder % 5;
int pb = remainder / 5;
if (pb > Base.kNumPosStatesBitsMax)
{
throw new InvalidParamException();
}
UInt32 dictionarySize = 0;
for (int i = 0; i < 4; i++)
{
dictionarySize += ((UInt32)properties[1 + i]) << (i * 8);
}
SetDictionarySize(dictionarySize);
SetLiteralProperties(lp, lc);
SetPosBitsProperties(pb);
}
public bool Train(System.IO.Stream stream)
{
_solid = true;
return m_OutWindow.Train(stream);
}
/*
public override bool CanRead { get { return true; }}
public override bool CanWrite { get { return true; }}
public override bool CanSeek { get { return true; }}
public override long Length { get { return 0; }}
public override long Position
{
get { return 0; }
set { }
}
public override void Flush() { }
public override int Read(byte[] buffer, int offset, int count)
{
return 0;
}
public override void Write(byte[] buffer, int offset, int count)
{
}
public override long Seek(long offset, System.IO.SeekOrigin origin)
{
return 0;
}
public override void SetLength(long value) {}
*/
}
}
File diff suppressed because it is too large Load Diff
+243 -234
View File
@@ -1,234 +1,243 @@
using System; using System;
namespace SevenZip.Compression.RangeCoder namespace SevenZip.Compression.RangeCoder
{ {
class Encoder internal class Encoder
{ {
public const uint kTopValue = (1 << 24); public const uint kTopValue = 1 << 24;
System.IO.Stream Stream; private System.IO.Stream Stream;
public UInt64 Low; public UInt64 Low;
public uint Range; public uint Range;
uint _cacheSize; private uint _cacheSize;
byte _cache; private byte _cache;
long StartPosition; private long StartPosition;
public void SetStream(System.IO.Stream stream) public void SetStream(System.IO.Stream stream)
{ {
Stream = stream; Stream = stream;
} }
public void ReleaseStream() public void ReleaseStream()
{ {
Stream = null; Stream = null;
} }
public void Init() public void Init()
{ {
StartPosition = Stream.Position; StartPosition = Stream.Position;
Low = 0; Low = 0;
Range = 0xFFFFFFFF; Range = 0xFFFFFFFF;
_cacheSize = 1; _cacheSize = 1;
_cache = 0; _cache = 0;
} }
public void FlushData() public void FlushData()
{ {
for (int i = 0; i < 5; i++) for (int i = 0; i < 5; i++)
ShiftLow(); {
} ShiftLow();
}
public void FlushStream() }
{
Stream.Flush(); public void FlushStream()
} {
Stream.Flush();
public void CloseStream() }
{
Stream.Close(); public void CloseStream()
} {
Stream.Close();
public void Encode(uint start, uint size, uint total) }
{
Low += start * (Range /= total); public void Encode(uint start, uint size, uint total)
Range *= size; {
while (Range < kTopValue) Low += start * (Range /= total);
{ Range *= size;
Range <<= 8; while (Range < kTopValue)
ShiftLow(); {
} Range <<= 8;
} ShiftLow();
}
public void ShiftLow() }
{
if ((uint)Low < (uint)0xFF000000 || (uint)(Low >> 32) == 1) public void ShiftLow()
{ {
byte temp = _cache; if ((uint)Low < 0xFF000000 || (uint)(Low >> 32) == 1)
do {
{ byte temp = _cache;
Stream.WriteByte((byte)(temp + (Low >> 32))); do
temp = 0xFF; {
} Stream.WriteByte((byte)(temp + (Low >> 32)));
while (--_cacheSize != 0); temp = 0xFF;
_cache = (byte)(((uint)Low) >> 24); }
} while (--_cacheSize != 0);
_cacheSize++; _cache = (byte)(((uint)Low) >> 24);
Low = ((uint)Low) << 8; }
} _cacheSize++;
Low = ((uint)Low) << 8;
public void EncodeDirectBits(uint v, int numTotalBits) }
{
for (int i = numTotalBits - 1; i >= 0; i--) public void EncodeDirectBits(uint v, int numTotalBits)
{ {
Range >>= 1; for (int i = numTotalBits - 1; i >= 0; i--)
if (((v >> i) & 1) == 1) {
Low += Range; Range >>= 1;
if (Range < kTopValue) if (((v >> i) & 1) == 1)
{ {
Range <<= 8; Low += Range;
ShiftLow(); }
}
} if (Range < kTopValue)
} {
Range <<= 8;
public void EncodeBit(uint size0, int numTotalBits, uint symbol) ShiftLow();
{ }
uint newBound = (Range >> numTotalBits) * size0; }
if (symbol == 0) }
Range = newBound;
else public void EncodeBit(uint size0, int numTotalBits, uint symbol)
{ {
Low += newBound; uint newBound = (Range >> numTotalBits) * size0;
Range -= newBound; if (symbol == 0)
} {
while (Range < kTopValue) Range = newBound;
{ }
Range <<= 8; else
ShiftLow(); {
} Low += newBound;
} Range -= newBound;
}
public long GetProcessedSizeAdd() while (Range < kTopValue)
{ {
return _cacheSize + Range <<= 8;
Stream.Position - StartPosition + 4; ShiftLow();
// (long)Stream.GetProcessedSize(); }
} }
}
public long GetProcessedSizeAdd()
class Decoder {
{ return _cacheSize +
public const uint kTopValue = (1 << 24); Stream.Position - StartPosition + 4;
public uint Range; // (long)Stream.GetProcessedSize();
public uint Code; }
// public Buffer.InBuffer Stream = new Buffer.InBuffer(1 << 16); }
public System.IO.Stream Stream;
internal class Decoder
public void Init(System.IO.Stream stream) {
{ public const uint kTopValue = 1 << 24;
// Stream.Init(stream); public uint Range;
Stream = stream; public uint Code;
// public Buffer.InBuffer Stream = new Buffer.InBuffer(1 << 16);
Code = 0; public System.IO.Stream Stream;
Range = 0xFFFFFFFF;
for (int i = 0; i < 5; i++) public void Init(System.IO.Stream stream)
Code = (Code << 8) | (byte)Stream.ReadByte(); {
} // Stream.Init(stream);
Stream = stream;
public void ReleaseStream()
{ Code = 0;
// Stream.ReleaseStream(); Range = 0xFFFFFFFF;
Stream = null; for (int i = 0; i < 5; i++)
} {
Code = (Code << 8) | (byte)Stream.ReadByte();
public void CloseStream() }
{ }
Stream.Close();
} public void ReleaseStream()
{
public void Normalize() // Stream.ReleaseStream();
{ Stream = null;
while (Range < kTopValue) }
{
Code = (Code << 8) | (byte)Stream.ReadByte(); public void CloseStream()
Range <<= 8; {
} Stream.Close();
} }
public void Normalize2() public void Normalize()
{ {
if (Range < kTopValue) while (Range < kTopValue)
{ {
Code = (Code << 8) | (byte)Stream.ReadByte(); Code = (Code << 8) | (byte)Stream.ReadByte();
Range <<= 8; Range <<= 8;
} }
} }
public uint GetThreshold(uint total) public void Normalize2()
{ {
return Code / (Range /= total); if (Range < kTopValue)
} {
Code = (Code << 8) | (byte)Stream.ReadByte();
public void Decode(uint start, uint size, uint total) Range <<= 8;
{ }
Code -= start * Range; }
Range *= size;
Normalize(); public uint GetThreshold(uint total)
} {
return Code / (Range /= total);
public uint DecodeDirectBits(int numTotalBits) }
{
uint range = Range; public void Decode(uint start, uint size, uint total)
uint code = Code; {
uint result = 0; Code -= start * Range;
for (int i = numTotalBits; i > 0; i--) Range *= size;
{ Normalize();
range >>= 1; }
/*
result <<= 1; public uint DecodeDirectBits(int numTotalBits)
if (code >= range) {
{ uint range = Range;
code -= range; uint code = Code;
result |= 1; uint result = 0;
} for (int i = numTotalBits; i > 0; i--)
*/ {
uint t = (code - range) >> 31; range >>= 1;
code -= range & (t - 1); /*
result = (result << 1) | (1 - t); result <<= 1;
if (code >= range)
if (range < kTopValue) {
{ code -= range;
code = (code << 8) | (byte)Stream.ReadByte(); result |= 1;
range <<= 8; }
} */
} uint t = (code - range) >> 31;
Range = range; code -= range & (t - 1);
Code = code; result = (result << 1) | (1 - t);
return result;
} if (range < kTopValue)
{
public uint DecodeBit(uint size0, int numTotalBits) code = (code << 8) | (byte)Stream.ReadByte();
{ range <<= 8;
uint newBound = (Range >> numTotalBits) * size0; }
uint symbol; }
if (Code < newBound) Range = range;
{ Code = code;
symbol = 0; return result;
Range = newBound; }
}
else public uint DecodeBit(uint size0, int numTotalBits)
{ {
symbol = 1; uint newBound = (Range >> numTotalBits) * size0;
Code -= newBound; uint symbol;
Range -= newBound; if (Code < newBound)
} {
Normalize(); symbol = 0;
return symbol; Range = newBound;
} }
else
// ulong GetProcessedSize() {return Stream.GetProcessedSize(); } {
} symbol = 1;
} Code -= newBound;
Range -= newBound;
}
Normalize();
return symbol;
}
// ulong GetProcessedSize() {return Stream.GetProcessedSize(); }
}
}
+127 -117
View File
@@ -1,117 +1,127 @@
using System; using System;
namespace SevenZip.Compression.RangeCoder namespace SevenZip.Compression.RangeCoder
{ {
struct BitEncoder internal struct BitEncoder
{ {
public const int kNumBitModelTotalBits = 11; public const int kNumBitModelTotalBits = 11;
public const uint kBitModelTotal = (1 << kNumBitModelTotalBits); public const uint kBitModelTotal = 1 << kNumBitModelTotalBits;
const int kNumMoveBits = 5; private const int kNumMoveBits = 5;
const int kNumMoveReducingBits = 2; private const int kNumMoveReducingBits = 2;
public const int kNumBitPriceShiftBits = 6; public const int kNumBitPriceShiftBits = 6;
uint Prob; private uint Prob;
public void Init() { Prob = kBitModelTotal >> 1; } public void Init() { Prob = kBitModelTotal >> 1; }
public void UpdateModel(uint symbol) public void UpdateModel(uint symbol)
{ {
if (symbol == 0) if (symbol == 0)
Prob += (kBitModelTotal - Prob) >> kNumMoveBits; {
else Prob += (kBitModelTotal - Prob) >> kNumMoveBits;
Prob -= (Prob) >> kNumMoveBits; }
} else
{
public void Encode(Encoder encoder, uint symbol) Prob -= Prob >> kNumMoveBits;
{ }
// encoder.EncodeBit(Prob, kNumBitModelTotalBits, symbol); }
// UpdateModel(symbol);
uint newBound = (encoder.Range >> kNumBitModelTotalBits) * Prob; public void Encode(Encoder encoder, uint symbol)
if (symbol == 0) {
{ // encoder.EncodeBit(Prob, kNumBitModelTotalBits, symbol);
encoder.Range = newBound; // UpdateModel(symbol);
Prob += (kBitModelTotal - Prob) >> kNumMoveBits; uint newBound = (encoder.Range >> kNumBitModelTotalBits) * Prob;
} if (symbol == 0)
else {
{ encoder.Range = newBound;
encoder.Low += newBound; Prob += (kBitModelTotal - Prob) >> kNumMoveBits;
encoder.Range -= newBound; }
Prob -= (Prob) >> kNumMoveBits; else
} {
if (encoder.Range < Encoder.kTopValue) encoder.Low += newBound;
{ encoder.Range -= newBound;
encoder.Range <<= 8; Prob -= Prob >> kNumMoveBits;
encoder.ShiftLow(); }
} if (encoder.Range < Encoder.kTopValue)
} {
encoder.Range <<= 8;
private static UInt32[] ProbPrices = new UInt32[kBitModelTotal >> kNumMoveReducingBits]; encoder.ShiftLow();
}
static BitEncoder() }
{
const int kNumBits = (kNumBitModelTotalBits - kNumMoveReducingBits); private static readonly UInt32[] ProbPrices = new UInt32[kBitModelTotal >> kNumMoveReducingBits];
for (int i = kNumBits - 1; i >= 0; i--)
{ static BitEncoder()
UInt32 start = (UInt32)1 << (kNumBits - i - 1); {
UInt32 end = (UInt32)1 << (kNumBits - i); const int kNumBits = kNumBitModelTotalBits - kNumMoveReducingBits;
for (UInt32 j = start; j < end; j++) for (int i = kNumBits - 1; i >= 0; i--)
ProbPrices[j] = ((UInt32)i << kNumBitPriceShiftBits) + {
(((end - j) << kNumBitPriceShiftBits) >> (kNumBits - i - 1)); UInt32 start = (UInt32)1 << (kNumBits - i - 1);
} UInt32 end = (UInt32)1 << (kNumBits - i);
} for (UInt32 j = start; j < end; j++)
{
public uint GetPrice(uint symbol) ProbPrices[j] = ((UInt32)i << kNumBitPriceShiftBits) +
{ (((end - j) << kNumBitPriceShiftBits) >> (kNumBits - i - 1));
return ProbPrices[(((Prob - symbol) ^ ((-(int)symbol))) & (kBitModelTotal - 1)) >> kNumMoveReducingBits]; }
} }
public uint GetPrice0() { return ProbPrices[Prob >> kNumMoveReducingBits]; } }
public uint GetPrice1() { return ProbPrices[(kBitModelTotal - Prob) >> kNumMoveReducingBits]; }
} public uint GetPrice(uint symbol)
{
struct BitDecoder return ProbPrices[(((Prob - symbol) ^ (-(int)symbol)) & (kBitModelTotal - 1)) >> kNumMoveReducingBits];
{ }
public const int kNumBitModelTotalBits = 11; public uint GetPrice0() { return ProbPrices[Prob >> kNumMoveReducingBits]; }
public const uint kBitModelTotal = (1 << kNumBitModelTotalBits); public uint GetPrice1() { return ProbPrices[(kBitModelTotal - Prob) >> kNumMoveReducingBits]; }
const int kNumMoveBits = 5; }
uint Prob; internal struct BitDecoder
{
public void UpdateModel(int numMoveBits, uint symbol) public const int kNumBitModelTotalBits = 11;
{ public const uint kBitModelTotal = 1 << kNumBitModelTotalBits;
if (symbol == 0) private const int kNumMoveBits = 5;
Prob += (kBitModelTotal - Prob) >> numMoveBits;
else private uint Prob;
Prob -= (Prob) >> numMoveBits;
} public void UpdateModel(int numMoveBits, uint symbol)
{
public void Init() { Prob = kBitModelTotal >> 1; } if (symbol == 0)
{
public uint Decode(RangeCoder.Decoder rangeDecoder) Prob += (kBitModelTotal - Prob) >> numMoveBits;
{ }
uint newBound = (uint)(rangeDecoder.Range >> kNumBitModelTotalBits) * (uint)Prob; else
if (rangeDecoder.Code < newBound) {
{ Prob -= Prob >> numMoveBits;
rangeDecoder.Range = newBound; }
Prob += (kBitModelTotal - Prob) >> kNumMoveBits; }
if (rangeDecoder.Range < Decoder.kTopValue)
{ public void Init() { Prob = kBitModelTotal >> 1; }
rangeDecoder.Code = (rangeDecoder.Code << 8) | (byte)rangeDecoder.Stream.ReadByte();
rangeDecoder.Range <<= 8; public uint Decode(Decoder rangeDecoder)
} {
return 0; uint newBound = (rangeDecoder.Range >> kNumBitModelTotalBits) * Prob;
} if (rangeDecoder.Code < newBound)
else {
{ rangeDecoder.Range = newBound;
rangeDecoder.Range -= newBound; Prob += (kBitModelTotal - Prob) >> kNumMoveBits;
rangeDecoder.Code -= newBound; if (rangeDecoder.Range < Decoder.kTopValue)
Prob -= (Prob) >> kNumMoveBits; {
if (rangeDecoder.Range < Decoder.kTopValue) rangeDecoder.Code = (rangeDecoder.Code << 8) | (byte)rangeDecoder.Stream.ReadByte();
{ rangeDecoder.Range <<= 8;
rangeDecoder.Code = (rangeDecoder.Code << 8) | (byte)rangeDecoder.Stream.ReadByte(); }
rangeDecoder.Range <<= 8; return 0;
} }
return 1; else
} {
} rangeDecoder.Range -= newBound;
} rangeDecoder.Code -= newBound;
} Prob -= Prob >> kNumMoveBits;
if (rangeDecoder.Range < Decoder.kTopValue)
{
rangeDecoder.Code = (rangeDecoder.Code << 8) | (byte)rangeDecoder.Stream.ReadByte();
rangeDecoder.Range <<= 8;
}
return 1;
}
}
}
}
+164 -157
View File
@@ -1,157 +1,164 @@
using System; using System;
namespace SevenZip.Compression.RangeCoder namespace SevenZip.Compression.RangeCoder
{ {
struct BitTreeEncoder internal struct BitTreeEncoder
{ {
BitEncoder[] Models; private readonly BitEncoder[] Models;
int NumBitLevels; private readonly int NumBitLevels;
public BitTreeEncoder(int numBitLevels) public BitTreeEncoder(int numBitLevels)
{ {
NumBitLevels = numBitLevels; NumBitLevels = numBitLevels;
Models = new BitEncoder[1 << numBitLevels]; Models = new BitEncoder[1 << numBitLevels];
} }
public void Init() public void Init()
{ {
for (uint i = 1; i < (1 << NumBitLevels); i++) for (uint i = 1; i < (1 << NumBitLevels); i++)
Models[i].Init(); {
} Models[i].Init();
}
public void Encode(Encoder rangeEncoder, UInt32 symbol) }
{
UInt32 m = 1; public void Encode(Encoder rangeEncoder, UInt32 symbol)
for (int bitIndex = NumBitLevels; bitIndex > 0; ) {
{ UInt32 m = 1;
bitIndex--; for (int bitIndex = NumBitLevels; bitIndex > 0;)
UInt32 bit = (symbol >> bitIndex) & 1; {
Models[m].Encode(rangeEncoder, bit); bitIndex--;
m = (m << 1) | bit; UInt32 bit = (symbol >> bitIndex) & 1;
} Models[m].Encode(rangeEncoder, bit);
} m = (m << 1) | bit;
}
public void ReverseEncode(Encoder rangeEncoder, UInt32 symbol) }
{
UInt32 m = 1; public void ReverseEncode(Encoder rangeEncoder, UInt32 symbol)
for (UInt32 i = 0; i < NumBitLevels; i++) {
{ UInt32 m = 1;
UInt32 bit = symbol & 1; for (UInt32 i = 0; i < NumBitLevels; i++)
Models[m].Encode(rangeEncoder, bit); {
m = (m << 1) | bit; UInt32 bit = symbol & 1;
symbol >>= 1; Models[m].Encode(rangeEncoder, bit);
} m = (m << 1) | bit;
} symbol >>= 1;
}
public UInt32 GetPrice(UInt32 symbol) }
{
UInt32 price = 0; public UInt32 GetPrice(UInt32 symbol)
UInt32 m = 1; {
for (int bitIndex = NumBitLevels; bitIndex > 0; ) UInt32 price = 0;
{ UInt32 m = 1;
bitIndex--; for (int bitIndex = NumBitLevels; bitIndex > 0;)
UInt32 bit = (symbol >> bitIndex) & 1; {
price += Models[m].GetPrice(bit); bitIndex--;
m = (m << 1) + bit; UInt32 bit = (symbol >> bitIndex) & 1;
} price += Models[m].GetPrice(bit);
return price; m = (m << 1) + bit;
} }
return price;
public UInt32 ReverseGetPrice(UInt32 symbol) }
{
UInt32 price = 0; public UInt32 ReverseGetPrice(UInt32 symbol)
UInt32 m = 1; {
for (int i = NumBitLevels; i > 0; i--) UInt32 price = 0;
{ UInt32 m = 1;
UInt32 bit = symbol & 1; for (int i = NumBitLevels; i > 0; i--)
symbol >>= 1; {
price += Models[m].GetPrice(bit); UInt32 bit = symbol & 1;
m = (m << 1) | bit; symbol >>= 1;
} price += Models[m].GetPrice(bit);
return price; m = (m << 1) | bit;
} }
return price;
public static UInt32 ReverseGetPrice(BitEncoder[] Models, UInt32 startIndex, }
int NumBitLevels, UInt32 symbol)
{ public static UInt32 ReverseGetPrice(BitEncoder[] Models, UInt32 startIndex,
UInt32 price = 0; int NumBitLevels, UInt32 symbol)
UInt32 m = 1; {
for (int i = NumBitLevels; i > 0; i--) UInt32 price = 0;
{ UInt32 m = 1;
UInt32 bit = symbol & 1; for (int i = NumBitLevels; i > 0; i--)
symbol >>= 1; {
price += Models[startIndex + m].GetPrice(bit); UInt32 bit = symbol & 1;
m = (m << 1) | bit; symbol >>= 1;
} price += Models[startIndex + m].GetPrice(bit);
return price; m = (m << 1) | bit;
} }
return price;
public static void ReverseEncode(BitEncoder[] Models, UInt32 startIndex, }
Encoder rangeEncoder, int NumBitLevels, UInt32 symbol)
{ public static void ReverseEncode(BitEncoder[] Models, UInt32 startIndex,
UInt32 m = 1; Encoder rangeEncoder, int NumBitLevels, UInt32 symbol)
for (int i = 0; i < NumBitLevels; i++) {
{ UInt32 m = 1;
UInt32 bit = symbol & 1; for (int i = 0; i < NumBitLevels; i++)
Models[startIndex + m].Encode(rangeEncoder, bit); {
m = (m << 1) | bit; UInt32 bit = symbol & 1;
symbol >>= 1; Models[startIndex + m].Encode(rangeEncoder, bit);
} m = (m << 1) | bit;
} symbol >>= 1;
} }
}
struct BitTreeDecoder }
{
BitDecoder[] Models; internal struct BitTreeDecoder
int NumBitLevels; {
private readonly BitDecoder[] Models;
public BitTreeDecoder(int numBitLevels) private readonly int NumBitLevels;
{
NumBitLevels = numBitLevels; public BitTreeDecoder(int numBitLevels)
Models = new BitDecoder[1 << numBitLevels]; {
} NumBitLevels = numBitLevels;
Models = new BitDecoder[1 << numBitLevels];
public void Init() }
{
for (uint i = 1; i < (1 << NumBitLevels); i++) public void Init()
Models[i].Init(); {
} for (uint i = 1; i < (1 << NumBitLevels); i++)
{
public uint Decode(RangeCoder.Decoder rangeDecoder) Models[i].Init();
{ }
uint m = 1; }
for (int bitIndex = NumBitLevels; bitIndex > 0; bitIndex--)
m = (m << 1) + Models[m].Decode(rangeDecoder); public uint Decode(Decoder rangeDecoder)
return m - ((uint)1 << NumBitLevels); {
} uint m = 1;
for (int bitIndex = NumBitLevels; bitIndex > 0; bitIndex--)
public uint ReverseDecode(RangeCoder.Decoder rangeDecoder) {
{ m = (m << 1) + Models[m].Decode(rangeDecoder);
uint m = 1; }
uint symbol = 0;
for (int bitIndex = 0; bitIndex < NumBitLevels; bitIndex++) return m - ((uint)1 << NumBitLevels);
{ }
uint bit = Models[m].Decode(rangeDecoder);
m <<= 1; public uint ReverseDecode(Decoder rangeDecoder)
m += bit; {
symbol |= (bit << bitIndex); uint m = 1;
} uint symbol = 0;
return symbol; for (int bitIndex = 0; bitIndex < NumBitLevels; bitIndex++)
} {
uint bit = Models[m].Decode(rangeDecoder);
public static uint ReverseDecode(BitDecoder[] Models, UInt32 startIndex, m <<= 1;
RangeCoder.Decoder rangeDecoder, int NumBitLevels) m += bit;
{ symbol |= bit << bitIndex;
uint m = 1; }
uint symbol = 0; return symbol;
for (int bitIndex = 0; bitIndex < NumBitLevels; bitIndex++) }
{
uint bit = Models[startIndex + m].Decode(rangeDecoder); public static uint ReverseDecode(BitDecoder[] Models, UInt32 startIndex,
m <<= 1; Decoder rangeDecoder, int NumBitLevels)
m += bit; {
symbol |= (bit << bitIndex); uint m = 1;
} uint symbol = 0;
return symbol; for (int bitIndex = 0; bitIndex < NumBitLevels; bitIndex++)
} {
} uint bit = Models[startIndex + m].Decode(rangeDecoder);
} m <<= 1;
m += bit;
symbol |= bit << bitIndex;
}
return symbol;
}
}
}
+173 -157
View File
@@ -1,157 +1,173 @@
// ICoder.h // ICoder.h
using System; using System;
using System.Threading;
namespace SevenZip
{ namespace SevenZip
/// <summary> {
/// The exception that is thrown when an error in input stream occurs during decoding. /// <summary>
/// </summary> /// The exception that is thrown when an error in input stream occurs during decoding.
class DataErrorException : ApplicationException /// </summary>
{ internal class DataErrorException : ApplicationException
public DataErrorException(): base("Data Error") { } {
} public DataErrorException() : base("Data Error") { }
/// <summary> public DataErrorException(string message) : base(message)
/// The exception that is thrown when the value of an argument is outside the allowable range. {
/// </summary> }
class InvalidParamException : ApplicationException
{ public DataErrorException(string message, Exception innerException) : base(message, innerException)
public InvalidParamException(): base("Invalid Parameter") { } {
} }
}
public interface ICodeProgress
{ /// <summary>
/// <summary> /// The exception that is thrown when the value of an argument is outside the allowable range.
/// Callback progress. /// </summary>
/// </summary> internal class InvalidParamException : ApplicationException
/// <param name="inSize"> {
/// input size. -1 if unknown. public InvalidParamException() : base("Invalid Parameter") { }
/// </param>
/// <param name="outSize"> public InvalidParamException(string message) : base(message)
/// output size. -1 if unknown. {
/// </param> }
void SetProgress(Int64 inSize, Int64 outSize);
}; public InvalidParamException(string message, Exception innerException) : base(message, innerException)
{
public interface ICoder }
{ }
/// <summary>
/// Codes streams. public interface ICodeProgress
/// </summary> {
/// <param name="inStream"> /// <summary>
/// input Stream. /// Callback progress.
/// </param> /// </summary>
/// <param name="outStream"> /// <param name="inSize">
/// output Stream. /// input size. -1 if unknown.
/// </param> /// </param>
/// <param name="inSize"> /// <param name="outSize">
/// input Size. -1 if unknown. /// output size. -1 if unknown.
/// </param> /// </param>
/// <param name="outSize"> void SetProgress(Int64 inSize, Int64 outSize);
/// output Size. -1 if unknown. };
/// </param>
/// <param name="progress"> public interface ICoder
/// callback progress reference. {
/// </param> /// <summary>
/// <exception cref="SevenZip.DataErrorException"> /// Codes streams.
/// if input stream is not valid /// </summary>
/// </exception> /// <param name="inStream">
void Code(System.IO.Stream inStream, System.IO.Stream outStream, /// input Stream.
Int64 inSize, Int64 outSize, ICodeProgress progress); /// </param>
}; /// <param name="outStream">
/// output Stream.
/* /// </param>
public interface ICoder2 /// <param name="inSize">
{ /// input Size. -1 if unknown.
void Code(ISequentialInStream []inStreams, /// </param>
const UInt64 []inSizes, /// <param name="outSize">
ISequentialOutStream []outStreams, /// output Size. -1 if unknown.
UInt64 []outSizes, /// </param>
ICodeProgress progress); /// <param name="progress">
}; /// callback progress reference.
*/ /// </param>
/// <exception cref="DataErrorException">
/// <summary> /// if input stream is not valid
/// Provides the fields that represent properties idenitifiers for compressing. /// </exception>
/// </summary> void Code(System.IO.Stream inStream, System.IO.Stream outStream,
public enum CoderPropID Int64 inSize, Int64 outSize, ICodeProgress progress, CancellationToken? token = null);
{ };
/// <summary>
/// Specifies default property. /*
/// </summary> public interface ICoder2
DefaultProp = 0, {
/// <summary> void Code(ISequentialInStream []inStreams,
/// Specifies size of dictionary. const UInt64 []inSizes,
/// </summary> ISequentialOutStream []outStreams,
DictionarySize, UInt64 []outSizes,
/// <summary> ICodeProgress progress);
/// Specifies size of memory for PPM*. };
/// </summary> */
UsedMemorySize,
/// <summary> /// <summary>
/// Specifies order for PPM methods. /// Provides the fields that represent properties idenitifiers for compressing.
/// </summary> /// </summary>
Order, public enum CoderPropID
/// <summary> {
/// Specifies Block Size. /// <summary>
/// </summary> /// Specifies default property.
BlockSize, /// </summary>
/// <summary> DefaultProp = 0,
/// Specifies number of postion state bits for LZMA (0 <= x <= 4). /// <summary>
/// </summary> /// Specifies size of dictionary.
PosStateBits, /// </summary>
/// <summary> DictionarySize,
/// Specifies number of literal context bits for LZMA (0 <= x <= 8). /// <summary>
/// </summary> /// Specifies size of memory for PPM*.
LitContextBits, /// </summary>
/// <summary> UsedMemorySize,
/// Specifies number of literal position bits for LZMA (0 <= x <= 4). /// <summary>
/// </summary> /// Specifies order for PPM methods.
LitPosBits, /// </summary>
/// <summary> Order,
/// Specifies number of fast bytes for LZ*. /// <summary>
/// </summary> /// Specifies Block Size.
NumFastBytes, /// </summary>
/// <summary> BlockSize,
/// Specifies match finder. LZMA: "BT2", "BT4" or "BT4B". /// <summary>
/// </summary> /// Specifies number of postion state bits for LZMA (0 <= x <= 4).
MatchFinder, /// </summary>
/// <summary> PosStateBits,
/// Specifies the number of match finder cyckes. /// <summary>
/// </summary> /// Specifies number of literal context bits for LZMA (0 <= x <= 8).
MatchFinderCycles, /// </summary>
/// <summary> LitContextBits,
/// Specifies number of passes. /// <summary>
/// </summary> /// Specifies number of literal position bits for LZMA (0 <= x <= 4).
NumPasses, /// </summary>
/// <summary> LitPosBits,
/// Specifies number of algorithm. /// <summary>
/// </summary> /// Specifies number of fast bytes for LZ*.
Algorithm, /// </summary>
/// <summary> NumFastBytes,
/// Specifies the number of threads. /// <summary>
/// </summary> /// Specifies match finder. LZMA: "BT2", "BT4" or "BT4B".
NumThreads, /// </summary>
/// <summary> MatchFinder,
/// Specifies mode with end marker. /// <summary>
/// </summary> /// Specifies the number of match finder cyckes.
EndMarker /// </summary>
}; MatchFinderCycles,
/// <summary>
/// Specifies number of passes.
public interface ISetCoderProperties /// </summary>
{ NumPasses,
void SetCoderProperties(CoderPropID[] propIDs, object[] properties); /// <summary>
}; /// Specifies number of algorithm.
/// </summary>
public interface IWriteCoderProperties Algorithm,
{ /// <summary>
void WriteCoderProperties(System.IO.Stream outStream); /// Specifies the number of threads.
} /// </summary>
NumThreads,
public interface ISetDecoderProperties /// <summary>
{ /// Specifies mode with end marker.
void SetDecoderProperties(byte[] properties); /// </summary>
} EndMarker
} };
public interface ISetCoderProperties
{
void SetCoderProperties(CoderPropID[] propIDs, object[] properties);
};
public interface IWriteCoderProperties
{
void WriteCoderProperties(System.IO.Stream outStream);
}
public interface ISetDecoderProperties
{
void SetDecoderProperties(byte[] properties);
}
}
-138
View File
@@ -1,138 +0,0 @@
//
// Copyright (c) 2008-2011, Kenneth Bell
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
namespace DiscUtils
{
using System;
using System.Collections.Generic;
using System.Text;
internal class BlockCache<T>
where T : Block, new()
{
private int _blockSize;
private Dictionary<long, T> _blocks;
private LinkedList<T> _lru;
private List<T> _freeBlocks;
private int _blocksCreated;
private int _totalBlocks;
private int _freeBlockCount;
public BlockCache(int blockSize, int blockCount)
{
_blockSize = blockSize;
_totalBlocks = blockCount;
_blocks = new Dictionary<long, T>();
_lru = new LinkedList<T>();
_freeBlocks = new List<T>(_totalBlocks);
_freeBlockCount = _totalBlocks;
}
public int FreeBlockCount
{
get { return _freeBlockCount; }
}
public bool ContainsBlock(long position)
{
return _blocks.ContainsKey(position);
}
public bool TryGetBlock(long position, out T block)
{
if (_blocks.TryGetValue(position, out block))
{
_lru.Remove(block);
_lru.AddFirst(block);
return true;
}
return false;
}
public T GetBlock(long position)
{
T result;
if (TryGetBlock(position, out result))
{
return result;
}
result = GetFreeBlock();
result.Position = position;
result.Available = -1;
StoreBlock(result);
return result;
}
public void ReleaseBlock(long position)
{
T block;
if (_blocks.TryGetValue(position, out block))
{
_blocks.Remove(position);
_lru.Remove(block);
_freeBlocks.Add(block);
_freeBlockCount++;
}
}
private void StoreBlock(T block)
{
_blocks[block.Position] = block;
_lru.AddFirst(block);
}
private T GetFreeBlock()
{
T block;
if (_freeBlocks.Count > 0)
{
int idx = _freeBlocks.Count - 1;
block = _freeBlocks[idx];
_freeBlocks.RemoveAt(idx);
_freeBlockCount--;
}
else if (_blocksCreated < _totalBlocks)
{
block = new T();
block.Data = new byte[_blockSize];
_blocksCreated++;
_freeBlockCount--;
}
else
{
block = _lru.Last.Value;
_lru.RemoveLast();
_blocks.Remove(block.Position);
}
return block;
}
}
}
-77
View File
@@ -1,77 +0,0 @@
//
// Copyright (c) 2008-2011, Kenneth Bell
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
namespace DiscUtils
{
/// <summary>
/// Settings controlling BlockCache instances.
/// </summary>
public sealed class BlockCacheSettings
{
/// <summary>
/// Initializes a new instance of the BlockCacheSettings class.
/// </summary>
public BlockCacheSettings()
{
this.BlockSize = (int)(4 * Sizes.OneKiB);
this.ReadCacheSize = 4 * Sizes.OneMiB;
this.LargeReadSize = 64 * Sizes.OneKiB;
this.OptimumReadSize = (int)(64 * Sizes.OneKiB);
}
/// <summary>
/// Initializes a new instance of the BlockCacheSettings class.
/// </summary>
/// <param name="settings">The cache settings.</param>
internal BlockCacheSettings(BlockCacheSettings settings)
{
this.BlockSize = settings.BlockSize;
this.ReadCacheSize = settings.ReadCacheSize;
this.LargeReadSize = settings.LargeReadSize;
this.OptimumReadSize = settings.OptimumReadSize;
}
/// <summary>
/// Gets or sets the size (in bytes) of each cached block.
/// </summary>
public int BlockSize { get; set; }
/// <summary>
/// Gets or sets the size (in bytes) of the read cache.
/// </summary>
public long ReadCacheSize { get; set; }
/// <summary>
/// Gets or sets the maximum read size that will be cached.
/// </summary>
/// <remarks>Large reads are not cached, on the assumption they will not
/// be repeated. This setting controls what is considered 'large'.
/// Any read that is more than this many bytes will not be cached.</remarks>
public long LargeReadSize { get; set; }
/// <summary>
/// Gets or sets the optimum size of a read to the wrapped stream.
/// </summary>
/// <remarks>This value must be a multiple of BlockSize.</remarks>
public int OptimumReadSize { get; set; }
}
}
-79
View File
@@ -1,79 +0,0 @@
//
// Copyright (c) 2008-2011, Kenneth Bell
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
namespace DiscUtils
{
/// <summary>
/// Statistical information about the effectiveness of a BlockCache instance.
/// </summary>
public sealed class BlockCacheStatistics
{
/// <summary>
/// Gets the number of requested 'large' reads, as defined by the LargeReadSize setting.
/// </summary>
public long LargeReadsIn { get; internal set; }
/// <summary>
/// Gets the number of requested unaligned reads.
/// </summary>
/// <remarks>Unaligned reads are reads where the read doesn't start on a multiple of
/// the block size.</remarks>
public long UnalignedReadsIn { get; internal set; }
/// <summary>
/// Gets the total number of requested reads.
/// </summary>
public long TotalReadsIn { get; internal set; }
/// <summary>
/// Gets the total number of reads passed on by the cache.
/// </summary>
public long TotalReadsOut { get; internal set; }
/// <summary>
/// Gets the number of times a read request was serviced (in part or whole) from the cache.
/// </summary>
public long ReadCacheHits { get; internal set; }
/// <summary>
/// Gets the number of time a read request was serviced (in part or whole) from the wrapped stream.
/// </summary>
public long ReadCacheMisses { get; internal set; }
/// <summary>
/// Gets the number of requested unaligned writes.
/// </summary>
/// <remarks>Unaligned writes are writes where the write doesn't start on a multiple of
/// the block size.</remarks>
public long UnalignedWritesIn { get; internal set; }
/// <summary>
/// Gets the total number of requested writes.
/// </summary>
public long TotalWritesIn { get; internal set; }
/// <summary>
/// Gets the number of free blocks in the read cache.
/// </summary>
public int FreeReadBlocks { get; internal set; }
}
}
-472
View File
@@ -1,472 +0,0 @@
//
// Copyright (c) 2008-2011, Kenneth Bell
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
namespace DiscUtils
{
using System;
using System.Collections.Generic;
using System.IO;
/// <summary>
/// A stream implementing a block-oriented read cache.
/// </summary>
public sealed class BlockCacheStream : SparseStream
{
private SparseStream _wrappedStream;
private Ownership _ownWrapped;
private BlockCacheSettings _settings;
private BlockCacheStatistics _stats;
private long _position;
private bool _atEof;
private BlockCache<Block> _cache;
private byte[] _readBuffer;
private int _blocksInReadBuffer;
/// <summary>
/// Initializes a new instance of the BlockCacheStream class.
/// </summary>
/// <param name="toWrap">The stream to wrap.</param>
/// <param name="ownership">Whether to assume ownership of <c>toWrap</c>.</param>
public BlockCacheStream(SparseStream toWrap, Ownership ownership)
: this(toWrap, ownership, new BlockCacheSettings())
{
}
/// <summary>
/// Initializes a new instance of the BlockCacheStream class.
/// </summary>
/// <param name="toWrap">The stream to wrap.</param>
/// <param name="ownership">Whether to assume ownership of <c>toWrap</c>.</param>
/// <param name="settings">The cache settings.</param>
public BlockCacheStream(SparseStream toWrap, Ownership ownership, BlockCacheSettings settings)
{
if (!toWrap.CanRead)
{
throw new ArgumentException("The wrapped stream does not support reading", "toWrap");
}
if (!toWrap.CanSeek)
{
throw new ArgumentException("The wrapped stream does not support seeking", "toWrap");
}
_wrappedStream = toWrap;
_ownWrapped = ownership;
_settings = new BlockCacheSettings(settings);
if (_settings.OptimumReadSize % _settings.BlockSize != 0)
{
throw new ArgumentException("Invalid settings, OptimumReadSize must be a multiple of BlockSize", "settings");
}
_readBuffer = new byte[_settings.OptimumReadSize];
_blocksInReadBuffer = _settings.OptimumReadSize / _settings.BlockSize;
int totalBlocks = (int)(_settings.ReadCacheSize / _settings.BlockSize);
_cache = new BlockCache<Block>(_settings.BlockSize, totalBlocks);
_stats = new BlockCacheStatistics();
_stats.FreeReadBlocks = totalBlocks;
}
/// <summary>
/// Gets the parts of the stream that are stored.
/// </summary>
/// <remarks>This may be an empty enumeration if all bytes are zero.</remarks>
public override IEnumerable<StreamExtent> Extents
{
get
{
CheckDisposed();
return _wrappedStream.Extents;
}
}
/// <summary>
/// Gets an indication as to whether the stream can be read.
/// </summary>
public override bool CanRead
{
get { return true; }
}
/// <summary>
/// Gets an indication as to whether the stream position can be changed.
/// </summary>
public override bool CanSeek
{
get { return true; }
}
/// <summary>
/// Gets an indication as to whether the stream can be written to.
/// </summary>
public override bool CanWrite
{
get { return _wrappedStream.CanWrite; }
}
/// <summary>
/// Gets the length of the stream.
/// </summary>
public override long Length
{
get
{
CheckDisposed();
return _wrappedStream.Length;
}
}
/// <summary>
/// Gets and sets the current stream position.
/// </summary>
public override long Position
{
get
{
CheckDisposed();
return _position;
}
set
{
CheckDisposed();
_position = value;
}
}
/// <summary>
/// Gets the performance statistics for this instance.
/// </summary>
public BlockCacheStatistics Statistics
{
get
{
_stats.FreeReadBlocks = _cache.FreeBlockCount;
return _stats;
}
}
/// <summary>
/// Gets the parts of a stream that are stored, within a specified range.
/// </summary>
/// <param name="start">The offset of the first byte of interest.</param>
/// <param name="count">The number of bytes of interest.</param>
/// <returns>An enumeration of stream extents, indicating stored bytes.</returns>
public override IEnumerable<StreamExtent> GetExtentsInRange(long start, long count)
{
CheckDisposed();
return _wrappedStream.GetExtentsInRange(start, count);
}
/// <summary>
/// Reads data from the stream.
/// </summary>
/// <param name="buffer">The buffer to fill.</param>
/// <param name="offset">The buffer offset to start from.</param>
/// <param name="count">The number of bytes to read.</param>
/// <returns>The number of bytes read.</returns>
public override int Read(byte[] buffer, int offset, int count)
{
CheckDisposed();
if (_position >= Length)
{
if (_atEof)
{
throw new IOException("Attempt to read beyond end of stream");
}
else
{
_atEof = true;
return 0;
}
}
_stats.TotalReadsIn++;
if (count > _settings.LargeReadSize)
{
_stats.LargeReadsIn++;
_stats.TotalReadsOut++;
_wrappedStream.Position = _position;
int numRead = _wrappedStream.Read(buffer, offset, count);
_position = _wrappedStream.Position;
if (_position >= Length)
{
_atEof = true;
}
return numRead;
}
int totalBytesRead = 0;
bool servicedFromCache = false;
bool servicedOutsideCache = false;
int blockSize = _settings.BlockSize;
long firstBlock = _position / blockSize;
int offsetInNextBlock = (int)(_position % blockSize);
long endBlock = Utilities.Ceil(Math.Min(_position + count, Length), blockSize);
int numBlocks = (int)(endBlock - firstBlock);
if (offsetInNextBlock != 0)
{
_stats.UnalignedReadsIn++;
}
int blocksRead = 0;
while (blocksRead < numBlocks)
{
Block block;
// Read from the cache as much as possible
while (blocksRead < numBlocks && _cache.TryGetBlock(firstBlock + blocksRead, out block))
{
int bytesToRead = Math.Min(count - totalBytesRead, block.Available - offsetInNextBlock);
Array.Copy(block.Data, offsetInNextBlock, buffer, offset + totalBytesRead, bytesToRead);
offsetInNextBlock = 0;
totalBytesRead += bytesToRead;
_position += bytesToRead;
blocksRead++;
servicedFromCache = true;
}
// Now handle a sequence of (one or more) blocks that are not cached
if (blocksRead < numBlocks && !_cache.ContainsBlock(firstBlock + blocksRead))
{
servicedOutsideCache = true;
// Figure out how many blocks to read from the wrapped stream
int blocksToRead = 0;
while (blocksRead + blocksToRead < numBlocks
&& blocksToRead < _blocksInReadBuffer
&& !_cache.ContainsBlock(firstBlock + blocksRead + blocksToRead))
{
++blocksToRead;
}
// Allow for the end of the stream not being block-aligned
long readPosition = (firstBlock + blocksRead) * (long)blockSize;
int bytesToRead = (int)Math.Min(blocksToRead * (long)blockSize, Length - readPosition);
// Do the read
_stats.TotalReadsOut++;
_wrappedStream.Position = readPosition;
int bytesRead = Utilities.ReadFully(_wrappedStream, _readBuffer, 0, bytesToRead);
if (bytesRead != bytesToRead)
{
throw new IOException("Short read before end of stream");
}
// Cache the read blocks
for (int i = 0; i < blocksToRead; ++i)
{
int copyBytes = Math.Min(blockSize, bytesToRead - (i * blockSize));
block = _cache.GetBlock(firstBlock + blocksRead + i);
Array.Copy(_readBuffer, i * blockSize, block.Data, 0, copyBytes);
block.Available = copyBytes;
if (copyBytes < blockSize)
{
Array.Clear(_readBuffer, (i * blockSize) + copyBytes, blockSize - copyBytes);
}
}
blocksRead += blocksToRead;
// Propogate the data onto the caller
int bytesToCopy = Math.Min(count - totalBytesRead, bytesRead - offsetInNextBlock);
Array.Copy(_readBuffer, offsetInNextBlock, buffer, offset + totalBytesRead, bytesToCopy);
totalBytesRead += bytesToCopy;
_position += bytesToCopy;
offsetInNextBlock = 0;
}
}
if (_position >= Length && totalBytesRead == 0)
{
_atEof = true;
}
if (servicedFromCache)
{
_stats.ReadCacheHits++;
}
if (servicedOutsideCache)
{
_stats.ReadCacheMisses++;
}
return totalBytesRead;
}
/// <summary>
/// Flushes the stream.
/// </summary>
public override void Flush()
{
CheckDisposed();
_wrappedStream.Flush();
}
/// <summary>
/// Moves the stream position.
/// </summary>
/// <param name="offset">The origin-relative location.</param>
/// <param name="origin">The base location.</param>
/// <returns>The new absolute stream position.</returns>
public override long Seek(long offset, SeekOrigin origin)
{
CheckDisposed();
long effectiveOffset = offset;
if (origin == SeekOrigin.Current)
{
effectiveOffset += _position;
}
else if (origin == SeekOrigin.End)
{
effectiveOffset += Length;
}
_atEof = false;
if (effectiveOffset < 0)
{
throw new IOException("Attempt to move before beginning of disk");
}
else
{
_position = effectiveOffset;
return _position;
}
}
/// <summary>
/// Sets the length of the stream.
/// </summary>
/// <param name="value">The new length.</param>
public override void SetLength(long value)
{
CheckDisposed();
_wrappedStream.SetLength(value);
}
/// <summary>
/// Writes data to the stream at the current location.
/// </summary>
/// <param name="buffer">The data to write.</param>
/// <param name="offset">The first byte to write from buffer.</param>
/// <param name="count">The number of bytes to write.</param>
public override void Write(byte[] buffer, int offset, int count)
{
CheckDisposed();
_stats.TotalWritesIn++;
int blockSize = _settings.BlockSize;
long firstBlock = _position / blockSize;
long endBlock = Utilities.Ceil(Math.Min(_position + count, Length), blockSize);
int numBlocks = (int)(endBlock - firstBlock);
try
{
_wrappedStream.Position = _position;
_wrappedStream.Write(buffer, offset, count);
}
catch
{
InvalidateBlocks(firstBlock, numBlocks);
throw;
}
int offsetInNextBlock = (int)(_position % blockSize);
if (offsetInNextBlock != 0)
{
_stats.UnalignedWritesIn++;
}
// For each block touched, if it's cached, update it
int bytesProcessed = 0;
for (int i = 0; i < numBlocks; ++i)
{
int bufferPos = offset + bytesProcessed;
int bytesThisBlock = Math.Min(count - bytesProcessed, blockSize - offsetInNextBlock);
Block block;
if (_cache.TryGetBlock(firstBlock + i, out block))
{
Array.Copy(buffer, bufferPos, block.Data, offsetInNextBlock, bytesThisBlock);
block.Available = Math.Max(block.Available, offsetInNextBlock + bytesThisBlock);
}
offsetInNextBlock = 0;
bytesProcessed += bytesThisBlock;
}
_position += count;
}
/// <summary>
/// Disposes of this instance, freeing up associated resources.
/// </summary>
/// <param name="disposing"><c>true</c> if invoked from <c>Dispose</c>, else <c>false</c>.</param>
protected override void Dispose(bool disposing)
{
if (disposing)
{
if (_wrappedStream != null && _ownWrapped == Ownership.Dispose)
{
_wrappedStream.Dispose();
}
_wrappedStream = null;
}
base.Dispose(disposing);
}
private void CheckDisposed()
{
if (_wrappedStream == null)
{
throw new ObjectDisposedException("BlockCacheStream");
}
}
private void InvalidateBlocks(long firstBlock, int numBlocks)
{
for (long i = firstBlock; i < (firstBlock + numBlocks); ++i)
{
_cache.ReleaseBlock(i);
}
}
}
}
@@ -1,55 +0,0 @@
//
// Copyright (c) 2008-2011, Kenneth Bell
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
namespace DiscUtils.BootConfig
{
/// <summary>
/// Enumeration of known application image types.
/// </summary>
public enum ApplicationImageType
{
/// <summary>
/// Unknown type.
/// </summary>
None = 0x0,
/// <summary>
/// Firmware application.
/// </summary>
Firmware = 0x1,
/// <summary>
/// Windows boot loader.
/// </summary>
WindowsBoot = 0x2,
/// <summary>
/// Legacy boot loader.
/// </summary>
LegacyLoader = 0x3,
/// <summary>
/// Real mode boot loader.
/// </summary>
RealMode = 0x4
}
}
-80
View File
@@ -1,80 +0,0 @@
//
// Copyright (c) 2008-2011, Kenneth Bell
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
namespace DiscUtils.BootConfig
{
/// <summary>
/// Enumeration of known application types.
/// </summary>
public enum ApplicationType
{
/// <summary>
/// Unknown type.
/// </summary>
None = 0,
/// <summary>
/// Firmware boot manager (e.g. UEFI).
/// </summary>
FirmwareBootManager = 1,
/// <summary>
/// Windows boot manager.
/// </summary>
BootManager = 2,
/// <summary>
/// Operating System Loader.
/// </summary>
OsLoader = 3,
/// <summary>
/// Resume loader.
/// </summary>
Resume = 4,
/// <summary>
/// Memory diagnostic application.
/// </summary>
MemoryDiagnostics = 5,
/// <summary>
/// Legacy NT loader application.
/// </summary>
NtLoader = 6,
/// <summary>
/// Windows setup application.
/// </summary>
SetupLoader = 7,
/// <summary>
/// Boot sector application.
/// </summary>
BootSector = 8,
/// <summary>
/// Startup application.
/// </summary>
Startup = 9
}
}
-75
View File
@@ -1,75 +0,0 @@
//
// Copyright (c) 2008-2011, Kenneth Bell
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
namespace DiscUtils.BootConfig
{
using System;
using System.Collections.Generic;
/// <summary>
/// Base class for BCD storage repositories.
/// </summary>
internal abstract class BaseStorage
{
/// <summary>
/// Tests if an element is present (i.e. has a value) on an object.
/// </summary>
/// <param name="obj">The object to inspect.</param>
/// <param name="element">The element to inspect.</param>
/// <returns><c>true</c> if present, else <c>false</c>.</returns>
public abstract bool HasValue(Guid obj, int element);
/// <summary>
/// Gets the value of a string element.
/// </summary>
/// <param name="obj">The object to inspect.</param>
/// <param name="element">The element to retrieve.</param>
/// <returns>The value as a string.</returns>
public abstract string GetString(Guid obj, int element);
public abstract byte[] GetBinary(Guid obj, int element);
public abstract void SetString(Guid obj, int element, string value);
public abstract void SetBinary(Guid obj, int element, byte[] value);
public abstract string[] GetMultiString(Guid obj, int element);
public abstract void SetMultiString(Guid obj, int element, string[] values);
public abstract IEnumerable<Guid> EnumerateObjects();
public abstract IEnumerable<int> EnumerateElements(Guid obj);
public abstract int GetObjectType(Guid obj);
public abstract bool ObjectExists(Guid obj);
public abstract Guid CreateObject(Guid obj, int type);
public abstract void CreateElement(Guid obj, int element);
public abstract void DeleteObject(Guid obj);
public abstract void DeleteElement(Guid obj, int element);
}
}
-365
View File
@@ -1,365 +0,0 @@
//
// Copyright (c) 2008-2011, Kenneth Bell
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
//
// Symbolic names of BCD Objects taken from Geoff Chappell's website:
// http://www.geoffchappell.com/viewer.htm?doc=notes/windows/boot/bcd/objects.htm
//
//
namespace DiscUtils.BootConfig
{
using System;
using System.Collections.Generic;
/// <summary>
/// Represents a Boot Configuration Database object (application, device or inherited settings).
/// </summary>
public class BcdObject
{
/// <summary>
/// Well-known object for Emergency Management Services settings.
/// </summary>
public const string EmsSettingsGroupId = "{0CE4991B-E6B3-4B16-B23C-5E0D9250E5D9}";
/// <summary>
/// Well-known object for the Resume boot loader.
/// </summary>
public const string ResumeLoaderSettingsGroupId = "{1AFA9C49-16AB-4A5C-4A90-212802DA9460}";
/// <summary>
/// Alias for the Default boot entry.
/// </summary>
public const string DefaultBootEntryId = "{1CAE1EB7-A0DF-4D4D-9851-4860E34EF535}";
/// <summary>
/// Well-known object for Emergency Management Services settings.
/// </summary>
public const string DebuggerSettingsGroupId = "{4636856E-540F-4170-A130-A84776F4C654}";
/// <summary>
/// Well-known object for NTLDR application.
/// </summary>
public const string WindowsLegacyNtldrId = "{466F5A88-0AF2-4F76-9038-095B170DC21C}";
/// <summary>
/// Well-known object for bad memory settings.
/// </summary>
public const string BadMemoryGroupId = "{5189B25C-5558-4BF2-BCA4-289B11BD29E2}";
/// <summary>
/// Well-known object for Boot Loader settings.
/// </summary>
public const string BootLoaderSettingsGroupId = "{6EFB52BF-1766-41DB-A6B3-0EE5EFF72BD7}";
/// <summary>
/// Well-known object for EFI setup.
/// </summary>
public const string WindowsSetupEfiId = "{7254A080-1510-4E85-AC0F-E7FB3D444736}";
/// <summary>
/// Well-known object for Global settings.
/// </summary>
public const string GlobalSettingsGroupId = "{7EA2E1AC-2E61-4728-AAA3-896D9D0A9F0E}";
/// <summary>
/// Well-known object for Windows Boot Manager.
/// </summary>
public const string WindowsBootManagerId = "{9DEA862C-5CDD-4E70-ACC1-F32B344D4795}";
/// <summary>
/// Well-known object for PCAT Template.
/// </summary>
public const string WindowsOsTargetTemplatePcatId = "{A1943BBC-EA85-487C-97C7-C9EDE908A38A}";
/// <summary>
/// Well-known object for Firmware Boot Manager.
/// </summary>
public const string FirmwareBootManagerId = "{A5A30FA2-3D06-4E9F-B5F4-A01DF9D1FCBA}";
/// <summary>
/// Well-known object for Windows Setup RAMDISK options.
/// </summary>
public const string WindowsSetupRamdiskOptionsId = "{AE5534E0-A924-466C-B836-758539A3EE3A}";
/// <summary>
/// Well-known object for EFI template.
/// </summary>
public const string WindowsOsTargetTemplateEfiId = "{B012B84D-C47C-4ED5-B722-C0C42163E569}";
/// <summary>
/// Well-known object for Windows memory tester application.
/// </summary>
public const string WindowsMemoryTesterId = "{B2721D73-1DB4-4C62-BF78-C548A880142D}";
/// <summary>
/// Well-known object for Windows PCAT setup.
/// </summary>
public const string WindowsSetupPcatId = "{CBD971BF-B7B8-4885-951A-FA03044F5D71}";
/// <summary>
/// Alias for the current boot entry.
/// </summary>
public const string CurrentBootEntryId = "{FA926493-6F1C-4193-A414-58F0B2456D1E}";
private static Dictionary<string, Guid> s_nameToGuid;
private static Dictionary<Guid, string> s_guidToName;
private BaseStorage _storage;
private Guid _id;
private int _type;
static BcdObject()
{
s_nameToGuid = new Dictionary<string, Guid>();
s_guidToName = new Dictionary<Guid, string>();
AddMapping("{emssettings}", EmsSettingsGroupId);
AddMapping("{resumeloadersettings}", ResumeLoaderSettingsGroupId);
AddMapping("{default}", DefaultBootEntryId);
AddMapping("{dbgsettings}", DebuggerSettingsGroupId);
AddMapping("{legacy}", WindowsLegacyNtldrId);
AddMapping("{ntldr}", WindowsLegacyNtldrId);
AddMapping("{badmemory}", BadMemoryGroupId);
AddMapping("{bootloadersettings}", BootLoaderSettingsGroupId);
AddMapping("{globalsettings}", GlobalSettingsGroupId);
AddMapping("{bootmgr}", WindowsBootManagerId);
AddMapping("{fwbootmgr}", FirmwareBootManagerId);
AddMapping("{ramdiskoptions}", WindowsSetupRamdiskOptionsId);
AddMapping("{memdiag}", WindowsMemoryTesterId);
AddMapping("{current}", CurrentBootEntryId);
}
internal BcdObject(BaseStorage store, Guid id)
{
_storage = store;
_id = id;
_type = _storage.GetObjectType(id);
}
/// <summary>
/// Gets the identity of this object.
/// </summary>
public Guid Identity
{
get { return _id; }
}
/// <summary>
/// Gets the friendly name for this object, if known.
/// </summary>
public string FriendlyName
{
get
{
string name;
if (s_guidToName.TryGetValue(_id, out name))
{
return name;
}
return _id.ToString("B");
}
}
/// <summary>
/// Gets the object type for this object.
/// </summary>
public ObjectType ObjectType
{
get { return (ObjectType)((_type >> 28) & 0xF); }
}
/// <summary>
/// Gets the image type for this application.
/// </summary>
public ApplicationImageType ApplicationImageType
{
get { return IsApplication ? (ApplicationImageType)((_type & 0x00F00000) >> 20) : 0; }
}
/// <summary>
/// Gets the application type for this application.
/// </summary>
public ApplicationType ApplicationType
{
get { return IsApplication ? (ApplicationType)(_type & 0xFFFFF) : 0; }
}
/// <summary>
/// Gets the elements in this object.
/// </summary>
public IEnumerable<Element> Elements
{
get
{
foreach (var el in _storage.EnumerateElements(_id))
{
yield return new Element(_storage, _id, ApplicationType, el);
}
}
}
private bool IsApplication
{
get { return ObjectType == ObjectType.Application; }
}
/// <summary>
/// Indicates if the settings in this object are inheritable by another object.
/// </summary>
/// <param name="type">The type of the object to test for inheritability.</param>
/// <returns><c>true</c> if the settings can be inherited, else <c>false</c>.</returns>
public bool IsInheritableBy(ObjectType type)
{
if (type == ObjectType.Inherit)
{
throw new ArgumentException("Can not test inheritability by inherit objects", "type");
}
if (ObjectType != ObjectType.Inherit)
{
return false;
}
InheritType setting = (InheritType)((_type & 0x00F00000) >> 20);
return setting == InheritType.AnyObject
|| (setting == InheritType.ApplicationObjects && type == ObjectType.Application)
|| (setting == InheritType.DeviceObjects && type == ObjectType.Device);
}
/// <summary>
/// Indicates if this object has a specific element.
/// </summary>
/// <param name="id">The identity of the element to look for.</param>
/// <returns><c>true</c> if present, else <c>false</c>.</returns>
public bool HasElement(int id)
{
return _storage.HasValue(_id, id);
}
/// <summary>
/// Indicates if this object has a specific element.
/// </summary>
/// <param name="id">The identity of the element to look for.</param>
/// <returns><c>true</c> if present, else <c>false</c>.</returns>
public bool HasElement(WellKnownElement id)
{
return HasElement((int)id);
}
/// <summary>
/// Gets a specific element in this object.
/// </summary>
/// <param name="id">The identity of the element to look for.</param>
/// <returns>The element object.</returns>
public Element GetElement(int id)
{
if (HasElement(id))
{
return new Element(_storage, _id, ApplicationType, id);
}
return null;
}
/// <summary>
/// Gets a specific element in this object.
/// </summary>
/// <param name="id">The identity of the element to look for.</param>
/// <returns>The element object.</returns>
public Element GetElement(WellKnownElement id)
{
return GetElement((int)id);
}
/// <summary>
/// Adds an element in this object.
/// </summary>
/// <param name="id">The identity of the element to add.</param>
/// <param name="initialValue">The initial value of the element.</param>
/// <returns>The element object.</returns>
public Element AddElement(int id, ElementValue initialValue)
{
_storage.CreateElement(_id, id);
Element el = new Element(_storage, _id, ApplicationType, id);
el.Value = initialValue;
return el;
}
/// <summary>
/// Adds an element in this object.
/// </summary>
/// <param name="id">The identity of the element to add.</param>
/// <param name="initialValue">The initial value of the element.</param>
/// <returns>The element object.</returns>
public Element AddElement(WellKnownElement id, ElementValue initialValue)
{
return AddElement((int)id, initialValue);
}
/// <summary>
/// Removes a specific element.
/// </summary>
/// <param name="id">The element to remove.</param>
public void RemoveElement(int id)
{
_storage.DeleteElement(_id, id);
}
/// <summary>
/// Removes a specific element.
/// </summary>
/// <param name="id">The element to remove.</param>
public void RemoveElement(WellKnownElement id)
{
RemoveElement((int)id);
}
/// <summary>
/// Returns the object identity as a GUID string.
/// </summary>
/// <returns>A string representation, with surrounding curly braces.</returns>
public override string ToString()
{
return _id.ToString("B");
}
internal static int MakeApplicationType(ApplicationImageType imageType, ApplicationType appType)
{
return 0x10000000 | (((int)imageType << 20) & 0x00F00000) | ((int)appType & 0x0000FFFF);
}
internal static int MakeInheritType(InheritType inheritType)
{
return 0x20000000 | (((int)inheritType << 20) & 0x00F00000);
}
private static void AddMapping(string name, string id)
{
Guid guid = new Guid(id);
s_nameToGuid[name] = guid;
s_guidToName[guid] = name;
}
}
}
@@ -1,58 +0,0 @@
//
// Copyright (c) 2008-2011, Kenneth Bell
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
namespace DiscUtils.BootConfig
{
using System;
using System.Text;
internal class DeviceAndPathRecord : DeviceRecord
{
private DeviceRecord _container;
private string _path;
public override int Size
{
get { throw new NotImplementedException(); }
}
public override void GetBytes(byte[] data, int offset)
{
throw new NotImplementedException();
}
public override string ToString()
{
return _container.ToString() + ":" + _path;
}
protected override void DoParse(byte[] data, int offset)
{
base.DoParse(data, offset);
_container = DeviceRecord.Parse(data, offset + 0x34);
int pathStart = 0x34 + _container.Size;
_path = Encoding.Unicode.GetString(data, offset + pathStart, Length - pathStart);
}
}
}
-114
View File
@@ -1,114 +0,0 @@
//
// Copyright (c) 2008-2011, Kenneth Bell
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
namespace DiscUtils.BootConfig
{
using System;
using System.Globalization;
internal class DeviceElementValue : ElementValue
{
private Guid _parentObject;
private DeviceRecord _record;
public DeviceElementValue()
{
_parentObject = Guid.Empty;
PartitionRecord record = new PartitionRecord();
record.Type = 5;
_record = record;
}
public DeviceElementValue(Guid parentObject, PhysicalVolumeInfo pvi)
{
_parentObject = parentObject;
PartitionRecord record = new PartitionRecord();
record.Type = 6;
if (pvi.VolumeType == PhysicalVolumeType.BiosPartition)
{
record.PartitionType = 1;
record.DiskIdentity = new byte[4];
Utilities.WriteBytesLittleEndian(pvi.DiskSignature, record.DiskIdentity, 0);
record.PartitionIdentity = new byte[8];
Utilities.WriteBytesLittleEndian(pvi.PhysicalStartSector * 512, record.PartitionIdentity, 0);
}
else if (pvi.VolumeType == PhysicalVolumeType.GptPartition)
{
record.PartitionType = 0;
record.DiskIdentity = new byte[16];
Utilities.WriteBytesLittleEndian(pvi.DiskIdentity, record.DiskIdentity, 0);
record.PartitionIdentity = new byte[16];
Utilities.WriteBytesLittleEndian(pvi.PartitionIdentity, record.PartitionIdentity, 0);
}
else
{
throw new NotImplementedException(string.Format(CultureInfo.InvariantCulture, "Unknown how to convert volume type {0} to a Device element", pvi.VolumeType));
}
_record = record;
}
public DeviceElementValue(byte[] value)
{
_parentObject = Utilities.ToGuidLittleEndian(value, 0x00);
_record = DeviceRecord.Parse(value, 0x10);
}
public override Guid ParentObject
{
get { return _parentObject; }
}
public override ElementFormat Format
{
get { return ElementFormat.Device; }
}
public override string ToString()
{
if (_parentObject != Guid.Empty)
{
return _parentObject.ToString() + ":" + _record.ToString();
}
else if (_record != null)
{
return _record.ToString();
}
else
{
return "<unknown>";
}
}
internal byte[] GetBytes()
{
byte[] buffer = new byte[_record.Size + 0x10];
Utilities.WriteBytesLittleEndian(_parentObject, buffer, 0);
_record.GetBytes(buffer, 0x10);
return buffer;
}
}
}
-84
View File
@@ -1,84 +0,0 @@
//
// Copyright (c) 2008-2011, Kenneth Bell
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
namespace DiscUtils.BootConfig
{
using System;
using System.IO;
internal abstract class DeviceRecord
{
public int Type { get; set; }
public int Length { get; set; }
public abstract int Size { get; }
public static DeviceRecord Parse(byte[] data, int offset)
{
int type = Utilities.ToInt32LittleEndian(data, offset);
int length = Utilities.ToInt32LittleEndian(data, offset + 0x8);
if (offset + length > data.Length)
{
throw new InvalidDataException("Device record is truncated");
}
DeviceRecord newRecord = null;
switch (type)
{
case 0:
newRecord = new DeviceAndPathRecord();
break;
case 5: // Logical 'boot' device
case 6: // Disk partition
newRecord = new PartitionRecord();
break;
case 8: // custom:nnnnnn
break;
default:
throw new NotImplementedException("Unknown device type: " + type);
}
if (newRecord != null)
{
newRecord.DoParse(data, offset);
}
return newRecord;
}
public abstract void GetBytes(byte[] data, int offset);
protected virtual void DoParse(byte[] data, int offset)
{
Type = Utilities.ToInt32LittleEndian(data, offset);
Length = Utilities.ToInt32LittleEndian(data, offset + 0x8);
}
protected void WriteHeader(byte[] data, int offset)
{
Length = Size;
Utilities.WriteBytesLittleEndian(Type, data, offset);
Utilities.WriteBytesLittleEndian(Size, data, offset + 0x8);
}
}
}
@@ -1,162 +0,0 @@
//
// Copyright (c) 2008-2011, Kenneth Bell
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
namespace DiscUtils.BootConfig
{
using System;
using System.Collections.Generic;
using System.Globalization;
using DiscUtils.Registry;
internal class DiscUtilsRegistryStorage : BaseStorage
{
private const string ElementsPathTemplate = @"Objects\{0}\Elements";
private const string ElementPathTemplate = @"Objects\{0}\Elements\{1:X8}";
private const string ObjectTypePathTemplate = @"Objects\{0}\Description";
private const string ObjectsPath = @"Objects";
private RegistryKey _rootKey;
public DiscUtilsRegistryStorage(RegistryKey key)
{
_rootKey = key;
}
public override string GetString(Guid obj, int element)
{
return GetValue(obj, element) as string;
}
public override void SetString(Guid obj, int element, string value)
{
SetValue(obj, element, value);
}
public override byte[] GetBinary(Guid obj, int element)
{
return GetValue(obj, element) as byte[];
}
public override void SetBinary(Guid obj, int element, byte[] value)
{
SetValue(obj, element, value);
}
public override string[] GetMultiString(Guid obj, int element)
{
return GetValue(obj, element) as string[];
}
public override void SetMultiString(Guid obj, int element, string[] values)
{
SetValue(obj, element, values);
}
public override IEnumerable<Guid> EnumerateObjects()
{
RegistryKey parentKey = _rootKey.OpenSubKey("Objects");
foreach (var key in parentKey.GetSubKeyNames())
{
yield return new Guid(key);
}
}
public override IEnumerable<int> EnumerateElements(Guid obj)
{
string path = string.Format(CultureInfo.InvariantCulture, ElementsPathTemplate, obj.ToString("B"));
RegistryKey parentKey = _rootKey.OpenSubKey(path);
foreach (var key in parentKey.GetSubKeyNames())
{
yield return int.Parse(key, NumberStyles.HexNumber);
}
}
public override int GetObjectType(Guid obj)
{
string path = string.Format(CultureInfo.InvariantCulture, ObjectTypePathTemplate, obj.ToString("B"));
RegistryKey descKey = _rootKey.OpenSubKey(path);
object val = descKey.GetValue("Type");
return (int)val;
}
public override bool HasValue(Guid obj, int element)
{
string path = string.Format(CultureInfo.InvariantCulture, ElementPathTemplate, obj.ToString("B"), element);
return _rootKey.OpenSubKey(path) != null;
}
public override bool ObjectExists(Guid obj)
{
string path = string.Format(CultureInfo.InvariantCulture, ObjectTypePathTemplate, obj.ToString("B"));
return _rootKey.OpenSubKey(path) != null;
}
public override Guid CreateObject(Guid obj, int type)
{
Guid realObj = (obj == Guid.Empty) ? Guid.NewGuid() : obj;
string path = string.Format(CultureInfo.InvariantCulture, ObjectTypePathTemplate, realObj.ToString("B"));
RegistryKey key = _rootKey.CreateSubKey(path);
key.SetValue("Type", type, RegistryValueType.Dword);
return realObj;
}
public override void CreateElement(Guid obj, int element)
{
string path = string.Format(CultureInfo.InvariantCulture, ElementPathTemplate, obj.ToString("B"), element);
_rootKey.CreateSubKey(path);
}
public override void DeleteObject(Guid obj)
{
string path = string.Format(CultureInfo.InvariantCulture, ObjectTypePathTemplate, obj.ToString("B"));
_rootKey.DeleteSubKeyTree(path);
}
public override void DeleteElement(Guid obj, int element)
{
string path = string.Format(CultureInfo.InvariantCulture, ElementPathTemplate, obj.ToString("B"), element);
_rootKey.DeleteSubKeyTree(path);
}
private object GetValue(Guid obj, int element)
{
string path = string.Format(CultureInfo.InvariantCulture, ElementPathTemplate, obj.ToString("B"), element);
RegistryKey key = _rootKey.OpenSubKey(path);
return key.GetValue("Element");
}
private void SetValue(Guid obj, int element, object value)
{
string path = string.Format(CultureInfo.InvariantCulture, ElementPathTemplate, obj.ToString("B"), element);
RegistryKey key = _rootKey.OpenSubKey(path);
key.SetValue("Element", value);
}
}
}
-390
View File
@@ -1,390 +0,0 @@
//
// Copyright (c) 2008-2011, Kenneth Bell
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
//
// Symbolic names of BCD Elements taken from Geoff Chappell's website:
// http://www.geoffchappell.com/viewer.htm?doc=notes/windows/boot/bcd/elements.htm
//
//
namespace DiscUtils.BootConfig
{
using System;
using System.Globalization;
/// <summary>
/// Represents an element in a Boot Configuration Database object.
/// </summary>
public class Element
{
private BaseStorage _storage;
private Guid _obj;
private ApplicationType _appType;
private int _identifier;
private ElementValue _value;
internal Element(BaseStorage storage, Guid obj, ApplicationType appType, int identifier)
{
_storage = storage;
_obj = obj;
_appType = appType;
_identifier = identifier;
}
/// <summary>
/// Gets the friendly name of the element, if any.
/// </summary>
public string FriendlyName
{
get
{
return "{" + IdentifierToName(_appType, _identifier) + "}";
}
}
/// <summary>
/// Gets the class of the element.
/// </summary>
public ElementClass Class
{
get { return (ElementClass)((_identifier >> 28) & 0xF); }
}
/// <summary>
/// Gets the element's format.
/// </summary>
public ElementFormat Format
{
get { return (ElementFormat)((_identifier >> 24) & 0xF); }
}
/// <summary>
/// Gets or sets the element's value.
/// </summary>
public ElementValue Value
{
get
{
if (_value == null)
{
_value = LoadValue();
}
return _value;
}
set
{
if (Format != value.Format)
{
throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, "Attempt to assign {1} value to {0} format element", Format, value.Format));
}
_value = value;
WriteValue();
}
}
/// <summary>
/// Gets the element's id as a hex string.
/// </summary>
/// <returns>A hex string.</returns>
public override string ToString()
{
return _identifier.ToString("X8", CultureInfo.InvariantCulture);
}
private static string IdentifierToName(ApplicationType appType, int identifier)
{
ElementClass idClass = GetClass(identifier);
if (idClass == ElementClass.Library)
{
switch (identifier)
{
case 0x11000001: return "device";
case 0x12000002: return "path";
case 0x12000004: return "description";
case 0x12000005: return "locale";
case 0x14000006: return "inherit";
case 0x15000007: return "truncatememory";
case 0x14000008: return "recoverysequence";
case 0x16000009: return "recoveryenabled";
case 0x1700000A: return "badmemorylist";
case 0x1600000B: return "badmemoryaccess";
case 0x1500000C: return "firstmegabytepolicy";
case 0x16000010: return "bootdebug";
case 0x15000011: return "debugtype";
case 0x15000012: return "debugaddress";
case 0x15000013: return "debugport";
case 0x15000014: return "baudrate";
case 0x15000015: return "channel";
case 0x12000016: return "targetname";
case 0x16000017: return "noumex";
case 0x15000018: return "debugstart";
case 0x16000020: return "bootems";
case 0x15000022: return "emsport";
case 0x15000023: return "emsbaudrate";
case 0x12000030: return "loadoptions";
case 0x16000040: return "advancedoptions";
case 0x16000041: return "optionsedit";
case 0x15000042: return "keyringaddress";
case 0x16000046: return "graphicsmodedisabled";
case 0x15000047: return "configaccesspolicy";
case 0x16000048: return "nointegritychecks";
case 0x16000049: return "testsigning";
case 0x16000050: return "extendedinput";
case 0x15000051: return "initialconsoleinput";
}
}
else if (idClass == ElementClass.Application)
{
switch (appType)
{
case ApplicationType.FirmwareBootManager:
case ApplicationType.BootManager:
switch (identifier)
{
case 0x24000001: return "displayorder";
case 0x24000002: return "bootsequence";
case 0x23000003: return "default";
case 0x25000004: return "timeout";
case 0x26000005: return "resume";
case 0x23000006: return "resumeobject";
case 0x24000010: return "toolsdisplayorder";
case 0x26000020: return "displaybootmenu";
case 0x26000021: return "noerrordisplay";
case 0x21000022: return "bcddevice";
case 0x22000023: return "bcdfilepath";
case 0x27000030: return "customactions";
}
break;
case ApplicationType.OsLoader:
switch (identifier)
{
case 0x21000001: return "osdevice";
case 0x22000002: return "systemroot";
case 0x23000003: return "resumeobject";
case 0x26000010: return "detecthal";
case 0x22000011: return "kernel";
case 0x22000012: return "hal";
case 0x22000013: return "dbgtransport";
case 0x25000020: return "nx";
case 0x25000021: return "pae";
case 0x26000022: return "winpe";
case 0x26000024: return "nocrashautoreboot";
case 0x26000025: return "lastknowngood";
case 0x26000026: return "oslnointegritychecks";
case 0x26000027: return "osltestsigning";
case 0x26000030: return "nolowmem";
case 0x25000031: return "removememory";
case 0x25000032: return "increaseuserva";
case 0x25000033: return "perfmem";
case 0x26000040: return "vga";
case 0x26000041: return "quietboot";
case 0x26000042: return "novesa";
case 0x25000050: return "clustermodeaddressing";
case 0x26000051: return "usephysicaldestination";
case 0x25000052: return "restrictapiccluster";
case 0x26000060: return "onecpu";
case 0x25000061: return "numproc";
case 0x26000062: return "maxproc";
case 0x25000063: return "configflags";
case 0x26000070: return "usefirmwarepcisettings";
case 0x25000071: return "msi";
case 0x25000072: return "pciexpress";
case 0x25000080: return "safeboot";
case 0x26000081: return "safebootalternateshell";
case 0x26000090: return "bootlog";
case 0x26000091: return "sos";
case 0x260000A0: return "debug";
case 0x260000A1: return "halbreakpoint";
case 0x260000B0: return "ems";
case 0x250000C0: return "forcefailure";
case 0x250000C1: return "driverloadfailurepolicy";
case 0x250000E0: return "bootstatuspolicy";
}
break;
case ApplicationType.Resume:
switch (identifier)
{
case 0x21000001: return "filedevice";
case 0x22000002: return "filepath";
case 0x26000003: return "customsettings";
case 0x26000004: return "pae";
case 0x21000005: return "associatedosdevice";
case 0x26000006: return "debugoptionenabled";
}
break;
case ApplicationType.MemoryDiagnostics:
switch (identifier)
{
case 0x25000001: return "passcount";
case 0x25000002: return "testmix";
case 0x25000003: return "failurecount";
case 0x25000004: return "testtofail";
}
break;
case ApplicationType.NtLoader:
case ApplicationType.SetupLoader:
switch (identifier)
{
case 0x22000001: return "bpbstring";
}
break;
case ApplicationType.Startup:
switch (identifier)
{
case 0x26000001: return "pxesoftreboot";
case 0x22000002: return "applicationname";
}
break;
}
}
else if (idClass == ElementClass.Device)
{
switch (identifier)
{
case 0x35000001: return "ramdiskimageoffset";
case 0x35000002: return "ramdisktftpclientport";
case 0x31000003: return "ramdisksdidevice";
case 0x32000004: return "ramdisksdipath";
case 0x35000005: return "ramdiskimagelength";
case 0x36000006: return "exportascd";
case 0x35000007: return "ramdisktftpblocksize";
}
}
else if (idClass == ElementClass.Hidden)
{
switch (identifier)
{
case 0x45000001: return "devicetype";
case 0x42000002: return "apprelativepath";
case 0x42000003: return "ramdiskdevicerelativepath";
case 0x46000004: return "omitosloaderelements";
case 0x46000010: return "recoveryos";
}
}
return identifier.ToString("X8", CultureInfo.InvariantCulture);
}
private static ElementClass GetClass(int identifier)
{
return (ElementClass)((identifier >> 28) & 0xF);
}
private ElementValue LoadValue()
{
switch (Format)
{
case ElementFormat.Boolean:
return new BooleanElementValue(_storage.GetBinary(_obj, _identifier));
case ElementFormat.Device:
return new DeviceElementValue(_storage.GetBinary(_obj, _identifier));
case ElementFormat.Guid:
return new GuidElementValue(_storage.GetString(_obj, _identifier));
case ElementFormat.GuidList:
return new GuidListElementValue(_storage.GetMultiString(_obj, _identifier));
case ElementFormat.Integer:
return new IntegerElementValue(_storage.GetBinary(_obj, _identifier));
case ElementFormat.IntegerList:
return new IntegerListElementValue(_storage.GetBinary(_obj, _identifier));
case ElementFormat.String:
return new StringElementValue(_storage.GetString(_obj, _identifier));
default:
throw new NotImplementedException("Unknown element format: " + Format);
}
}
private void WriteValue()
{
switch (_value.Format)
{
case ElementFormat.Boolean:
_storage.SetBinary(_obj, _identifier, ((BooleanElementValue)_value).GetBytes());
break;
case ElementFormat.Device:
_storage.SetBinary(_obj, _identifier, ((DeviceElementValue)_value).GetBytes());
break;
case ElementFormat.GuidList:
_storage.SetMultiString(_obj, _identifier, ((GuidListElementValue)_value).GetGuidStrings());
break;
case ElementFormat.Integer:
_storage.SetBinary(_obj, _identifier, ((IntegerElementValue)_value).GetBytes());
break;
case ElementFormat.IntegerList:
_storage.SetBinary(_obj, _identifier, ((IntegerListElementValue)_value).GetBytes());
break;
case ElementFormat.Guid:
case ElementFormat.String:
_storage.SetString(_obj, _identifier, _value.ToString());
break;
default:
throw new NotImplementedException("Unknown element format: " + Format);
}
}
}
}
-70
View File
@@ -1,70 +0,0 @@
//
// Copyright (c) 2008-2011, Kenneth Bell
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
namespace DiscUtils.BootConfig
{
/// <summary>
/// The known formats used to store BCD values.
/// </summary>
public enum ElementFormat
{
/// <summary>
/// Unknown format.
/// </summary>
None = 0,
/// <summary>
/// A block device, or partition.
/// </summary>
Device = 1,
/// <summary>
/// A unicode string.
/// </summary>
String = 2,
/// <summary>
/// A Globally Unique Identifier (GUID).
/// </summary>
Guid = 3,
/// <summary>
/// A GUID list.
/// </summary>
GuidList = 4,
/// <summary>
/// An integer.
/// </summary>
Integer = 5,
/// <summary>
/// A boolean.
/// </summary>
Boolean = 6,
/// <summary>
/// An integer list.
/// </summary>
IntegerList = 7
}
}
-138
View File
@@ -1,138 +0,0 @@
//
// Copyright (c) 2008-2011, Kenneth Bell
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
namespace DiscUtils.BootConfig
{
using System;
using System.Globalization;
/// <summary>
/// The value of an element.
/// </summary>
public abstract class ElementValue
{
/// <summary>
/// Gets the format of the value.
/// </summary>
public abstract ElementFormat Format { get; }
/// <summary>
/// Gets the parent object (only for Device values).
/// </summary>
public virtual Guid ParentObject
{
get { return Guid.Empty; }
}
/// <summary>
/// Gets a value representing a device (aka partition).
/// </summary>
/// <param name="parentObject">Object containing detailed information about the device.</param>
/// <param name="physicalVolume">The volume to represent.</param>
/// <returns>The value as an object.</returns>
public static ElementValue ForDevice(Guid parentObject, PhysicalVolumeInfo physicalVolume)
{
return new DeviceElementValue(parentObject, physicalVolume);
}
/// <summary>
/// Gets a value representing the logical boot device.
/// </summary>
/// <returns>The boot pseudo-device as an object.</returns>
public static ElementValue ForBootDevice()
{
return new DeviceElementValue();
}
/// <summary>
/// Gets a value representing a string value.
/// </summary>
/// <param name="value">The value to convert.</param>
/// <returns>The value as an object.</returns>
public static ElementValue ForString(string value)
{
return new StringElementValue(value);
}
/// <summary>
/// Gets a value representing an integer value.
/// </summary>
/// <param name="value">The value to convert.</param>
/// <returns>The value as an object.</returns>
public static ElementValue ForInteger(long value)
{
return new IntegerElementValue((ulong)value);
}
/// <summary>
/// Gets a value representing an integer list value.
/// </summary>
/// <param name="values">The value to convert.</param>
/// <returns>The value as an object.</returns>
public static ElementValue ForIntegerList(long[] values)
{
ulong[] ulValues = new ulong[values.Length];
for (int i = 0; i < values.Length; ++i)
{
ulValues[i] = (ulong)values[i];
}
return new IntegerListElementValue(ulValues);
}
/// <summary>
/// Gets a value representing a boolean value.
/// </summary>
/// <param name="value">The value to convert.</param>
/// <returns>The value as an object.</returns>
public static ElementValue ForBoolean(bool value)
{
return new BooleanElementValue(value);
}
/// <summary>
/// Gets a value representing a GUID value.
/// </summary>
/// <param name="value">The value to convert.</param>
/// <returns>The value as an object.</returns>
public static ElementValue ForGuid(Guid value)
{
return new GuidElementValue(value.ToString("B"));
}
/// <summary>
/// Gets a value representing a GUID list value.
/// </summary>
/// <param name="values">The value to convert.</param>
/// <returns>The value as an object.</returns>
public static ElementValue ForGuidList(Guid[] values)
{
string[] strValues = new string[values.Length];
for (int i = 0; i < values.Length; ++i)
{
strValues[i] = values[i].ToString("B");
}
return new GuidListElementValue(strValues);
}
}
}
-54
View File
@@ -1,54 +0,0 @@
//
// Copyright (c) 2008-2011, Kenneth Bell
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
namespace DiscUtils.BootConfig
{
using System;
using System.Collections.Generic;
using System.Text;
/// <summary>
/// Indicates the type of objects that can inherit from an object.
/// </summary>
public enum InheritType
{
/// <summary>
/// Undefined value.
/// </summary>
None = 0x0,
/// <summary>
/// Any type of object may inherit from this object.
/// </summary>
AnyObject = 0x1,
/// <summary>
/// Only Application objects may inherit from this object.
/// </summary>
ApplicationObjects = 0x2,
/// <summary>
/// Only Device objects may inherit from this object.
/// </summary>
DeviceObjects = 0x3
}
}
@@ -1,63 +0,0 @@
//
// Copyright (c) 2008-2011, Kenneth Bell
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
namespace DiscUtils.BootConfig
{
using System;
using System.Globalization;
internal class IntegerElementValue : ElementValue
{
private ulong _value;
public IntegerElementValue(byte[] value)
{
// Actual bytes stored may be less than 8
byte[] buffer = new byte[8];
Array.Copy(value, buffer, value.Length);
_value = Utilities.ToUInt64LittleEndian(buffer, 0);
}
public IntegerElementValue(ulong value)
{
_value = value;
}
public override ElementFormat Format
{
get { return ElementFormat.Integer; }
}
public override string ToString()
{
return string.Format(CultureInfo.InvariantCulture, "{0}", _value);
}
internal byte[] GetBytes()
{
byte[] bytes = new byte[8];
Utilities.WriteBytesLittleEndian(_value, bytes, 0);
return bytes;
}
}
}
@@ -1,82 +0,0 @@
//
// Copyright (c) 2008-2011, Kenneth Bell
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
namespace DiscUtils.BootConfig
{
using System.Globalization;
internal class IntegerListElementValue : ElementValue
{
private ulong[] _values;
public IntegerListElementValue(byte[] value)
{
_values = new ulong[value.Length / 8];
for (int i = 0; i < _values.Length; ++i)
{
_values[i] = Utilities.ToUInt64LittleEndian(value, i * 8);
}
}
public IntegerListElementValue(ulong[] values)
{
_values = values;
}
public override ElementFormat Format
{
get { return ElementFormat.IntegerList; }
}
public override string ToString()
{
if (_values == null || _values.Length == 0)
{
return "<none>";
}
string result = string.Empty;
for (int i = 0; i < _values.Length; ++i)
{
if (i != 0)
{
result += " ";
}
result += _values[i].ToString("X16", CultureInfo.InvariantCulture);
}
return result;
}
internal byte[] GetBytes()
{
byte[] bytes = new byte[_values.Length * 8];
for (int i = 0; i < _values.Length; ++i)
{
Utilities.WriteBytesLittleEndian(_values[i], bytes, i * 8);
}
return bytes;
}
}
}
-149
View File
@@ -1,149 +0,0 @@
//
// Copyright (c) 2008-2011, Kenneth Bell
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
namespace DiscUtils.BootConfig
{
using System;
using System.Globalization;
internal class PartitionRecord : DeviceRecord
{
public int PartitionType { get; set; }
public byte[] DiskIdentity { get; set; }
public byte[] PartitionIdentity { get; set; }
public override int Size
{
get { return 0x48; }
}
public override void GetBytes(byte[] data, int offset)
{
WriteHeader(data, offset);
if (Type == 5)
{
Array.Clear(data, offset + 0x10, 0x38);
}
else if (Type == 6)
{
Utilities.WriteBytesLittleEndian(PartitionType, data, offset + 0x24);
if (PartitionType == 1)
{
Array.Copy(DiskIdentity, 0, data, offset + 0x28, 4);
Array.Copy(PartitionIdentity, 0, data, offset + 0x10, 8);
}
else if (PartitionType == 0)
{
Array.Copy(DiskIdentity, 0, data, offset + 0x28, 16);
Array.Copy(PartitionIdentity, 0, data, offset + 0x10, 16);
}
else
{
throw new NotImplementedException("Unknown partition type: " + PartitionType);
}
}
else
{
throw new NotImplementedException("Unknown device type: " + Type);
}
}
public override string ToString()
{
if (Type == 5)
{
return "<boot device>";
}
else if (Type == 6)
{
if (PartitionType == 1)
{
return string.Format(
CultureInfo.InvariantCulture,
"(disk:{0:X2}{1:X2}{2:X2}{3:X2} part-offset:{4})",
DiskIdentity[0],
DiskIdentity[1],
DiskIdentity[2],
DiskIdentity[3],
Utilities.ToUInt64LittleEndian(PartitionIdentity, 0));
}
else
{
Guid diskGuid = Utilities.ToGuidLittleEndian(DiskIdentity, 0);
Guid partitionGuid = Utilities.ToGuidLittleEndian(PartitionIdentity, 0);
return string.Format(CultureInfo.InvariantCulture, "(disk:{0} partition:{1})", diskGuid, partitionGuid);
}
}
else if (Type == 8)
{
return "custom:<unknown>";
}
else
{
return "<unknown>";
}
}
protected override void DoParse(byte[] data, int offset)
{
base.DoParse(data, offset);
if (Type == 5)
{
// Nothing to do - just empty...
}
else if (Type == 6)
{
PartitionType = Utilities.ToInt32LittleEndian(data, offset + 0x24);
if (PartitionType == 1)
{
// BIOS disk
DiskIdentity = new byte[4];
Array.Copy(data, offset + 0x28, DiskIdentity, 0, 4);
PartitionIdentity = new byte[8];
Array.Copy(data, offset + 0x10, PartitionIdentity, 0, 8);
}
else if (PartitionType == 0)
{
// GPT disk
DiskIdentity = new byte[16];
Array.Copy(data, offset + 0x28, DiskIdentity, 0, 16);
PartitionIdentity = new byte[16];
Array.Copy(data, offset + 0x10, PartitionIdentity, 0, 16);
}
else
{
throw new NotImplementedException("Unknown partition type: " + PartitionType);
}
}
else
{
throw new NotImplementedException("Unknown device type: " + Type);
}
}
}
}
-168
View File
@@ -1,168 +0,0 @@
//
// Copyright (c) 2008-2011, Kenneth Bell
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
namespace DiscUtils.BootConfig
{
using System;
using System.Collections.Generic;
using DiscUtils.Registry;
/// <summary>
/// Represents a Boot Configuration Database store (i.e. a BCD file).
/// </summary>
public class Store
{
private BaseStorage _store;
/// <summary>
/// Initializes a new instance of the Store class.
/// </summary>
/// <param name="key">The registry key that is the root of the configuration database.</param>
public Store(RegistryKey key)
{
_store = new DiscUtilsRegistryStorage(key);
}
/// <summary>
/// Gets the objects within the store.
/// </summary>
public IEnumerable<BcdObject> Objects
{
get
{
foreach (var obj in _store.EnumerateObjects())
{
yield return new BcdObject(_store, obj);
}
}
}
/// <summary>
/// Initializes a new Boot Configuration Database.
/// </summary>
/// <param name="root">The registry key at the root of the database.</param>
/// <returns>The BCD store.</returns>
public static Store Initialize(RegistryKey root)
{
RegistryKey descKey = root.CreateSubKey("Description");
descKey.SetValue("KeyName", "BCD00000001");
root.CreateSubKey("Objects");
return new Store(root);
}
/// <summary>
/// Gets an object from the store.
/// </summary>
/// <param name="id">The identity of the object.</param>
/// <returns>The requested object, or <c>null</c>.</returns>
public BcdObject GetObject(Guid id)
{
if (_store.ObjectExists(id))
{
return new BcdObject(_store, id);
}
else
{
return null;
}
}
/// <summary>
/// Creates a specific object.
/// </summary>
/// <param name="id">The identity of the object to create.</param>
/// <param name="type">The object's type.</param>
/// <returns>The object representing the new application.</returns>
public BcdObject CreateObject(Guid id, int type)
{
_store.CreateObject(id, type);
return new BcdObject(_store, id);
}
/// <summary>
/// Creates an application object.
/// </summary>
/// <param name="imageType">The image type of the application.</param>
/// <param name="appType">The application's type.</param>
/// <returns>The object representing the new application.</returns>
public BcdObject CreateApplication(ApplicationImageType imageType, ApplicationType appType)
{
Guid obj = _store.CreateObject(Guid.NewGuid(), BcdObject.MakeApplicationType(imageType, appType));
return new BcdObject(_store, obj);
}
/// <summary>
/// Creates an application object.
/// </summary>
/// <param name="id">The identity of the object to create.</param>
/// <param name="imageType">The image type of the application.</param>
/// <param name="appType">The application's type.</param>
/// <returns>The object representing the new application.</returns>
public BcdObject CreateApplication(Guid id, ApplicationImageType imageType, ApplicationType appType)
{
Guid obj = _store.CreateObject(id, BcdObject.MakeApplicationType(imageType, appType));
return new BcdObject(_store, obj);
}
/// <summary>
/// Creates an 'inherit' object that contains common settings.
/// </summary>
/// <param name="inheritType">The type of object the settings apply to.</param>
/// <returns>The object representing the new settings.</returns>
public BcdObject CreateInherit(InheritType inheritType)
{
Guid obj = _store.CreateObject(Guid.NewGuid(), BcdObject.MakeInheritType(inheritType));
return new BcdObject(_store, obj);
}
/// <summary>
/// Creates an 'inherit' object that contains common settings.
/// </summary>
/// <param name="id">The identity of the object to create.</param>
/// <param name="inheritType">The type of object the settings apply to.</param>
/// <returns>The object representing the new settings.</returns>
public BcdObject CreateInherit(Guid id, InheritType inheritType)
{
Guid obj = _store.CreateObject(id, BcdObject.MakeInheritType(inheritType));
return new BcdObject(_store, obj);
}
/// <summary>
/// Creates a new device object, representing a partition.
/// </summary>
/// <returns>The object representing the new device.</returns>
public BcdObject CreateDevice()
{
Guid obj = _store.CreateObject(Guid.NewGuid(), 0x30000000);
return new BcdObject(_store, obj);
}
/// <summary>
/// Removes an object.
/// </summary>
/// <param name="id">The identity of the object to remove.</param>
public void RemoveObject(Guid id)
{
_store.DeleteObject(id);
}
}
}
-618
View File
@@ -1,618 +0,0 @@
//
// Copyright (c) 2008-2011, Kenneth Bell
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
//
// Symbolic names of BCD Elements taken from Geoff Chappell's website:
// http://www.geoffchappell.com/viewer.htm?doc=notes/windows/boot/bcd/elements.htm
//
//
namespace DiscUtils.BootConfig
{
/// <summary>
/// Enumeration of known BCD elements.
/// </summary>
public enum WellKnownElement : int
{
/// <summary>
/// Not specified.
/// </summary>
None = 0,
/// <summary>
/// Device containing the application.
/// </summary>
LibraryApplicationDevice = 0x11000001,
/// <summary>
/// Path to the application.
/// </summary>
LibraryApplicationPath = 0x12000002,
/// <summary>
/// Description of the object.
/// </summary>
LibraryDescription = 0x12000004,
/// <summary>
/// Preferred locale of the object.
/// </summary>
LibraryPreferredLocale = 0x12000005,
/// <summary>
/// Objects containing elements inherited by the object.
/// </summary>
LibraryInheritedObjects = 0x14000006,
/// <summary>
/// Upper bound on physical addresses used by Windows.
/// </summary>
LibraryTruncatePhysicalMemory = 0x15000007,
/// <summary>
/// List of objects, indicating recovery sequence.
/// </summary>
LibraryRecoverySequence = 0x14000008,
/// <summary>
/// Enables auto recovery.
/// </summary>
LibraryAutoRecoveryEnabled = 0x16000009,
/// <summary>
/// List of bad memory regions.
/// </summary>
LibraryBadMemoryList = 0x1700000A,
/// <summary>
/// Allow use of bad memory regions.
/// </summary>
LibraryAllowBadMemoryAccess = 0x1600000B,
/// <summary>
/// Policy on use of first mega-byte of physical RAM.
/// </summary>
/// <remarks>0 = UseNone, 1 = UseAll, 2 = UsePrivate.</remarks>
LibraryFirstMegaBytePolicy = 0x1500000C,
/// <summary>
/// Debugger enabled.
/// </summary>
LibraryDebuggerEnabled = 0x16000010,
/// <summary>
/// Debugger type.
/// </summary>
/// <remarks>0 = Serial, 1 = 1394, 2 = USB.</remarks>
LibraryDebuggerType = 0x15000011,
/// <summary>
/// Debugger serial port address.
/// </summary>
LibraryDebuggerSerialAddress = 0x15000012,
/// <summary>
/// Debugger serial port.
/// </summary>
LibraryDebuggerSerialPort = 0x15000013,
/// <summary>
/// Debugger serial port baud rate.
/// </summary>
LibraryDebuggerSerialBaudRate = 0x15000014,
/// <summary>
/// Debugger 1394 channel.
/// </summary>
LibraryDebugger1394Channel = 0x15000015,
/// <summary>
/// Debugger USB target name.
/// </summary>
LibraryDebuggerUsbTargetName = 0x12000016,
/// <summary>
/// Debugger ignores user mode exceptions.
/// </summary>
LibraryDebuggerIgnoreUserModeExceptions = 0x16000017,
/// <summary>
/// Debugger start policy.
/// </summary>
/// <remarks>0 = Active, 1 = AutoEnable, 2 = Disable.</remarks>
LibraryDebuggerStartPolicy = 0x15000018,
/// <summary>
/// Emergency Management System enabled.
/// </summary>
LibraryEmergencyManagementSystemEnabled = 0x16000020,
/// <summary>
/// Emergency Management System serial port.
/// </summary>
LibraryEmergencyManagementSystemPort = 0x15000022,
/// <summary>
/// Emergency Management System baud rate.
/// </summary>
LibraryEmergencyManagementSystemBaudRate = 0x15000023,
/// <summary>
/// Load options.
/// </summary>
LibraryLoadOptions = 0x12000030,
/// <summary>
/// Displays advanced options.
/// </summary>
LibraryDisplayAdvancedOptions = 0x16000040,
/// <summary>
/// Displays UI to edit advanced options.
/// </summary>
LibraryDisplayOptionsEdit = 0x16000041,
/// <summary>
/// FVE (Full Volume Encryption - aka BitLocker?) KeyRing address.
/// </summary>
LibraryFveKeyRingAddress = 0x16000042,
/// <summary>
/// Device to contain Boot Status Log.
/// </summary>
LibraryBootStatusLogDevice = 0x11000043,
/// <summary>
/// Path to Boot Status Log.
/// </summary>
LibraryBootStatusLogFile = 0x12000044,
/// <summary>
/// Whether to append to the existing Boot Status Log.
/// </summary>
LibraryBootStatusLogAppend = 0x12000045,
/// <summary>
/// Disables graphics mode.
/// </summary>
LibraryGraphicsModeDisabled = 0x16000046,
/// <summary>
/// Configure access policy.
/// </summary>
/// <remarks>0 = default, 1 = DisallowMmConfig.</remarks>
LibraryConfigAccessPolicy = 0x15000047,
/// <summary>
/// Disables integrity checks.
/// </summary>
LibraryDisableIntegrityChecks = 0x16000048,
/// <summary>
/// Allows pre-release signatures (test signing).
/// </summary>
LibraryAllowPrereleaseSignatures = 0x16000049,
/// <summary>
/// Console extended input.
/// </summary>
LibraryConsoleExtendedInput = 0x16000050,
/// <summary>
/// Initial console input.
/// </summary>
LibraryInitialConsoleInput = 0x15000051,
/// <summary>
/// Application display order.
/// </summary>
BootMgrDisplayOrder = 0x24000001,
/// <summary>
/// Application boot sequence.
/// </summary>
BootMgrBootSequence = 0x24000002,
/// <summary>
/// Default application.
/// </summary>
BootMgrDefaultObject = 0x23000003,
/// <summary>
/// User input timeout.
/// </summary>
BootMgrTimeout = 0x25000004,
/// <summary>
/// Attempt to resume from hibernated state.
/// </summary>
BootMgrAttemptResume = 0x26000005,
/// <summary>
/// The resume application.
/// </summary>
BootMgrResumeObject = 0x23000006,
/// <summary>
/// The tools display order.
/// </summary>
BootMgrToolsDisplayOrder = 0x24000010,
/// <summary>
/// Displays the boot menu.
/// </summary>
BootMgrDisplayBootMenu = 0x26000020,
/// <summary>
/// No error display.
/// </summary>
BootMgrNoErrorDisplay = 0x26000021,
/// <summary>
/// The BCD device.
/// </summary>
BootMgrBcdDevice = 0x21000022,
/// <summary>
/// The BCD file path.
/// </summary>
BootMgrBcdFilePath = 0x22000023,
/// <summary>
/// The custom actions list.
/// </summary>
BootMgrCustomActionsList = 0x27000030,
/// <summary>
/// Device containing the Operating System.
/// </summary>
OsLoaderOsDevice = 0x21000001,
/// <summary>
/// System root on the OS device.
/// </summary>
OsLoaderSystemRoot = 0x22000002,
/// <summary>
/// The resume application associated with this OS.
/// </summary>
OsLoaderAssociatedResumeObject = 0x23000003,
/// <summary>
/// Auto-detect the correct kernel &amp; HAL.
/// </summary>
OsLoaderDetectKernelAndHal = 0x26000010,
/// <summary>
/// The filename of the kernel.
/// </summary>
OsLoaderKernelPath = 0x22000011,
/// <summary>
/// The filename of the HAL.
/// </summary>
OsLoaderHalPath = 0x22000012,
/// <summary>
/// The debug transport path.
/// </summary>
OsLoaderDebugTransportPath = 0x22000013,
/// <summary>
/// NX (No-Execute) policy.
/// </summary>
/// <remarks>0 = OptIn, 1 = OptOut, 2 = AlwaysOff, 3 = AlwaysOn.</remarks>
OsLoaderNxPolicy = 0x25000020,
/// <summary>
/// PAE policy.
/// </summary>
/// <remarks>0 = default, 1 = ForceEnable, 2 = ForceDisable.</remarks>
OsLoaderPaePolicy = 0x25000021,
/// <summary>
/// WinPE mode.
/// </summary>
OsLoaderWinPeMode = 0x26000022,
/// <summary>
/// Disable automatic reboot on OS crash.
/// </summary>
OsLoaderDisableCrashAutoReboot = 0x26000024,
/// <summary>
/// Use the last known good settings.
/// </summary>
OsLoaderUseLastGoodSettings = 0x26000025,
/// <summary>
/// Disable integrity checks.
/// </summary>
OsLoaderDisableIntegrityChecks = 0x26000026,
/// <summary>
/// Allows pre-release signatures (test signing).
/// </summary>
OsLoaderAllowPrereleaseSignatures = 0x26000027,
/// <summary>
/// Loads all executables above 4GB boundary.
/// </summary>
OsLoaderNoLowMemory = 0x26000030,
/// <summary>
/// Excludes a given amount of memory from use by Windows.
/// </summary>
OsLoaderRemoveMemory = 0x25000031,
/// <summary>
/// Increases the User Mode virtual address space.
/// </summary>
OsLoaderIncreaseUserVa = 0x25000032,
/// <summary>
/// Size of buffer (in MB) for perfomance data logging.
/// </summary>
OsLoaderPerformanceDataMemory = 0x25000033,
/// <summary>
/// Uses the VGA display driver.
/// </summary>
OsLoaderUseVgaDriver = 0x26000040,
/// <summary>
/// Quiet boot.
/// </summary>
OsLoaderDisableBootDisplay = 0x26000041,
/// <summary>
/// Disables use of the VESA BIOS.
/// </summary>
OsLoaderDisableVesaBios = 0x26000042,
/// <summary>
/// Maximum processors in a single APIC cluster.
/// </summary>
OsLoaderClusterModeAddressing = 0x25000050,
/// <summary>
/// Forces the physical APIC to be used.
/// </summary>
OsLoaderUsePhysicalDestination = 0x26000051,
/// <summary>
/// The largest APIC cluster number the system can use.
/// </summary>
OsLoaderRestrictApicCluster = 0x25000052,
/// <summary>
/// Forces only the boot processor to be used.
/// </summary>
OsLoaderUseBootProcessorOnly = 0x26000060,
/// <summary>
/// The number of processors to be used.
/// </summary>
OsLoaderNumberOfProcessors = 0x25000061,
/// <summary>
/// Use maximum number of processors.
/// </summary>
OsLoaderForceMaxProcessors = 0x26000062,
/// <summary>
/// Processor specific configuration flags.
/// </summary>
OsLoaderProcessorConfigurationFlags = 0x25000063,
/// <summary>
/// Uses BIOS-configured PCI resources.
/// </summary>
OsLoaderUseFirmwarePciSettings = 0x26000070,
/// <summary>
/// Message Signalled Interrupt setting.
/// </summary>
OsLoaderMsiPolicy = 0x25000071,
/// <summary>
/// PCE Express Policy.
/// </summary>
OsLoaderPciExpressPolicy = 0x25000072,
/// <summary>
/// The safe boot option.
/// </summary>
/// <remarks>0 = Minimal, 1 = Network, 2 = DsRepair.</remarks>
OsLoaderSafeBoot = 0x25000080,
/// <summary>
/// Loads the configured alternate shell during a safe boot.
/// </summary>
OsLoaderSafeBootAlternateShell = 0x26000081,
/// <summary>
/// Enables boot log.
/// </summary>
OsLoaderBootLogInitialization = 0x26000090,
/// <summary>
/// Displays diagnostic information during boot.
/// </summary>
OsLoaderVerboseObjectLoadMode = 0x26000091,
/// <summary>
/// Enables the kernel debugger.
/// </summary>
OsLoaderKernelDebuggerEnabled = 0x260000A0,
/// <summary>
/// Causes the kernal to halt early during boot.
/// </summary>
OsLoaderDebuggerHalBreakpoint = 0x260000A1,
/// <summary>
/// Enables Windows Emergency Management System.
/// </summary>
OsLoaderEmsEnabled = 0x260000B0,
/// <summary>
/// Forces a failure on boot.
/// </summary>
OsLoaderForceFailure = 0x250000C0,
/// <summary>
/// The OS failure policy.
/// </summary>
OsLoaderDriverLoadFailurePolicy = 0x250000C1,
/// <summary>
/// The OS boot status policy.
/// </summary>
OsLoaderBootStatusPolicy = 0x250000E0,
/// <summary>
/// The device containing the hibernation file.
/// </summary>
ResumeHiberFileDevice = 0x21000001,
/// <summary>
/// The path to the hibernation file.
/// </summary>
ResumeHiberFilePath = 0x22000002,
/// <summary>
/// Allows resume loader to use custom settings.
/// </summary>
ResumeUseCustomSettings = 0x26000003,
/// <summary>
/// PAE settings for resume application.
/// </summary>
ResumePaeMode = 0x26000004,
/// <summary>
/// An MS-DOS device with containing resume application.
/// </summary>
ResumeAssociatedDosDevice = 0x21000005,
/// <summary>
/// Enables debug option.
/// </summary>
ResumeDebugOptionEnabled = 0x26000006,
/// <summary>
/// The number of iterations to run.
/// </summary>
MemDiagPassCount = 0x25000001,
/// <summary>
/// The test mix.
/// </summary>
MemDiagTestMix = 0x25000002,
/// <summary>
/// The failure count.
/// </summary>
MemDiagFailureCount = 0x25000003,
/// <summary>
/// The tests to fail.
/// </summary>
MemDiagTestToFail = 0x25000004,
/// <summary>
/// BPB string.
/// </summary>
LoaderBpbString = 0x22000001,
/// <summary>
/// Causes a soft PXE reboot.
/// </summary>
StartupPxeSoftReboot = 0x26000001,
/// <summary>
/// PXE application name.
/// </summary>
StartupPxeApplicationName = 0x22000002,
/// <summary>
/// Offset of the RAM disk image.
/// </summary>
DeviceRamDiskImageOffset = 0x35000001,
/// <summary>
/// Client port for TFTP.
/// </summary>
DeviceRamDiskTftpClientPort = 0x35000002,
/// <summary>
/// Device containing the SDI file.
/// </summary>
DeviceRamDiskSdiDevice = 0x31000003,
/// <summary>
/// Path to the SDI file.
/// </summary>
DeviceRamDiskSdiPath = 0x32000004,
/// <summary>
/// Length of the RAM disk image.
/// </summary>
DeviceRamDiskRamDiskImageLength = 0x35000005,
/// <summary>
/// Exports the image as a CD.
/// </summary>
DeviceRamDiskExportAsCd = 0x36000006,
/// <summary>
/// The TFTP transfer block size.
/// </summary>
DeviceRamDiskTftpBlockSize = 0x35000007,
/// <summary>
/// The device type.
/// </summary>
SetupDeviceType = 0x45000001,
/// <summary>
/// The application relative path.
/// </summary>
SetupAppRelativePath = 0x42000002,
/// <summary>
/// The device relative path.
/// </summary>
SetupRamDiskDeviceRelativePath = 0x42000003,
/// <summary>
/// Omit OS loader elements.
/// </summary>
SetupOmitOsLoaderElements = 0x46000004,
/// <summary>
/// Recovery OS flag.
/// </summary>
SetupRecoveryOs = 0x46000010,
}
}
-120
View File
@@ -1,120 +0,0 @@
//
// Copyright (c) 2008-2011, Kenneth Bell
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
namespace DiscUtils
{
using System;
using System.Collections.Generic;
/// <summary>
/// Abstract base class for implementations of IBuffer.
/// </summary>
public abstract class Buffer : MarshalByRefObject, IBuffer
{
/// <summary>
/// Gets a value indicating whether this buffer can be read.
/// </summary>
public abstract bool CanRead { get; }
/// <summary>
/// Gets a value indicating whether this buffer can be modified.
/// </summary>
public abstract bool CanWrite { get; }
/// <summary>
/// Gets the current capacity of the buffer, in bytes.
/// </summary>
public abstract long Capacity { get; }
/// <summary>
/// Gets the parts of the stream that are stored.
/// </summary>
/// <remarks>This may be an empty enumeration if all bytes are zero.</remarks>
public virtual IEnumerable<StreamExtent> Extents
{
get
{
return GetExtentsInRange(0, Capacity);
}
}
/// <summary>
/// Reads from the buffer into a byte array.
/// </summary>
/// <param name="pos">The offset within the buffer to start reading.</param>
/// <param name="buffer">The destination byte array.</param>
/// <param name="offset">The start offset within the destination buffer.</param>
/// <param name="count">The number of bytes to read.</param>
/// <returns>The actual number of bytes read.</returns>
public abstract int Read(long pos, byte[] buffer, int offset, int count);
/// <summary>
/// Writes a byte array into the buffer.
/// </summary>
/// <param name="pos">The start offset within the buffer.</param>
/// <param name="buffer">The source byte array.</param>
/// <param name="offset">The start offset within the source byte array.</param>
/// <param name="count">The number of bytes to write.</param>
public abstract void Write(long pos, byte[] buffer, int offset, int count);
/// <summary>
/// Clears bytes from the buffer.
/// </summary>
/// <param name="pos">The start offset within the buffer.</param>
/// <param name="count">The number of bytes to clear.</param>
/// <remarks>
/// <para>Logically equivalent to writing <c>count</c> null/zero bytes to the buffer, some
/// implementations determine that some (or all) of the range indicated is not actually
/// stored. There is no direct, automatic, correspondence to clearing bytes and them
/// not being represented as an 'extent' - for example, the implementation of the underlying
/// stream may not permit fine-grained extent storage.</para>
/// <para>It is always safe to call this method to 'zero-out' a section of a buffer, regardless of
/// the underlying buffer implementation.</para>
/// </remarks>
public virtual void Clear(long pos, int count)
{
Write(pos, new byte[count], 0, count);
}
/// <summary>
/// Flushes all data to the underlying storage.
/// </summary>
/// <remarks>The default behaviour, implemented by this class, is to take no action.</remarks>
public virtual void Flush()
{
}
/// <summary>
/// Sets the capacity of the buffer, truncating if appropriate.
/// </summary>
/// <param name="value">The desired capacity of the buffer.</param>
public abstract void SetCapacity(long value);
/// <summary>
/// Gets the parts of a buffer that are stored, within a specified range.
/// </summary>
/// <param name="start">The offset of the first byte of interest.</param>
/// <param name="count">The number of bytes of interest.</param>
/// <returns>An enumeration of stream extents, indicating stored bytes.</returns>
public abstract IEnumerable<StreamExtent> GetExtentsInRange(long start, long count);
}
}
-218
View File
@@ -1,218 +0,0 @@
//
// Copyright (c) 2008-2011, Kenneth Bell
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
namespace DiscUtils
{
using System.Collections.Generic;
using System.IO;
/// <summary>
/// Converts a Buffer into a Stream.
/// </summary>
public class BufferStream : SparseStream
{
private IBuffer _buffer;
private FileAccess _access;
private long _position;
/// <summary>
/// Initializes a new instance of the BufferStream class.
/// </summary>
/// <param name="buffer">The buffer to use.</param>
/// <param name="access">The access permitted to clients.</param>
public BufferStream(IBuffer buffer, FileAccess access)
{
_buffer = buffer;
_access = access;
}
/// <summary>
/// Gets an indication of whether read access is permitted.
/// </summary>
public override bool CanRead
{
get { return _access != FileAccess.Write; }
}
/// <summary>
/// Gets an indication of whether seeking is permitted.
/// </summary>
public override bool CanSeek
{
get { return true; }
}
/// <summary>
/// Gets an indication of whether write access is permitted.
/// </summary>
public override bool CanWrite
{
get { return _access != FileAccess.Read; }
}
/// <summary>
/// Gets the length of the stream (the capacity of the underlying buffer).
/// </summary>
public override long Length
{
get { return _buffer.Capacity; }
}
/// <summary>
/// Gets and sets the current position within the stream.
/// </summary>
public override long Position
{
get { return _position; }
set { _position = value; }
}
/// <summary>
/// Gets the stored extents within the sparse stream.
/// </summary>
public override IEnumerable<StreamExtent> Extents
{
get { return _buffer.Extents; }
}
/// <summary>
/// Flushes all data to the underlying storage.
/// </summary>
public override void Flush()
{
}
/// <summary>
/// Reads a number of bytes from the stream.
/// </summary>
/// <param name="buffer">The destination buffer.</param>
/// <param name="offset">The start offset within the destination buffer.</param>
/// <param name="count">The number of bytes to read.</param>
/// <returns>The number of bytes read.</returns>
public override int Read(byte[] buffer, int offset, int count)
{
if (!CanRead)
{
throw new IOException("Attempt to read from write-only stream");
}
Utilities.AssertBufferParameters(buffer, offset, count);
int numRead = _buffer.Read(_position, buffer, offset, count);
_position += numRead;
return numRead;
}
/// <summary>
/// Changes the current stream position.
/// </summary>
/// <param name="offset">The origin-relative stream position.</param>
/// <param name="origin">The origin for the stream position.</param>
/// <returns>The new stream position.</returns>
public override long Seek(long offset, SeekOrigin origin)
{
long effectiveOffset = offset;
if (origin == SeekOrigin.Current)
{
effectiveOffset += _position;
}
else if (origin == SeekOrigin.End)
{
effectiveOffset += _buffer.Capacity;
}
if (effectiveOffset < 0)
{
throw new IOException("Attempt to move before beginning of disk");
}
else
{
_position = effectiveOffset;
return _position;
}
}
/// <summary>
/// Sets the length of the stream (the underlying buffer's capacity).
/// </summary>
/// <param name="value">The new length of the stream.</param>
public override void SetLength(long value)
{
_buffer.SetCapacity(value);
}
/// <summary>
/// Writes a buffer to the stream.
/// </summary>
/// <param name="buffer">The buffer to write.</param>
/// <param name="offset">The starting offset within buffer.</param>
/// <param name="count">The number of bytes to write.</param>
public override void Write(byte[] buffer, int offset, int count)
{
if (!CanWrite)
{
throw new IOException("Attempt to write to read-only stream");
}
Utilities.AssertBufferParameters(buffer, offset, count);
_buffer.Write(_position, buffer, offset, count);
_position += count;
}
/// <summary>
/// Clears bytes from the stream.
/// </summary>
/// <param name="count">The number of bytes (from the current position) to clear.</param>
/// <remarks>
/// <para>Logically equivalent to writing <c>count</c> null/zero bytes to the stream, some
/// implementations determine that some (or all) of the range indicated is not actually
/// stored. There is no direct, automatic, correspondence to clearing bytes and them
/// not being represented as an 'extent' - for example, the implementation of the underlying
/// stream may not permit fine-grained extent storage.</para>
/// <para>It is always safe to call this method to 'zero-out' a section of a stream, regardless of
/// the underlying stream implementation.</para>
/// </remarks>
public override void Clear(int count)
{
if (!CanWrite)
{
throw new IOException("Attempt to erase bytes in a read-only stream");
}
_buffer.Clear(_position, count);
_position += count;
}
/// <summary>
/// Gets the parts of a stream that are stored, within a specified range.
/// </summary>
/// <param name="start">The offset of the first byte of interest.</param>
/// <param name="count">The number of bytes of interest.</param>
/// <returns>An enumeration of stream extents, indicating stored bytes.</returns>
public override IEnumerable<StreamExtent> GetExtentsInRange(long start, long count)
{
return _buffer.GetExtentsInRange(start, count);
}
}
}
-77
View File
@@ -1,77 +0,0 @@
//
// Copyright (c) 2008-2011, Kenneth Bell
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
namespace DiscUtils
{
using System;
internal class BuilderBufferExtent : BuilderExtent
{
private bool _fixedBuffer;
private byte[] _buffer;
public BuilderBufferExtent(long start, long length)
: base(start, length)
{
}
public BuilderBufferExtent(long start, byte[] buffer)
: base(start, buffer.Length)
{
_fixedBuffer = true;
_buffer = buffer;
}
public override void Dispose()
{
}
internal override void PrepareForRead()
{
if (!_fixedBuffer)
{
_buffer = GetBuffer();
}
}
internal override int Read(long diskOffset, byte[] block, int offset, int count)
{
int startOffset = (int)(diskOffset - Start);
int numBytes = (int)Math.Min(Length - startOffset, count);
Array.Copy(_buffer, startOffset, block, offset, numBytes);
return numBytes;
}
internal override void DisposeReadState()
{
if (!_fixedBuffer)
{
_buffer = null;
}
}
protected virtual byte[] GetBuffer()
{
throw new NotSupportedException("Derived class should implement");
}
}
}
-69
View File
@@ -1,69 +0,0 @@
//
// Copyright (c) 2008-2011, Kenneth Bell
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
namespace DiscUtils
{
using System;
using System.Collections.Generic;
internal abstract class BuilderExtent : IDisposable
{
private long _start;
private long _length;
public BuilderExtent(long start, long length)
{
_start = start;
_length = length;
}
/// <summary>
/// Gets the parts of the stream that are stored.
/// </summary>
/// <remarks>This may be an empty enumeration if all bytes are zero.</remarks>
public virtual IEnumerable<StreamExtent> StreamExtents
{
get
{
return new StreamExtent[] { new StreamExtent(Start, Length) };
}
}
internal long Start
{
get { return _start; }
}
internal long Length
{
get { return _length; }
}
public abstract void Dispose();
internal abstract void PrepareForRead();
internal abstract int Read(long diskOffset, byte[] block, int offset, int count);
internal abstract void DisposeReadState();
}
}
-74
View File
@@ -1,74 +0,0 @@
//
// Copyright (c) 2008-2011, Kenneth Bell
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
namespace DiscUtils
{
using System;
using System.Collections.Generic;
using System.Text;
internal class BuilderSparseStreamExtent : BuilderExtent
{
private SparseStream _stream;
private Ownership _ownership;
public BuilderSparseStreamExtent(long start, SparseStream stream)
: this(start, stream, Ownership.None)
{
}
public BuilderSparseStreamExtent(long start, SparseStream stream, Ownership ownership)
: base(start, stream.Length)
{
_stream = stream;
_ownership = ownership;
}
public override IEnumerable<StreamExtent> StreamExtents
{
get { return StreamExtent.Offset(_stream.Extents, Start); }
}
public override void Dispose()
{
if (_stream != null && _ownership == Ownership.Dispose)
{
_stream.Dispose();
_stream = null;
}
}
internal override void PrepareForRead()
{
}
internal override int Read(long diskOffset, byte[] block, int offset, int count)
{
_stream.Position = diskOffset - Start;
return _stream.Read(block, offset, count);
}
internal override void DisposeReadState()
{
}
}
}
-327
View File
@@ -1,327 +0,0 @@
//
// Copyright (c) 2008-2011, Kenneth Bell
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
namespace DiscUtils
{
using System;
using System.Collections.Generic;
using System.IO;
internal class BuiltStream : SparseStream
{
private Stream _baseStream;
private long _length;
private List<BuilderExtent> _extents;
private BuilderExtent _currentExtent;
private long _position;
public BuiltStream(long length, List<BuilderExtent> extents)
{
_baseStream = new ZeroStream(length);
_length = length;
_extents = extents;
// Make sure the extents are sorted, so binary searches will work.
_extents.Sort(new ExtentStartComparer());
}
public override bool CanRead
{
get { return true; }
}
public override bool CanSeek
{
get { return true; }
}
public override bool CanWrite
{
get { return false; }
}
public override long Length
{
get { return _length; }
}
public override long Position
{
get { return _position; }
set { _position = value; }
}
public override IEnumerable<StreamExtent> Extents
{
get
{
foreach (var extent in _extents)
{
foreach (var streamExtent in extent.StreamExtents)
{
yield return streamExtent;
}
}
}
}
public override void Flush()
{
return;
}
public override int Read(byte[] buffer, int offset, int count)
{
if (_position >= _length)
{
return 0;
}
int totalRead = 0;
while (totalRead < count && _position < _length)
{
// If current region is outside the area of interest, clean it up
if (_currentExtent != null && (_position < _currentExtent.Start || _position >= _currentExtent.Start + _currentExtent.Length))
{
_currentExtent.DisposeReadState();
_currentExtent = null;
}
// If we need to find a new region, look for it
if (_currentExtent == null)
{
using (SearchExtent searchExtent = new SearchExtent(_position))
{
int idx = _extents.BinarySearch(searchExtent, new ExtentRangeComparer());
if (idx >= 0)
{
BuilderExtent extent = _extents[idx];
extent.PrepareForRead();
_currentExtent = extent;
}
}
}
int numRead = 0;
// If the block is outside any known extent, defer to base stream.
if (_currentExtent == null)
{
_baseStream.Position = _position;
BuilderExtent nextExtent = FindNext(_position);
if (nextExtent != null)
{
numRead = _baseStream.Read(buffer, offset + totalRead, (int)Math.Min(count - totalRead, nextExtent.Start - _position));
}
else
{
numRead = _baseStream.Read(buffer, offset + totalRead, count - totalRead);
}
}
else
{
numRead = _currentExtent.Read(_position, buffer, offset + totalRead, count - totalRead);
}
_position += numRead;
totalRead += numRead;
}
return totalRead;
}
public override long Seek(long offset, SeekOrigin origin)
{
long newPos = offset;
if (origin == SeekOrigin.Current)
{
newPos += _position;
}
else if (origin == SeekOrigin.End)
{
newPos += _length;
}
_position = newPos;
return newPos;
}
public override void SetLength(long value)
{
throw new NotSupportedException();
}
public override void Write(byte[] buffer, int offset, int count)
{
throw new NotSupportedException();
}
protected override void Dispose(bool disposing)
{
try
{
if (disposing)
{
if (_currentExtent != null)
{
_currentExtent.DisposeReadState();
_currentExtent = null;
}
if (_baseStream != null)
{
_baseStream.Dispose();
_baseStream = null;
}
}
}
finally
{
base.Dispose(disposing);
}
}
private BuilderExtent FindNext(long pos)
{
int min = 0;
int max = _extents.Count - 1;
if (_extents.Count == 0 || (_extents[_extents.Count - 1].Start + _extents[_extents.Count - 1].Length) <= pos)
{
return null;
}
while (true)
{
if (min >= max)
{
return _extents[min];
}
int mid = (max + min) / 2;
if (_extents[mid].Start < pos)
{
min = mid + 1;
}
else if (_extents[mid].Start > pos)
{
max = mid;
}
else
{
return _extents[mid];
}
}
}
private class SearchExtent : BuilderExtent
{
public SearchExtent(long pos)
: base(pos, 1)
{
}
public override void Dispose()
{
}
internal override void PrepareForRead()
{
// Not valid to use this 'dummy' extent for actual construction
throw new NotSupportedException();
}
internal override int Read(long diskOffset, byte[] block, int offset, int count)
{
// Not valid to use this 'dummy' extent for actual construction
throw new NotSupportedException();
}
internal override void DisposeReadState()
{
// Not valid to use this 'dummy' extent for actual construction
throw new NotSupportedException();
}
}
private class ExtentRangeComparer : IComparer<BuilderExtent>
{
public int Compare(BuilderExtent x, BuilderExtent y)
{
if (x == null)
{
throw new ArgumentNullException("x");
}
if (y == null)
{
throw new ArgumentNullException("y");
}
if (x.Start + x.Length <= y.Start)
{
// x < y, with no intersection
return -1;
}
else if (x.Start >= y.Start + y.Length)
{
// x > y, with no intersection
return 1;
}
// x intersects y
return 0;
}
}
private class ExtentStartComparer : IComparer<BuilderExtent>
{
public int Compare(BuilderExtent x, BuilderExtent y)
{
if (x == null)
{
throw new ArgumentNullException("x");
}
if (y == null)
{
throw new ArgumentNullException("y");
}
long val = x.Start - y.Start;
if (val < 0)
{
return -1;
}
else if (val > 0)
{
return 1;
}
else
{
return 0;
}
}
}
}
}
-112
View File
@@ -1,112 +0,0 @@
//
// Copyright (c) 2008-2011, Kenneth Bell
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
namespace DiscUtils
{
/// <summary>
/// Class whose instances represent a CHS (Cylinder, Head, Sector) address on a disk.
/// </summary>
/// <remarks>Instances of this class are immutable.</remarks>
public sealed class ChsAddress
{
/// <summary>
/// The address of the first sector on any disk.
/// </summary>
public static readonly ChsAddress First = new ChsAddress(0, 0, 1);
private int _cylinder;
private int _head;
private int _sector;
/// <summary>
/// Initializes a new instance of the ChsAddress class.
/// </summary>
/// <param name="cylinder">The number of cylinders of the disk.</param>
/// <param name="head">The number of heads (aka platters) of the disk.</param>
/// <param name="sector">The number of sectors per track/cylinder of the disk.</param>
public ChsAddress(int cylinder, int head, int sector)
{
_cylinder = cylinder;
_head = head;
_sector = sector;
}
/// <summary>
/// Gets the cylinder number (zero-based).
/// </summary>
public int Cylinder
{
get { return _cylinder; }
}
/// <summary>
/// Gets the head (zero-based).
/// </summary>
public int Head
{
get { return _head; }
}
/// <summary>
/// Gets the sector number (one-based).
/// </summary>
public int Sector
{
get { return _sector; }
}
/// <summary>
/// Determines if this object is equivalent to another.
/// </summary>
/// <param name="obj">The object to test against.</param>
/// <returns><c>true</c> if the <paramref name="obj"/> is equivalent, else <c>false</c>.</returns>
public override bool Equals(object obj)
{
if (obj == null || obj.GetType() != GetType())
{
return false;
}
ChsAddress other = (ChsAddress)obj;
return _cylinder == other._cylinder && _head == other._head && _sector == other._sector;
}
/// <summary>
/// Calculates the hash code for this object.
/// </summary>
/// <returns>The hash code.</returns>
public override int GetHashCode()
{
return _cylinder.GetHashCode() ^ _head.GetHashCode() ^ _sector.GetHashCode();
}
/// <summary>
/// Gets a string representation of this object, in the form (C/H/S).
/// </summary>
/// <returns>The string representation.</returns>
public override string ToString()
{
return "(" + _cylinder + "/" + _head + "/" + _sector + ")";
}
}
}
-128
View File
@@ -1,128 +0,0 @@
//
// Copyright (c) 2008-2011, Kenneth Bell
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
namespace DiscUtils
{
using System;
using System.Collections.Generic;
using System.Text;
/// <summary>
/// Enumeration of possible cluster roles.
/// </summary>
/// <remarks>A cluster may be in more than one role.</remarks>
[Flags]
public enum ClusterRoles
{
/// <summary>
/// Unknown, or unspecified role.
/// </summary>
None = 0x00,
/// <summary>
/// Cluster is free.
/// </summary>
Free = 0x01,
/// <summary>
/// Cluster is in use by a normal file.
/// </summary>
DataFile = 0x02,
/// <summary>
/// Cluster is in use by a system file.
/// </summary>
/// <remarks>This isn't a file marked with the 'system' attribute,
/// rather files that form part of the file system namespace but also
/// form part of the file system meta-data.</remarks>
SystemFile = 0x04,
/// <summary>
/// Cluster is in use for meta-data.
/// </summary>
Metadata = 0x08,
/// <summary>
/// Cluster contains the boot region.
/// </summary>
BootArea = 0x10,
/// <summary>
/// Cluster is marked bad.
/// </summary>
Bad = 0x20,
}
/// <summary>
/// Class that identifies the role of each cluster in a file system.
/// </summary>
public sealed class ClusterMap
{
private ClusterRoles[] _clusterToRole;
private object[] _clusterToFileId;
private Dictionary<object, string[]> _fileIdToPaths;
internal ClusterMap(ClusterRoles[] clusterToRole, object[] clusterToFileId, Dictionary<object, string[]> fileIdToPaths)
{
_clusterToRole = clusterToRole;
_clusterToFileId = clusterToFileId;
_fileIdToPaths = fileIdToPaths;
}
/// <summary>
/// Gets the role of a cluster within the file system.
/// </summary>
/// <param name="cluster">The cluster to inspect.</param>
/// <returns>The clusters role (or roles).</returns>
public ClusterRoles GetRole(long cluster)
{
if (_clusterToRole == null || _clusterToRole.Length < cluster)
{
return ClusterRoles.None;
}
else
{
return _clusterToRole[cluster];
}
}
/// <summary>
/// Converts a cluster to a list of file names.
/// </summary>
/// <param name="cluster">The cluster to inspect.</param>
/// <returns>A list of paths that map to the cluster.</returns>
/// <remarks>A list is returned because on file systems with the notion of
/// hard links, a cluster may correspond to multiple directory entries.</remarks>
public string[] ClusterToPaths(long cluster)
{
if ((GetRole(cluster) & (ClusterRoles.DataFile | ClusterRoles.SystemFile)) != 0)
{
object fileId = _clusterToFileId[cluster];
return _fileIdToPaths[fileId];
}
else
{
return new string[0];
}
}
}
}
-93
View File
@@ -1,93 +0,0 @@
//
// Copyright (c) 2008-2011, Kenneth Bell
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
namespace DiscUtils.Compression
{
using System;
/// <summary>
/// Implementation of the Adler-32 checksum algorithm.
/// </summary>
public class Adler32
{
private uint _a;
private uint _b;
/// <summary>
/// Initializes a new instance of the Adler32 class.
/// </summary>
public Adler32()
{
_a = 1;
}
/// <summary>
/// Gets the checksum of all data processed so far.
/// </summary>
public int Value
{
get { return (int)(_b << 16 | _a); }
}
/// <summary>
/// Provides data that should be checksummed.
/// </summary>
/// <param name="buffer">Buffer containing the data to checksum.</param>
/// <param name="offset">Offset of the first byte to checksum.</param>
/// <param name="count">The number of bytes to checksum.</param>
/// <remarks>
/// Call this method repeatedly until all checksummed
/// data has been processed.
/// </remarks>
public void Process(byte[] buffer, int offset, int count)
{
if (buffer == null)
{
throw new ArgumentNullException("buffer");
}
if (offset < 0 || offset > buffer.Length)
{
throw new ArgumentException("Offset outside of array bounds", "offset");
}
if (count < 0 || offset + count > buffer.Length)
{
throw new ArgumentException("Array index out of bounds", "count");
}
int processed = 0;
while (processed < count)
{
int innerEnd = Math.Min(count, processed + 2000);
while (processed < innerEnd)
{
_a += buffer[processed++];
_b += _a;
}
_a %= 65521;
_b %= 65521;
}
}
}
}
-144
View File
@@ -1,144 +0,0 @@
//
// Copyright (c) 2008-2011, Kenneth Bell
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
//
// Based on "libbzip2", Copyright (C) 1996-2007 Julian R Seward.
//
namespace DiscUtils.Compression
{
using System.IO;
internal class BZip2BlockDecoder
{
private InverseBurrowsWheeler _inverseBurrowsWheeler;
private uint _crc;
public BZip2BlockDecoder(int blockSize)
{
_inverseBurrowsWheeler = new InverseBurrowsWheeler(blockSize);
}
public uint Crc
{
get { return _crc; }
}
public int Process(BitStream bitstream, byte[] outputBuffer, int outputBufferOffset)
{
_crc = 0;
for (int i = 0; i < 4; ++i)
{
_crc = (_crc << 8) | bitstream.Read(8);
}
bool rand = bitstream.Read(1) != 0;
int origPtr = (int)bitstream.Read(24);
int thisBlockSize = ReadBuffer(bitstream, outputBuffer, outputBufferOffset);
_inverseBurrowsWheeler.OriginalIndex = origPtr;
_inverseBurrowsWheeler.Process(outputBuffer, outputBufferOffset, thisBlockSize, outputBuffer, outputBufferOffset);
if (rand)
{
BZip2Randomizer randomizer = new BZip2Randomizer();
randomizer.Process(outputBuffer, outputBufferOffset, thisBlockSize, outputBuffer, outputBufferOffset);
}
return thisBlockSize;
}
private static int ReadBuffer(BitStream bitstream, byte[] buffer, int offset)
{
// The MTF state
int numInUse = 0;
MoveToFront moveFrontTransform = new MoveToFront();
bool[] inUseGroups = new bool[16];
for (int i = 0; i < 16; ++i)
{
inUseGroups[i] = bitstream.Read(1) != 0;
}
for (int i = 0; i < 256; ++i)
{
if (inUseGroups[i / 16])
{
if (bitstream.Read(1) != 0)
{
moveFrontTransform.Set(numInUse, (byte)i);
numInUse++;
}
}
}
// Initialize 'virtual' Huffman tree from bitstream
BZip2CombinedHuffmanTrees huffmanTree = new BZip2CombinedHuffmanTrees(bitstream, numInUse + 2);
// Main loop reading data
int readBytes = 0;
while (true)
{
uint symbol = huffmanTree.NextSymbol();
if (symbol < 2)
{
// RLE, with length stored in a binary-style format
uint runLength = 0;
int bitShift = 0;
while (symbol < 2)
{
runLength += (symbol + 1) << bitShift;
bitShift++;
symbol = huffmanTree.NextSymbol();
}
byte b = moveFrontTransform.Head;
while (runLength > 0)
{
buffer[offset + readBytes] = b;
++readBytes;
--runLength;
}
}
if (symbol <= numInUse)
{
// Single byte
byte b = moveFrontTransform.GetAndMove((int)symbol - 1);
buffer[offset + readBytes] = b;
++readBytes;
}
else if (symbol == numInUse + 1)
{
// End of block marker
return readBytes;
}
else
{
throw new InvalidDataException("Invalid symbol from Huffman table");
}
}
}
}
}
@@ -1,135 +0,0 @@
//
// Copyright (c) 2008-2011, Kenneth Bell
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
//
// Based on "libbzip2", Copyright (C) 1996-2007 Julian R Seward.
//
namespace DiscUtils.Compression
{
using System.IO;
/// <summary>
/// Represents scheme used by BZip2 where multiple Huffman trees are used as a
/// virtual Huffman tree, with a logical selector every 50 bits in the bit stream.
/// </summary>
internal class BZip2CombinedHuffmanTrees
{
private BitStream _bitstream;
private byte[] _selectors;
private HuffmanTree[] _trees;
private HuffmanTree _activeTree;
private int _symbolsToNextSelector;
private int _nextSelector;
public BZip2CombinedHuffmanTrees(BitStream bitstream, int maxSymbols)
{
_bitstream = bitstream;
Initialize(maxSymbols);
}
public uint NextSymbol()
{
if (_symbolsToNextSelector == 0)
{
_symbolsToNextSelector = 50;
_activeTree = _trees[_selectors[_nextSelector]];
_nextSelector++;
}
_symbolsToNextSelector--;
return _activeTree.NextSymbol(_bitstream);
}
private void Initialize(int maxSymbols)
{
int numTrees = (int)_bitstream.Read(3);
if (numTrees < 2 || numTrees > 6)
{
throw new InvalidDataException("Invalid number of tables");
}
int numSelectors = (int)_bitstream.Read(15);
if (numSelectors < 1)
{
throw new InvalidDataException("Invalid number of selectors");
}
_selectors = new byte[numSelectors];
MoveToFront mtf = new MoveToFront(numTrees, true);
for (int i = 0; i < numSelectors; ++i)
{
_selectors[i] = mtf.GetAndMove(CountSetBits(numTrees));
}
_trees = new HuffmanTree[numTrees];
for (int t = 0; t < numTrees; ++t)
{
uint[] lengths = new uint[maxSymbols];
uint len = _bitstream.Read(5);
for (int i = 0; i < maxSymbols; ++i)
{
if (len < 1 || len > 20)
{
throw new InvalidDataException("Invalid length constructing Huffman tree");
}
while (_bitstream.Read(1) != 0)
{
len = (_bitstream.Read(1) == 0) ? len + 1 : len - 1;
if (len < 1 || len > 20)
{
throw new InvalidDataException("Invalid length constructing Huffman tree");
}
}
lengths[i] = len;
}
_trees[t] = new HuffmanTree(lengths);
}
_symbolsToNextSelector = 0;
_nextSelector = 0;
}
private byte CountSetBits(int max)
{
byte val = 0;
while (_bitstream.Read(1) != 0)
{
val++;
if (val >= max)
{
throw new InvalidDataException("Exceeded max number of consecutive bits");
}
}
return val;
}
}
}
-349
View File
@@ -1,349 +0,0 @@
//
// Copyright (c) 2008-2011, Kenneth Bell
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
//
// Based on "libbzip2", Copyright (C) 1996-2007 Julian R Seward.
//
namespace DiscUtils.Compression
{
using System;
using System.IO;
/// <summary>
/// Implementation of a BZip2 decoder.
/// </summary>
public sealed class BZip2DecoderStream : Stream
{
private long _position;
private Stream _compressedStream;
private Ownership _ownsCompressed;
private BitStream _bitstream;
private BZip2RleStream _rleStream;
private BZip2BlockDecoder _blockDecoder;
private Crc32 _calcBlockCrc;
private byte[] _blockBuffer;
private uint _blockCrc;
private uint _compoundCrc;
private uint _calcCompoundCrc;
private bool _eof;
/// <summary>
/// Initializes a new instance of the BZip2DecoderStream class.
/// </summary>
/// <param name="stream">The compressed input stream.</param>
/// <param name="ownsStream">Whether ownership of stream passes to the new instance.</param>
public BZip2DecoderStream(Stream stream, Ownership ownsStream)
{
_compressedStream = stream;
_ownsCompressed = ownsStream;
_bitstream = new BigEndianBitStream(new BufferedStream(stream));
// The Magic BZh
byte[] magic = new byte[3];
magic[0] = (byte)_bitstream.Read(8);
magic[1] = (byte)_bitstream.Read(8);
magic[2] = (byte)_bitstream.Read(8);
if (magic[0] != 0x42 || magic[1] != 0x5A || magic[2] != 0x68)
{
throw new InvalidDataException("Bad magic at start of stream");
}
// The size of the decompression blocks in multiples of 100,000
int blockSize = (int)_bitstream.Read(8) - 0x30;
if (blockSize < 1 || blockSize > 9)
{
throw new InvalidDataException("Unexpected block size in header: " + blockSize);
}
blockSize *= 100000;
_rleStream = new BZip2RleStream();
_blockDecoder = new BZip2BlockDecoder(blockSize);
_blockBuffer = new byte[blockSize];
if (ReadBlock() == 0)
{
_eof = true;
}
}
/// <summary>
/// Gets an indication of whether read access is permitted.
/// </summary>
public override bool CanRead
{
get { return true; }
}
/// <summary>
/// Gets an indication of whether seeking is permitted.
/// </summary>
public override bool CanSeek
{
get { return false; }
}
/// <summary>
/// Gets an indication of whether write access is permitted.
/// </summary>
public override bool CanWrite
{
get { return false; }
}
/// <summary>
/// Gets the length of the stream (the capacity of the underlying buffer).
/// </summary>
public override long Length
{
get { throw new NotSupportedException(); }
}
/// <summary>
/// Gets and sets the current position within the stream.
/// </summary>
public override long Position
{
get { return _position; }
set { throw new NotSupportedException(); }
}
/// <summary>
/// Flushes all data to the underlying storage.
/// </summary>
public override void Flush()
{
throw new NotSupportedException();
}
/// <summary>
/// Reads a number of bytes from the stream.
/// </summary>
/// <param name="buffer">The destination buffer.</param>
/// <param name="offset">The start offset within the destination buffer.</param>
/// <param name="count">The number of bytes to read.</param>
/// <returns>The number of bytes read.</returns>
public override int Read(byte[] buffer, int offset, int count)
{
if (buffer == null)
{
throw new ArgumentNullException("buffer");
}
if (buffer.Length < offset + count)
{
throw new ArgumentException("Buffer smaller than declared");
}
if (offset < 0)
{
throw new ArgumentException("Offset less than zero", "offset");
}
if (count < 0)
{
throw new ArgumentException("Count less than zero", "count");
}
if (_eof)
{
throw new IOException("Attempt to read beyond end of stream");
}
if (count == 0)
{
return 0;
}
int numRead = _rleStream.Read(buffer, offset, count);
if (numRead == 0)
{
// If there was an existing block, check it's crc.
if (_calcBlockCrc != null)
{
if (_blockCrc != _calcBlockCrc.Value)
{
throw new InvalidDataException("Decompression failed - block CRC mismatch");
}
_calcCompoundCrc = ((_calcCompoundCrc << 1) | (_calcCompoundCrc >> 31)) ^ _blockCrc;
}
// Read a new block (if any), if none - check the overall CRC before returning
if (ReadBlock() == 0)
{
_eof = true;
if (_calcCompoundCrc != _compoundCrc)
{
throw new InvalidDataException("Decompression failed - compound CRC");
}
return 0;
}
numRead = _rleStream.Read(buffer, offset, count);
}
_calcBlockCrc.Process(buffer, offset, numRead);
// Pre-read next block, so a client that knows the decompressed length will still
// have the overall CRC calculated.
if (_rleStream.AtEof)
{
// If there was an existing block, check it's crc.
if (_calcBlockCrc != null)
{
if (_blockCrc != _calcBlockCrc.Value)
{
throw new InvalidDataException("Decompression failed - block CRC mismatch");
}
}
_calcCompoundCrc = ((_calcCompoundCrc << 1) | (_calcCompoundCrc >> 31)) ^ _blockCrc;
if (ReadBlock() == 0)
{
_eof = true;
if (_calcCompoundCrc != _compoundCrc)
{
throw new InvalidDataException("Decompression failed - compound CRC mismatch");
}
return numRead;
}
}
_position += numRead;
return numRead;
}
/// <summary>
/// Changes the current stream position.
/// </summary>
/// <param name="offset">The origin-relative stream position.</param>
/// <param name="origin">The origin for the stream position.</param>
/// <returns>The new stream position.</returns>
public override long Seek(long offset, SeekOrigin origin)
{
throw new NotSupportedException();
}
/// <summary>
/// Sets the length of the stream (the underlying buffer's capacity).
/// </summary>
/// <param name="value">The new length of the stream.</param>
public override void SetLength(long value)
{
throw new NotSupportedException();
}
/// <summary>
/// Writes a buffer to the stream.
/// </summary>
/// <param name="buffer">The buffer to write.</param>
/// <param name="offset">The starting offset within buffer.</param>
/// <param name="count">The number of bytes to write.</param>
public override void Write(byte[] buffer, int offset, int count)
{
throw new NotSupportedException();
}
/// <summary>
/// Releases underlying resources.
/// </summary>
/// <param name="disposing">Whether this method is called from Dispose.</param>
protected override void Dispose(bool disposing)
{
try
{
if (disposing)
{
if (_compressedStream != null && _ownsCompressed == Ownership.Dispose)
{
_compressedStream.Dispose();
}
_compressedStream = null;
if (_rleStream != null)
{
_rleStream.Dispose();
_rleStream = null;
}
}
}
finally
{
base.Dispose(disposing);
}
}
private int ReadBlock()
{
ulong marker = ReadMarker();
if (marker == 0x314159265359)
{
int blockSize = _blockDecoder.Process(_bitstream, _blockBuffer, 0);
_rleStream.Reset(_blockBuffer, 0, blockSize);
_blockCrc = _blockDecoder.Crc;
_calcBlockCrc = new Crc32BigEndian(Crc32Algorithm.Common);
return blockSize;
}
else if (marker == 0x177245385090)
{
_compoundCrc = ReadUint();
return 0;
}
else
{
throw new InvalidDataException("Found invalid marker in stream");
}
}
private uint ReadUint()
{
uint val = 0;
for (int i = 0; i < 4; ++i)
{
val = (val << 8) | _bitstream.Read(8);
}
return val;
}
private ulong ReadMarker()
{
ulong marker = 0;
for (int i = 0; i < 6; ++i)
{
marker = (marker << 8) | _bitstream.Read(8);
}
return marker;
}
}
}
-124
View File
@@ -1,124 +0,0 @@
//
// Copyright (c) 2008-2011, Kenneth Bell
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
//
// Based on "libbzip2", Copyright (C) 1996-2007 Julian R Seward.
//
namespace DiscUtils.Compression
{
using System;
internal class BZip2Randomizer : DataBlockTransform
{
private static readonly int[] RandomVals =
{
619, 720, 127, 481, 931, 816, 813, 233, 566, 247,
985, 724, 205, 454, 863, 491, 741, 242, 949, 214,
733, 859, 335, 708, 621, 574, 73, 654, 730, 472,
419, 436, 278, 496, 867, 210, 399, 680, 480, 51,
878, 465, 811, 169, 869, 675, 611, 697, 867, 561,
862, 687, 507, 283, 482, 129, 807, 591, 733, 623,
150, 238, 59, 379, 684, 877, 625, 169, 643, 105,
170, 607, 520, 932, 727, 476, 693, 425, 174, 647,
73, 122, 335, 530, 442, 853, 695, 249, 445, 515,
909, 545, 703, 919, 874, 474, 882, 500, 594, 612,
641, 801, 220, 162, 819, 984, 589, 513, 495, 799,
161, 604, 958, 533, 221, 400, 386, 867, 600, 782,
382, 596, 414, 171, 516, 375, 682, 485, 911, 276,
98, 553, 163, 354, 666, 933, 424, 341, 533, 870,
227, 730, 475, 186, 263, 647, 537, 686, 600, 224,
469, 68, 770, 919, 190, 373, 294, 822, 808, 206,
184, 943, 795, 384, 383, 461, 404, 758, 839, 887,
715, 67, 618, 276, 204, 918, 873, 777, 604, 560,
951, 160, 578, 722, 79, 804, 96, 409, 713, 940,
652, 934, 970, 447, 318, 353, 859, 672, 112, 785,
645, 863, 803, 350, 139, 93, 354, 99, 820, 908,
609, 772, 154, 274, 580, 184, 79, 626, 630, 742,
653, 282, 762, 623, 680, 81, 927, 626, 789, 125,
411, 521, 938, 300, 821, 78, 343, 175, 128, 250,
170, 774, 972, 275, 999, 639, 495, 78, 352, 126,
857, 956, 358, 619, 580, 124, 737, 594, 701, 612,
669, 112, 134, 694, 363, 992, 809, 743, 168, 974,
944, 375, 748, 52, 600, 747, 642, 182, 862, 81,
344, 805, 988, 739, 511, 655, 814, 334, 249, 515,
897, 955, 664, 981, 649, 113, 974, 459, 893, 228,
433, 837, 553, 268, 926, 240, 102, 654, 459, 51,
686, 754, 806, 760, 493, 403, 415, 394, 687, 700,
946, 670, 656, 610, 738, 392, 760, 799, 887, 653,
978, 321, 576, 617, 626, 502, 894, 679, 243, 440,
680, 879, 194, 572, 640, 724, 926, 56, 204, 700,
707, 151, 457, 449, 797, 195, 791, 558, 945, 679,
297, 59, 87, 824, 713, 663, 412, 693, 342, 606,
134, 108, 571, 364, 631, 212, 174, 643, 304, 329,
343, 97, 430, 751, 497, 314, 983, 374, 822, 928,
140, 206, 73, 263, 980, 736, 876, 478, 430, 305,
170, 514, 364, 692, 829, 82, 855, 953, 676, 246,
369, 970, 294, 750, 807, 827, 150, 790, 288, 923,
804, 378, 215, 828, 592, 281, 565, 555, 710, 82,
896, 831, 547, 261, 524, 462, 293, 465, 502, 56,
661, 821, 976, 991, 658, 869, 905, 758, 745, 193,
768, 550, 608, 933, 378, 286, 215, 979, 792, 961,
61, 688, 793, 644, 986, 403, 106, 366, 905, 644,
372, 567, 466, 434, 645, 210, 389, 550, 919, 135,
780, 773, 635, 389, 707, 100, 626, 958, 165, 504,
920, 176, 193, 713, 857, 265, 203, 50, 668, 108,
645, 990, 626, 197, 510, 357, 358, 850, 858, 364,
936, 638
};
protected override bool BuffersMustNotOverlap
{
get { return false; }
}
protected override int DoProcess(byte[] input, int inputOffset, int inputCount, byte[] output, int outputOffset)
{
if (input != output || inputOffset != outputOffset)
{
Array.Copy(input, inputOffset, output, outputOffset, inputCount);
}
int randIndex = 1;
int nextByte = RandomVals[0] - 2;
while (nextByte < inputCount)
{
output[nextByte] ^= 1;
nextByte += RandomVals[randIndex++];
randIndex &= 0x1FF;
}
return inputCount;
}
protected override int MaxOutputCount(int inputCount)
{
return inputCount;
}
protected override int MinOutputCount(int inputCount)
{
return inputCount;
}
}
}
-161
View File
@@ -1,161 +0,0 @@
//
// Copyright (c) 2008-2011, Kenneth Bell
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
//
// Based on "libbzip2", Copyright (C) 1996-2007 Julian R Seward.
//
namespace DiscUtils.Compression
{
using System;
using System.IO;
internal class BZip2RleStream : Stream
{
private long _position;
private byte[] _blockBuffer;
private int _blockOffset;
private int _blockRemaining;
private int _numSame;
private byte _lastByte;
private int _runBytesOutstanding;
public BZip2RleStream()
{
}
public bool AtEof
{
get { return _runBytesOutstanding == 0 && _blockRemaining == 0; }
}
public override bool CanRead
{
get { return true; }
}
public override bool CanSeek
{
get { return false; }
}
public override bool CanWrite
{
get { return false; }
}
public override long Length
{
get { throw new NotSupportedException(); }
}
public override long Position
{
get { return _position; }
set { throw new NotSupportedException(); }
}
public void Reset(byte[] buffer, int offset, int count)
{
_position = 0;
_blockBuffer = buffer;
_blockOffset = offset;
_blockRemaining = count;
_numSame = -1;
_lastByte = 0;
_runBytesOutstanding = 0;
}
public override void Flush()
{
throw new NotSupportedException();
}
public override int Read(byte[] buffer, int offset, int count)
{
int numRead = 0;
while (numRead < count && _runBytesOutstanding > 0)
{
int runCount = Math.Min(_runBytesOutstanding, count);
for (int i = 0; i < runCount; ++i)
{
buffer[offset + numRead] = _lastByte;
}
_runBytesOutstanding -= runCount;
numRead += runCount;
}
while (numRead < count && _blockRemaining > 0)
{
byte b = _blockBuffer[_blockOffset];
++_blockOffset;
--_blockRemaining;
if (_numSame == 4)
{
int runCount = Math.Min(b, count - numRead);
for (int i = 0; i < runCount; ++i)
{
buffer[offset + numRead] = _lastByte;
numRead++;
}
_runBytesOutstanding = b - runCount;
_numSame = 0;
}
else
{
if (b != _lastByte || _numSame <= 0)
{
_lastByte = b;
_numSame = 0;
}
buffer[offset + numRead] = b;
numRead++;
_numSame++;
}
}
_position += numRead;
return numRead;
}
public override long Seek(long offset, SeekOrigin origin)
{
throw new NotSupportedException();
}
public override void SetLength(long value)
{
throw new NotSupportedException();
}
public override void Write(byte[] buffer, int offset, int count)
{
throw new NotSupportedException();
}
}
}
@@ -1,95 +0,0 @@
//
// Copyright (c) 2008-2011, Kenneth Bell
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
namespace DiscUtils.Compression
{
using System.IO;
/// <summary>
/// Converts a byte stream into a bit stream.
/// </summary>
internal class BigEndianBitStream : BitStream
{
private Stream _byteStream;
private uint _buffer;
private int _bufferAvailable;
private byte[] _readBuffer = new byte[2];
public BigEndianBitStream(Stream byteStream)
{
_byteStream = byteStream;
}
public override int MaxReadAhead
{
get { return 16; }
}
public override uint Read(int count)
{
if (count > 16)
{
uint result = Read(16) << (count - 16);
return result | Read(count - 16);
}
EnsureBufferFilled();
_bufferAvailable -= count;
uint mask = (uint)((1 << count) - 1);
return (uint)((_buffer >> _bufferAvailable) & mask);
}
public override uint Peek(int count)
{
EnsureBufferFilled();
uint mask = (uint)((1 << count) - 1);
return (uint)((_buffer >> (_bufferAvailable - count)) & mask);
}
public override void Consume(int count)
{
EnsureBufferFilled();
_bufferAvailable -= count;
}
private void EnsureBufferFilled()
{
if (_bufferAvailable < 16)
{
_readBuffer[0] = 0;
_readBuffer[1] = 0;
_byteStream.Read(_readBuffer, 0, 2);
_buffer = (uint)((uint)(_buffer << 16) | (uint)(_readBuffer[0] << 8) | (uint)_readBuffer[1]);
_bufferAvailable += 16;
}
}
}
}
-60
View File
@@ -1,60 +0,0 @@
//
// Copyright (c) 2008-2011, Kenneth Bell
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
namespace DiscUtils.Compression
{
/// <summary>
/// Base class for bit streams.
/// </summary>
/// <remarks>
/// The rules for conversion of a byte stream to a bit stream vary
/// between implementations.
/// </remarks>
internal abstract class BitStream
{
/// <summary>
/// Gets the maximum number of bits that can be peeked on the stream.
/// </summary>
public abstract int MaxReadAhead { get; }
/// <summary>
/// Reads bits from the stream.
/// </summary>
/// <param name="count">The number of bits to read.</param>
/// <returns>The bits as a UInt32.</returns>
public abstract uint Read(int count);
/// <summary>
/// Queries data from the stream.
/// </summary>
/// <param name="count">The number of bits to query.</param>
/// <returns>The bits as a UInt32.</returns>
/// <remarks>This method does not consume the bits (i.e. move the file pointer).</remarks>
public abstract uint Peek(int count);
/// <summary>
/// Consumes bits from the stream without returning them.
/// </summary>
/// <param name="count">The number of bits to consume.</param>
public abstract void Consume(int count);
}
}
-62
View File
@@ -1,62 +0,0 @@
//
// Copyright (c) 2008-2011, Kenneth Bell
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
namespace DiscUtils.Compression
{
/// <summary>
/// Base class for block compression algorithms.
/// </summary>
public abstract class BlockCompressor
{
/// <summary>
/// Gets or sets the block size parameter to the algorithm.
/// </summary>
/// <remarks>
/// Some algorithms may use this to control both compression and decompression, others may
/// only use it to control compression. Some may ignore it entirely.
/// </remarks>
public int BlockSize { get; set; }
/// <summary>
/// Compresses some data.
/// </summary>
/// <param name="source">The uncompressed input.</param>
/// <param name="sourceOffset">Offset of the input data in <c>source</c>.</param>
/// <param name="sourceLength">The amount of uncompressed data.</param>
/// <param name="compressed">The destination for the output compressed data.</param>
/// <param name="compressedOffset">Offset for the output data in <c>compressed</c>.</param>
/// <param name="compressedLength">The maximum size of the compressed data on input, and the actual size on output.</param>
/// <returns>Indication of success, or indication the data could not compress into the requested space.</returns>
public abstract CompressionResult Compress(byte[] source, int sourceOffset, int sourceLength, byte[] compressed, int compressedOffset, ref int compressedLength);
/// <summary>
/// Decompresses some data.
/// </summary>
/// <param name="source">The compressed input.</param>
/// <param name="sourceOffset">Offset of the input data in <c>source</c>.</param>
/// <param name="sourceLength">The amount of compressed data.</param>
/// <param name="decompressed">The destination for the output decompressed data.</param>
/// <param name="decompressedOffset">Offset for the output data in <c>decompressed</c>.</param>
/// <returns>The amount of decompressed data.</returns>
public abstract int Decompress(byte[] source, int sourceOffset, int sourceLength, byte[] decompressed, int decompressedOffset);
}
}
@@ -1,50 +0,0 @@
//
// Copyright (c) 2008-2011, Kenneth Bell
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
namespace DiscUtils.Compression
{
/// <summary>
/// Possible results of attempting to compress data.
/// </summary>
/// <remarks>
/// A compression routine <i>may</i> return <c>Compressed</c>, even if the data
/// was 'all zeros' or increased in size. The <c>AllZeros</c> and <c>Incompressible</c>
/// values are for algorithms that include special detection for these cases.
/// </remarks>
public enum CompressionResult
{
/// <summary>
/// The data compressed succesfully.
/// </summary>
Compressed,
/// <summary>
/// The data was all-zero's.
/// </summary>
AllZeros,
/// <summary>
/// The data was incompressible (could not fit into destination buffer).
/// </summary>
Incompressible
}
}
@@ -1,70 +0,0 @@
//
// Copyright (c) 2008-2011, Kenneth Bell
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
namespace DiscUtils.Compression
{
using System;
using System.Globalization;
internal abstract class DataBlockTransform
{
protected abstract bool BuffersMustNotOverlap { get; }
public int Process(byte[] input, int inputOffset, int inputCount, byte[] output, int outputOffset)
{
if (output.Length < outputOffset + (long)MinOutputCount(inputCount))
{
throw new ArgumentException(
string.Format(
CultureInfo.InvariantCulture,
"Output buffer to small, must be at least {0} bytes may need to be {1} bytes",
MinOutputCount(inputCount),
MaxOutputCount(inputCount)));
}
if (BuffersMustNotOverlap)
{
int maxOut = MaxOutputCount(inputCount);
if (input == output
&& (inputOffset + (long)inputCount > outputOffset)
&& (inputOffset <= outputOffset + (long)maxOut))
{
byte[] tempBuffer = new byte[maxOut];
int outCount = DoProcess(input, inputOffset, inputCount, tempBuffer, 0);
Array.Copy(tempBuffer, 0, output, outputOffset, outCount);
return outCount;
}
}
return DoProcess(input, inputOffset, inputCount, output, outputOffset);
}
protected abstract int DoProcess(byte[] input, int inputOffset, int inputCount, byte[] output, int outputOffset);
protected abstract int MaxOutputCount(int inputCount);
protected abstract int MinOutputCount(int inputCount);
}
}
-109
View File
@@ -1,109 +0,0 @@
//
// Copyright (c) 2008-2011, Kenneth Bell
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
namespace DiscUtils.Compression
{
/// <summary>
/// A canonical Huffman tree implementation.
/// </summary>
/// <remarks>
/// A lookup table is created that will take any bit sequence (max tree depth in length),
/// indicating the output symbol. In WIM files, in practice, no chunk exceeds 32768 bytes
/// in length, so we often end up generating a bigger lookup table than the data it's
/// encoding. This makes for exceptionally fast symbol lookups O(1), but is inefficient
/// overall.
/// </remarks>
internal sealed class HuffmanTree
{
private int _numBits; // Max bits per symbol
private int _numSymbols; // Max symbols
private uint[] _lengths;
private uint[] _buffer;
public HuffmanTree(uint[] lengths)
{
_lengths = lengths;
_numSymbols = lengths.Length;
uint maxLength = 0;
for (int i = 0; i < _lengths.Length; ++i)
{
if (_lengths[i] > maxLength)
{
maxLength = _lengths[i];
}
}
_numBits = (int)maxLength;
_buffer = new uint[1 << _numBits];
Build();
}
public uint[] Lengths
{
get
{
return _lengths;
}
}
public uint NextSymbol(BitStream bitStream)
{
uint symbol = _buffer[bitStream.Peek(_numBits)];
// We may have over-read, reset bitstream position
bitStream.Consume((int)_lengths[symbol]);
return symbol;
}
private void Build()
{
int position = 0;
// For each bit-length...
for (int i = 1; i <= _numBits; ++i)
{
// Check each symbol
for (uint symbol = 0; symbol < _numSymbols; ++symbol)
{
if (_lengths[symbol] == i)
{
int numToFill = 1 << (_numBits - i);
for (int n = 0; n < numToFill; ++n)
{
_buffer[position + n] = symbol;
}
position += numToFill;
}
}
}
for (int i = position; i < _buffer.Length; ++i)
{
_buffer[i] = uint.MaxValue;
}
}
}
}
@@ -1,97 +0,0 @@
//
// Copyright (c) 2008-2011, Kenneth Bell
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
namespace DiscUtils.Compression
{
using System;
internal sealed class InverseBurrowsWheeler : DataBlockTransform
{
private int[] _pointers;
private int[] _nextPos;
public InverseBurrowsWheeler(int bufferSize)
{
_pointers = new int[bufferSize];
_nextPos = new int[256];
}
public int OriginalIndex { get; set; }
protected override bool BuffersMustNotOverlap
{
get { return true; }
}
protected override int DoProcess(byte[] input, int inputOffset, int inputCount, byte[] output, int outputOffset)
{
int outputCount = inputCount;
// First find the frequency of each value
Array.Clear(_nextPos, 0, _nextPos.Length);
for (int i = inputOffset; i < inputOffset + inputCount; ++i)
{
_nextPos[input[i]]++;
}
// We know they're 'sorted' in the first column, so now can figure
// out the position of the first instance of each.
int sum = 0;
for (int i = 0; i < 256; ++i)
{
int tempSum = sum;
sum += _nextPos[i];
_nextPos[i] = tempSum;
}
// For each value in the final column, put a pointer to to the
// 'next' character in the first (sorted) column.
for (int i = 0; i < inputCount; ++i)
{
_pointers[_nextPos[input[inputOffset + i]]++] = i;
}
// The 'next' character after the end of the original string is the
// first character of the original string.
int focus = _pointers[OriginalIndex];
// We can now just walk the pointers to reconstruct the original string
for (int i = 0; i < outputCount; ++i)
{
output[outputOffset + i] = input[inputOffset + focus];
focus = _pointers[focus];
}
return outputCount;
}
protected override int MaxOutputCount(int inputCount)
{
return inputCount;
}
protected override int MinOutputCount(int inputCount)
{
return inputCount;
}
}
}
-237
View File
@@ -1,237 +0,0 @@
//
// Copyright (c) 2008-2011, Kenneth Bell
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
namespace DiscUtils.Compression
{
using System;
using System.IO;
using System.IO.Compression;
/// <summary>
/// Implementation of the Zlib compression algorithm.
/// </summary>
/// <remarks>Only decompression is currently implemented.</remarks>
public class ZlibStream : Stream
{
private Stream _stream;
private CompressionMode _mode;
private DeflateStream _deflateStream;
private Adler32 _adler32;
/// <summary>
/// Initializes a new instance of the ZlibStream class.
/// </summary>
/// <param name="stream">The stream to compress of decompress.</param>
/// <param name="mode">Whether to compress or decompress.</param>
/// <param name="leaveOpen">Whether closing this stream should leave <c>stream</c> open.</param>
public ZlibStream(Stream stream, CompressionMode mode, bool leaveOpen)
{
_stream = stream;
_mode = mode;
if (mode == CompressionMode.Decompress)
{
// We just sanity check against expected header values...
byte[] headerBuffer = Utilities.ReadFully(stream, 2);
ushort header = Utilities.ToUInt16BigEndian(headerBuffer, 0);
if ((header % 31) != 0)
{
throw new IOException("Invalid Zlib header found");
}
if ((header & 0x0F00) != (8 << 8))
{
throw new NotSupportedException("Zlib compression not using DEFLATE algorithm");
}
if ((header & 0x0020) != 0)
{
throw new NotSupportedException("Zlib compression using preset dictionary");
}
}
else
{
ushort header =
(8 << 8) // DEFLATE
| (7 << 12) // 32K window size
| 0x80; // Default algorithm
header |= (ushort)(31 - (header % 31));
byte[] headerBuffer = new byte[2];
Utilities.WriteBytesBigEndian(header, headerBuffer, 0);
stream.Write(headerBuffer, 0, 2);
}
_deflateStream = new DeflateStream(stream, mode, leaveOpen);
_adler32 = new Adler32();
}
/// <summary>
/// Gets whether the stream can be read.
/// </summary>
public override bool CanRead
{
get { return _deflateStream.CanRead; }
}
/// <summary>
/// Gets whether the stream pointer can be changed.
/// </summary>
public override bool CanSeek
{
get { return false; }
}
/// <summary>
/// Gets whether the stream can be written to.
/// </summary>
public override bool CanWrite
{
get { return _deflateStream.CanWrite; }
}
/// <summary>
/// Gets the length of the stream.
/// </summary>
public override long Length
{
get { throw new NotSupportedException(); }
}
/// <summary>
/// Gets and sets the stream position.
/// </summary>
public override long Position
{
get { throw new NotSupportedException(); }
set { throw new NotSupportedException(); }
}
/// <summary>
/// Closes the stream.
/// </summary>
public override void Close()
{
if (_mode == CompressionMode.Decompress)
{
// Can only check Adler checksum on seekable streams. Since DeflateStream
// aggresively caches input, it normally has already consumed the footer.
if (_stream.CanSeek)
{
_stream.Seek(-4, SeekOrigin.End);
byte[] footerBuffer = Utilities.ReadFully(_stream, 4);
if (Utilities.ToInt32BigEndian(footerBuffer, 0) != _adler32.Value)
{
throw new InvalidDataException("Corrupt decompressed data detected");
}
}
_deflateStream.Close();
}
else
{
_deflateStream.Close();
byte[] footerBuffer = new byte[4];
Utilities.WriteBytesBigEndian(_adler32.Value, footerBuffer, 0);
_stream.Write(footerBuffer, 0, 4);
}
}
/// <summary>
/// Flushes the stream.
/// </summary>
public override void Flush()
{
_deflateStream.Flush();
}
/// <summary>
/// Reads data from the stream.
/// </summary>
/// <param name="buffer">The buffer to populate.</param>
/// <param name="offset">The first byte to write.</param>
/// <param name="count">The number of bytes requested.</param>
/// <returns>The number of bytes read.</returns>
public override int Read(byte[] buffer, int offset, int count)
{
CheckParams(buffer, offset, count);
int numRead = _deflateStream.Read(buffer, offset, count);
_adler32.Process(buffer, offset, numRead);
return numRead;
}
/// <summary>
/// Seeks to a new position.
/// </summary>
/// <param name="offset">Relative position to seek to.</param>
/// <param name="origin">The origin of the seek.</param>
/// <returns>The new position.</returns>
public override long Seek(long offset, SeekOrigin origin)
{
throw new NotSupportedException();
}
/// <summary>
/// Changes the length of the stream.
/// </summary>
/// <param name="value">The new desired length of the stream.</param>
public override void SetLength(long value)
{
throw new NotSupportedException();
}
/// <summary>
/// Writes data to the stream.
/// </summary>
/// <param name="buffer">Buffer containing the data to write.</param>
/// <param name="offset">Offset of the first byte to write.</param>
/// <param name="count">Number of bytes to write.</param>
public override void Write(byte[] buffer, int offset, int count)
{
CheckParams(buffer, offset, count);
_adler32.Process(buffer, offset, count);
_deflateStream.Write(buffer, offset, count);
}
private static void CheckParams(byte[] buffer, int offset, int count)
{
if (buffer == null)
{
throw new ArgumentNullException("buffer");
}
if (offset < 0 || offset > buffer.Length)
{
throw new ArgumentException("Offset outside of array bounds", "offset");
}
if (count < 0 || offset + count > buffer.Length)
{
throw new ArgumentException("Array index out of bounds", "count");
}
}
}
}
-289
View File
@@ -1,289 +0,0 @@
//
// Copyright (c) 2008-2011, Kenneth Bell
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
namespace DiscUtils
{
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
/// <summary>
/// The concatenation of multiple streams (read-only, for now).
/// </summary>
internal class ConcatStream : SparseStream
{
private SparseStream[] _streams;
private Ownership _ownsStreams;
private bool _canWrite;
private long _position;
public ConcatStream(Ownership ownsStreams, params SparseStream[] streams)
{
_ownsStreams = ownsStreams;
_streams = streams;
// Only allow writes if all streams can be written
_canWrite = true;
foreach (var stream in streams)
{
if (!stream.CanWrite)
{
_canWrite = false;
}
}
}
public override bool CanRead
{
get
{
CheckDisposed();
return true;
}
}
public override bool CanSeek
{
get
{
CheckDisposed();
return true;
}
}
public override bool CanWrite
{
get
{
CheckDisposed();
return _canWrite;
}
}
public override long Length
{
get
{
CheckDisposed();
long length = 0;
for (int i = 0; i < _streams.Length; ++i)
{
length += _streams[i].Length;
}
return length;
}
}
public override long Position
{
get
{
CheckDisposed();
return _position;
}
set
{
CheckDisposed();
_position = value;
}
}
public override IEnumerable<StreamExtent> Extents
{
get
{
CheckDisposed();
List<StreamExtent> extents = new List<StreamExtent>();
long pos = 0;
for (int i = 0; i < _streams.Length; ++i)
{
foreach (StreamExtent extent in _streams[i].Extents)
{
extents.Add(new StreamExtent(extent.Start + pos, extent.Length));
}
pos += _streams[i].Length;
}
return extents;
}
}
public override void Flush()
{
CheckDisposed();
for (int i = 0; i < _streams.Length; ++i)
{
_streams[i].Flush();
}
}
public override int Read(byte[] buffer, int offset, int count)
{
CheckDisposed();
int totalRead = 0;
int numRead = 0;
do
{
long activeStreamStartPos;
int activeStream = GetActiveStream(out activeStreamStartPos);
_streams[activeStream].Position = _position - activeStreamStartPos;
numRead = _streams[activeStream].Read(buffer, offset + totalRead, count - totalRead);
totalRead += numRead;
_position += numRead;
}
while (numRead != 0);
return totalRead;
}
public override long Seek(long offset, System.IO.SeekOrigin origin)
{
CheckDisposed();
long effectiveOffset = offset;
if (origin == SeekOrigin.Current)
{
effectiveOffset += _position;
}
else if (origin == SeekOrigin.End)
{
effectiveOffset += Length;
}
if (effectiveOffset < 0)
{
throw new IOException("Attempt to move before beginning of disk");
}
else
{
Position = effectiveOffset;
return Position;
}
}
public override void SetLength(long value)
{
CheckDisposed();
long lastStreamOffset;
int lastStream = GetStream(Length, out lastStreamOffset);
if (value < lastStreamOffset)
{
throw new IOException(string.Format(CultureInfo.InvariantCulture, "Unable to reduce stream length to less than {0}", lastStreamOffset));
}
_streams[lastStream].SetLength(value - lastStreamOffset);
}
public override void Write(byte[] buffer, int offset, int count)
{
CheckDisposed();
int totalWritten = 0;
while (totalWritten != count)
{
// Offset of the stream = streamOffset
long streamOffset;
int streamIdx = GetActiveStream(out streamOffset);
// Offset within the stream = streamPos
long streamPos = _position - streamOffset;
_streams[streamIdx].Position = streamPos;
// Write (limited to the stream's length), except for final stream - that may be
// extendable
int numToWrite;
if (streamIdx == _streams.Length - 1)
{
numToWrite = count - totalWritten;
}
else
{
numToWrite = (int)Math.Min(count - totalWritten, _streams[streamIdx].Length - streamPos);
}
_streams[streamIdx].Write(buffer, offset + totalWritten, numToWrite);
totalWritten += numToWrite;
_position += numToWrite;
}
}
protected override void Dispose(bool disposing)
{
try
{
if (disposing && _ownsStreams == Ownership.Dispose && _streams != null)
{
foreach (var stream in _streams)
{
stream.Dispose();
}
_streams = null;
}
}
finally
{
base.Dispose(disposing);
}
}
private int GetActiveStream(out long startPos)
{
return GetStream(_position, out startPos);
}
private int GetStream(long targetPos, out long streamStartPos)
{
// Find the stream that _position is within
streamStartPos = 0;
int focusStream = 0;
while (focusStream < _streams.Length - 1 && streamStartPos + _streams[focusStream].Length <= targetPos)
{
streamStartPos += _streams[focusStream].Length;
focusStream++;
}
return focusStream;
}
private void CheckDisposed()
{
if (_streams == null)
{
throw new ObjectDisposedException("ConcatStream");
}
}
}
}
-43
View File
@@ -1,43 +0,0 @@
//
// Copyright (c) 2008-2011, Kenneth Bell
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
namespace DiscUtils
{
internal abstract class Crc32
{
protected readonly uint[] Table;
protected uint _value;
protected Crc32(uint[] table)
{
Table = table;
_value = 0xFFFFFFFF;
}
public uint Value
{
get { return _value ^ 0xFFFFFFFF; }
}
public abstract void Process(byte[] buffer, int offset, int count);
}
}
-47
View File
@@ -1,47 +0,0 @@
//
// Copyright (c) 2008-2011, Kenneth Bell
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
namespace DiscUtils
{
internal enum Crc32Algorithm
{
/// <summary>
/// Used in Ethernet, PKZIP, BZIP2, Gzip, PNG, etc. (aka CRC32).
/// </summary>
Common = 0,
/// <summary>
/// Used in iSCSI, SCTP, Btrfs, Vhdx. (aka CRC32C).
/// </summary>
Castagnoli = 1,
/// <summary>
/// Unknown usage. (aka CRC32K).
/// </summary>
Koopman = 2,
/// <summary>
/// Used in AIXM. (aka CRC32Q).
/// </summary>
Aeronautical = 3
}
}
-96
View File
@@ -1,96 +0,0 @@
//
// Copyright (c) 2008-2011, Kenneth Bell
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
namespace DiscUtils
{
/// <summary>
/// Calculates CRC32 of buffers.
/// </summary>
internal sealed class Crc32BigEndian : Crc32
{
private static readonly uint[][] Tables;
static Crc32BigEndian()
{
Tables = new uint[4][];
Tables[(int)Crc32Algorithm.Common] = CalcTable(0x04C11DB7);
Tables[(int)Crc32Algorithm.Castagnoli] = CalcTable(0x1EDC6F41);
Tables[(int)Crc32Algorithm.Koopman] = CalcTable(0x741B8CD7);
Tables[(int)Crc32Algorithm.Aeronautical] = CalcTable(0x814141AB);
}
public Crc32BigEndian(Crc32Algorithm algorithm)
: base(Tables[(int)algorithm])
{
}
public static uint Compute(Crc32Algorithm algorithm, byte[] buffer, int offset, int count)
{
return Process(Tables[(int)algorithm], 0xFFFFFFFF, buffer, offset, count) ^ 0xFFFFFFFF;
}
public override void Process(byte[] buffer, int offset, int count)
{
_value = Process(Table, _value, buffer, offset, count);
}
private static uint[] CalcTable(uint polynomial)
{
uint[] table = new uint[256];
for (uint i = 0; i < 256; ++i)
{
uint crc = i << 24;
for (int j = 8; j > 0; --j)
{
if ((crc & 0x80000000) != 0)
{
crc = (crc << 1) ^ polynomial;
}
else
{
crc <<= 1;
}
}
table[i] = crc;
}
return table;
}
private static uint Process(uint[] table, uint accumulator, byte[] buffer, int offset, int count)
{
uint value = accumulator;
for (int i = 0; i < count; ++i)
{
byte b = buffer[offset + i];
value = table[(value >> 24) ^ b] ^ (value << 8);
}
return value;
}
}
}
-100
View File
@@ -1,100 +0,0 @@
//
// Copyright (c) 2008-2011, Kenneth Bell
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
namespace DiscUtils
{
/// <summary>
/// Calculates CRC32 of buffers.
/// </summary>
internal sealed class Crc32LittleEndian : Crc32
{
private static readonly uint[][] Tables;
static Crc32LittleEndian()
{
Tables = new uint[4][];
Tables[(int)Crc32Algorithm.Common] = CalcTable(0xEDB88320);
Tables[(int)Crc32Algorithm.Castagnoli] = CalcTable(0x82F63B78);
Tables[(int)Crc32Algorithm.Koopman] = CalcTable(0xEB31D82E);
Tables[(int)Crc32Algorithm.Aeronautical] = CalcTable(0xD5828281);
}
public Crc32LittleEndian(Crc32Algorithm algorithm)
: base(Tables[(int)algorithm])
{
}
public static uint Compute(Crc32Algorithm algorithm, byte[] buffer, int offset, int count)
{
return Process(Tables[(int)algorithm], 0xFFFFFFFF, buffer, offset, count) ^ 0xFFFFFFFF;
}
public override void Process(byte[] buffer, int offset, int count)
{
_value = Process(Table, _value, buffer, offset, count);
}
private static uint[] CalcTable(uint polynomial)
{
uint[] table = new uint[256];
table[0] = 0;
for (uint i = 0; i <= 255; ++i)
{
uint crc = i;
for (int j = 8; j > 0; --j)
{
if ((crc & 1) != 0)
{
crc = (crc >> 1) ^ polynomial;
}
else
{
crc >>= 1;
}
}
table[i] = crc;
}
return table;
}
private static uint Process(uint[] table, uint accumulator, byte[] buffer, int offset, int count)
{
uint value = accumulator;
for (int i = 0; i < count; ++i)
{
byte b = buffer[offset + i];
uint temp1 = (value >> 8) & 0x00FFFFFF;
uint temp2 = table[(value ^ b) & 0xFF];
value = temp1 ^ temp2;
}
return value;
}
}
}
-186
View File
@@ -1,186 +0,0 @@
//
// Copyright (c) 2008-2011, Kenneth Bell
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
namespace DiscUtils
{
using System.IO;
/// <summary>
/// Provides information about a directory on a disc.
/// </summary>
/// <remarks>
/// This class allows navigation of the disc directory/file hierarchy.
/// </remarks>
public sealed class DiscDirectoryInfo : DiscFileSystemInfo
{
/// <summary>
/// Initializes a new instance of the DiscDirectoryInfo class.
/// </summary>
/// <param name="fileSystem">The file system the directory info relates to.</param>
/// <param name="path">The path within the file system of the directory.</param>
internal DiscDirectoryInfo(DiscFileSystem fileSystem, string path)
: base(fileSystem, path)
{
}
/// <summary>
/// Gets a value indicating whether the directory exists.
/// </summary>
public override bool Exists
{
get { return FileSystem.DirectoryExists(Path); }
}
/// <summary>
/// Gets the full path of the directory.
/// </summary>
public override string FullName
{
get { return base.FullName + @"\"; }
}
/// <summary>
/// Creates a directory.
/// </summary>
public void Create()
{
FileSystem.CreateDirectory(Path);
}
/// <summary>
/// Deletes a directory, even if it's not empty.
/// </summary>
public override void Delete()
{
FileSystem.DeleteDirectory(Path, false);
}
/// <summary>
/// Deletes a directory, with the caller choosing whether to recurse.
/// </summary>
/// <param name="recursive"><c>true</c> to delete all child node, <c>false</c> to fail if the directory is not empty.</param>
public void Delete(bool recursive)
{
FileSystem.DeleteDirectory(Path, recursive);
}
/// <summary>
/// Moves a directory and it's contents to a new path.
/// </summary>
/// <param name="destinationDirName">The destination directory name.</param>
public void MoveTo(string destinationDirName)
{
FileSystem.MoveDirectory(Path, destinationDirName);
}
/// <summary>
/// Gets all child directories.
/// </summary>
/// <returns>An array of child directories.</returns>
public DiscDirectoryInfo[] GetDirectories()
{
return Utilities.Map<string, DiscDirectoryInfo>(FileSystem.GetDirectories(Path), (p) => new DiscDirectoryInfo(FileSystem, p));
}
/// <summary>
/// Gets all child directories matching a search pattern.
/// </summary>
/// <param name="pattern">The search pattern.</param>
/// <returns>An array of child directories, or empty if none match.</returns>
/// <remarks>The search pattern can include the wildcards * (matching 0 or more characters)
/// and ? (matching 1 character).</remarks>
public DiscDirectoryInfo[] GetDirectories(string pattern)
{
return GetDirectories(pattern, SearchOption.TopDirectoryOnly);
}
/// <summary>
/// Gets all descendant directories matching a search pattern.
/// </summary>
/// <param name="pattern">The search pattern.</param>
/// <param name="searchOption">Whether to search just this directory, or all children.</param>
/// <returns>An array of descendant directories, or empty if none match.</returns>
/// <remarks>The search pattern can include the wildcards * (matching 0 or more characters)
/// and ? (matching 1 character). The option parameter determines whether only immediate
/// children, or all children are returned.</remarks>
public DiscDirectoryInfo[] GetDirectories(string pattern, SearchOption searchOption)
{
return Utilities.Map<string, DiscDirectoryInfo>(FileSystem.GetDirectories(Path, pattern, searchOption), (p) => new DiscDirectoryInfo(FileSystem, p));
}
/// <summary>
/// Gets all files.
/// </summary>
/// <returns>An array of files.</returns>
public DiscFileInfo[] GetFiles()
{
return Utilities.Map<string, DiscFileInfo>(FileSystem.GetFiles(Path), (p) => new DiscFileInfo(FileSystem, p));
}
/// <summary>
/// Gets all files matching a search pattern.
/// </summary>
/// <param name="pattern">The search pattern.</param>
/// <returns>An array of files, or empty if none match.</returns>
/// <remarks>The search pattern can include the wildcards * (matching 0 or more characters)
/// and ? (matching 1 character).</remarks>
public DiscFileInfo[] GetFiles(string pattern)
{
return GetFiles(pattern, SearchOption.TopDirectoryOnly);
}
/// <summary>
/// Gets all descendant files matching a search pattern.
/// </summary>
/// <param name="pattern">The search pattern.</param>
/// <param name="searchOption">Whether to search just this directory, or all children.</param>
/// <returns>An array of descendant files, or empty if none match.</returns>
/// <remarks>The search pattern can include the wildcards * (matching 0 or more characters)
/// and ? (matching 1 character). The option parameter determines whether only immediate
/// children, or all children are returned.</remarks>
public DiscFileInfo[] GetFiles(string pattern, SearchOption searchOption)
{
return Utilities.Map<string, DiscFileInfo>(FileSystem.GetFiles(Path, pattern, searchOption), (p) => new DiscFileInfo(FileSystem, p));
}
/// <summary>
/// Gets all files and directories in this directory.
/// </summary>
/// <returns>An array of files and directories.</returns>
public DiscFileSystemInfo[] GetFileSystemInfos()
{
return Utilities.Map<string, DiscFileSystemInfo>(FileSystem.GetFileSystemEntries(Path), (p) => new DiscFileSystemInfo(FileSystem, p));
}
/// <summary>
/// Gets all files and directories in this directory.
/// </summary>
/// <param name="pattern">The search pattern.</param>
/// <returns>An array of files and directories.</returns>
/// <remarks>The search pattern can include the wildcards * (matching 0 or more characters)
/// and ? (matching 1 character).</remarks>
public DiscFileSystemInfo[] GetFileSystemInfos(string pattern)
{
return Utilities.Map<string, DiscFileSystemInfo>(FileSystem.GetFileSystemEntries(Path, pattern), (p) => new DiscFileSystemInfo(FileSystem, p));
}
}
}
-205
View File
@@ -1,205 +0,0 @@
//
// Copyright (c) 2008-2011, Kenneth Bell
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
namespace DiscUtils
{
using System.IO;
/// <summary>
/// Provides information about a file on a disc.
/// </summary>
public sealed class DiscFileInfo : DiscFileSystemInfo
{
internal DiscFileInfo(DiscFileSystem fileSystem, string path)
: base(fileSystem, path)
{
}
/// <summary>
/// Gets a value indicating whether the file exists.
/// </summary>
public override bool Exists
{
get { return FileSystem.FileExists(Path); }
}
/// <summary>
/// Gets an instance of the parent directory.
/// </summary>
public DiscDirectoryInfo Directory
{
get { return Parent; }
}
/// <summary>
/// Gets a string representing the directory's full path.
/// </summary>
public string DirectoryName
{
get { return Directory.FullName; }
}
/// <summary>
/// Gets or sets a value indicating whether the file is read-only.
/// </summary>
public bool IsReadOnly
{
get
{
return (Attributes & FileAttributes.ReadOnly) != 0;
}
set
{
if (value)
{
Attributes = Attributes | FileAttributes.ReadOnly;
}
else
{
Attributes = Attributes & ~FileAttributes.ReadOnly;
}
}
}
/// <summary>
/// Gets the length of the current file in bytes.
/// </summary>
public long Length
{
get { return FileSystem.GetFileLength(Path); }
}
/// <summary>
/// Deletes a file.
/// </summary>
public override void Delete()
{
FileSystem.DeleteFile(Path);
}
/// <summary>
/// Creates a <see cref="StreamWriter" /> that appends text to the file represented by this <see cref="DiscFileInfo"/>.
/// </summary>
/// <returns>The newly created writer.</returns>
public StreamWriter AppendText()
{
return new StreamWriter(Open(FileMode.Append));
}
/// <summary>
/// Copies an existing file to a new file.
/// </summary>
/// <param name="destinationFileName">The destination file.</param>
public void CopyTo(string destinationFileName)
{
CopyTo(destinationFileName, false);
}
/// <summary>
/// Copies an existing file to a new file, allowing overwriting of an existing file.
/// </summary>
/// <param name="destinationFileName">The destination file.</param>
/// <param name="overwrite">Whether to permit over-writing of an existing file.</param>
public void CopyTo(string destinationFileName, bool overwrite)
{
FileSystem.CopyFile(Path, destinationFileName, overwrite);
}
/// <summary>
/// Creates a new file for reading and writing.
/// </summary>
/// <returns>The newly created stream.</returns>
public Stream Create()
{
return Open(FileMode.Create);
}
/// <summary>
/// Creates a new <see cref="StreamWriter"/> that writes a new text file.
/// </summary>
/// <returns>A new stream writer that can write to the file contents.</returns>
public StreamWriter CreateText()
{
return new StreamWriter(Open(FileMode.Create));
}
/// <summary>
/// Moves a file to a new location.
/// </summary>
/// <param name="destinationFileName">The new name of the file.</param>
public void MoveTo(string destinationFileName)
{
FileSystem.MoveFile(Path, destinationFileName);
}
/// <summary>
/// Opens the current file.
/// </summary>
/// <param name="mode">The file mode for the created stream.</param>
/// <returns>The newly created stream.</returns>
/// <remarks>Read-only file systems only support <c>FileMode.Open</c>.</remarks>
public Stream Open(FileMode mode)
{
return FileSystem.OpenFile(Path, mode);
}
/// <summary>
/// Opens the current file.
/// </summary>
/// <param name="mode">The file mode for the created stream.</param>
/// <param name="access">The access permissions for the created stream.</param>
/// <returns>The newly created stream.</returns>
/// <remarks>Read-only file systems only support <c>FileMode.Open</c> and <c>FileAccess.Read</c>.</remarks>
public Stream Open(FileMode mode, FileAccess access)
{
return FileSystem.OpenFile(Path, mode, access);
}
/// <summary>
/// Opens an existing file for read-only access.
/// </summary>
/// <returns>The newly created stream.</returns>
public Stream OpenRead()
{
return Open(FileMode.Open, FileAccess.Read);
}
/// <summary>
/// Opens an existing file for reading as UTF-8 text.
/// </summary>
/// <returns>The newly created reader.</returns>
public StreamReader OpenText()
{
return new StreamReader(OpenRead());
}
/// <summary>
/// Opens a file for writing.
/// </summary>
/// <returns>The newly created stream.</returns>
public Stream OpenWrite()
{
return Open(FileMode.Open, FileAccess.Write);
}
}
}
-92
View File
@@ -1,92 +0,0 @@
//
// Copyright (c) 2008-2011, Kenneth Bell
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
namespace DiscUtils
{
using System;
using System.IO;
internal sealed class DiscFileLocator : FileLocator
{
private DiscFileSystem _fileSystem;
private string _basePath;
public DiscFileLocator(DiscFileSystem fileSystem, string basePath)
{
_fileSystem = fileSystem;
_basePath = basePath;
}
public override bool Exists(string fileName)
{
return _fileSystem.FileExists(Utilities.CombinePaths(_basePath, fileName));
}
public override Stream Open(string fileName, FileMode mode, FileAccess access, FileShare share)
{
return _fileSystem.OpenFile(Utilities.CombinePaths(_basePath, fileName), mode, access);
}
public override FileLocator GetRelativeLocator(string path)
{
return new DiscFileLocator(_fileSystem, Utilities.CombinePaths(_basePath, path));
}
public override string GetFullPath(string path)
{
return Utilities.CombinePaths(_basePath, path);
}
public override string GetDirectoryFromPath(string path)
{
return Utilities.GetDirectoryFromPath(path);
}
public override string GetFileFromPath(string path)
{
return Utilities.GetFileFromPath(path);
}
public override DateTime GetLastWriteTimeUtc(string path)
{
return _fileSystem.GetLastWriteTimeUtc(Utilities.CombinePaths(_basePath, path));
}
public override bool HasCommonRoot(FileLocator other)
{
DiscFileLocator otherDiscLocator = other as DiscFileLocator;
if (otherDiscLocator == null)
{
return false;
}
// Common root if the same file system instance.
return Object.ReferenceEquals(otherDiscLocator._fileSystem, _fileSystem);
}
public override string ResolveRelativePath(string path)
{
return Utilities.ResolveRelativePath(_basePath, path);
}
}
}
-499
View File
@@ -1,499 +0,0 @@
//
// Copyright (c) 2008-2011, Kenneth Bell
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
namespace DiscUtils
{
using System;
using System.IO;
/// <summary>
/// Provides the base class for all file systems.
/// </summary>
public abstract class DiscFileSystem : MarshalByRefObject, IFileSystem, IDisposable
{
private DiscFileSystemOptions _options;
/// <summary>
/// Initializes a new instance of the DiscFileSystem class.
/// </summary>
protected DiscFileSystem()
{
_options = new DiscFileSystemOptions();
}
/// <summary>
/// Initializes a new instance of the DiscFileSystem class.
/// </summary>
/// <param name="defaultOptions">The options instance to use for this file system instance.</param>
protected DiscFileSystem(DiscFileSystemOptions defaultOptions)
{
_options = defaultOptions;
}
/// <summary>
/// Finalizes an instance of the DiscFileSystem class.
/// </summary>
~DiscFileSystem()
{
Dispose(false);
}
/// <summary>
/// Gets the file system options, which can be modified.
/// </summary>
public virtual DiscFileSystemOptions Options
{
get { return _options; }
}
/// <summary>
/// Gets a friendly description of the file system type.
/// </summary>
public abstract string FriendlyName
{
get;
}
/// <summary>
/// Gets a value indicating whether the file system is read-only or read-write.
/// </summary>
/// <returns>true if the file system is read-write.</returns>
public abstract bool CanWrite { get; }
/// <summary>
/// Gets the root directory of the file system.
/// </summary>
public virtual DiscDirectoryInfo Root
{
get { return new DiscDirectoryInfo(this, string.Empty); }
}
/// <summary>
/// Gets the volume label.
/// </summary>
public virtual string VolumeLabel
{
get { return string.Empty; }
}
/// <summary>
/// Gets a value indicating whether the file system is thread-safe.
/// </summary>
public virtual bool IsThreadSafe
{
get { return false; }
}
/// <summary>
/// Copies an existing file to a new file.
/// </summary>
/// <param name="sourceFile">The source file.</param>
/// <param name="destinationFile">The destination file.</param>
public virtual void CopyFile(string sourceFile, string destinationFile)
{
CopyFile(sourceFile, destinationFile, false);
}
/// <summary>
/// Copies an existing file to a new file, allowing overwriting of an existing file.
/// </summary>
/// <param name="sourceFile">The source file.</param>
/// <param name="destinationFile">The destination file.</param>
/// <param name="overwrite">Whether to permit over-writing of an existing file.</param>
public abstract void CopyFile(string sourceFile, string destinationFile, bool overwrite);
/// <summary>
/// Creates a directory.
/// </summary>
/// <param name="path">The path of the new directory.</param>
public abstract void CreateDirectory(string path);
/// <summary>
/// Deletes a directory.
/// </summary>
/// <param name="path">The path of the directory to delete.</param>
public abstract void DeleteDirectory(string path);
/// <summary>
/// Deletes a directory, optionally with all descendants.
/// </summary>
/// <param name="path">The path of the directory to delete.</param>
/// <param name="recursive">Determines if the all descendants should be deleted.</param>
public virtual void DeleteDirectory(string path, bool recursive)
{
if (recursive)
{
foreach (string dir in GetDirectories(path))
{
DeleteDirectory(dir, true);
}
foreach (string file in GetFiles(path))
{
DeleteFile(file);
}
}
DeleteDirectory(path);
}
/// <summary>
/// Deletes a file.
/// </summary>
/// <param name="path">The path of the file to delete.</param>
public abstract void DeleteFile(string path);
/// <summary>
/// Indicates if a directory exists.
/// </summary>
/// <param name="path">The path to test.</param>
/// <returns>true if the directory exists.</returns>
public abstract bool DirectoryExists(string path);
/// <summary>
/// Indicates if a file exists.
/// </summary>
/// <param name="path">The path to test.</param>
/// <returns>true if the file exists.</returns>
public abstract bool FileExists(string path);
/// <summary>
/// Indicates if a file or directory exists.
/// </summary>
/// <param name="path">The path to test.</param>
/// <returns>true if the file or directory exists.</returns>
public virtual bool Exists(string path)
{
return FileExists(path) || DirectoryExists(path);
}
/// <summary>
/// Gets the names of subdirectories in a specified directory.
/// </summary>
/// <param name="path">The path to search.</param>
/// <returns>Array of directories.</returns>
public virtual string[] GetDirectories(string path)
{
return GetDirectories(path, "*.*", SearchOption.TopDirectoryOnly);
}
/// <summary>
/// Gets the names of subdirectories in a specified directory matching a specified
/// search pattern.
/// </summary>
/// <param name="path">The path to search.</param>
/// <param name="searchPattern">The search string to match against.</param>
/// <returns>Array of directories matching the search pattern.</returns>
public virtual string[] GetDirectories(string path, string searchPattern)
{
return GetDirectories(path, searchPattern, SearchOption.TopDirectoryOnly);
}
/// <summary>
/// Gets the names of subdirectories in a specified directory matching a specified
/// search pattern, using a value to determine whether to search subdirectories.
/// </summary>
/// <param name="path">The path to search.</param>
/// <param name="searchPattern">The search string to match against.</param>
/// <param name="searchOption">Indicates whether to search subdirectories.</param>
/// <returns>Array of directories matching the search pattern.</returns>
public abstract string[] GetDirectories(string path, string searchPattern, SearchOption searchOption);
/// <summary>
/// Gets the names of files in a specified directory.
/// </summary>
/// <param name="path">The path to search.</param>
/// <returns>Array of files.</returns>
public virtual string[] GetFiles(string path)
{
return GetFiles(path, "*.*", SearchOption.TopDirectoryOnly);
}
/// <summary>
/// Gets the names of files in a specified directory.
/// </summary>
/// <param name="path">The path to search.</param>
/// <param name="searchPattern">The search string to match against.</param>
/// <returns>Array of files matching the search pattern.</returns>
public virtual string[] GetFiles(string path, string searchPattern)
{
return GetFiles(path, searchPattern, SearchOption.TopDirectoryOnly);
}
/// <summary>
/// Gets the names of files in a specified directory matching a specified
/// search pattern, using a value to determine whether to search subdirectories.
/// </summary>
/// <param name="path">The path to search.</param>
/// <param name="searchPattern">The search string to match against.</param>
/// <param name="searchOption">Indicates whether to search subdirectories.</param>
/// <returns>Array of files matching the search pattern.</returns>
public abstract string[] GetFiles(string path, string searchPattern, SearchOption searchOption);
/// <summary>
/// Gets the names of all files and subdirectories in a specified directory.
/// </summary>
/// <param name="path">The path to search.</param>
/// <returns>Array of files and subdirectories matching the search pattern.</returns>
public abstract string[] GetFileSystemEntries(string path);
/// <summary>
/// Gets the names of files and subdirectories in a specified directory matching a specified
/// search pattern.
/// </summary>
/// <param name="path">The path to search.</param>
/// <param name="searchPattern">The search string to match against.</param>
/// <returns>Array of files and subdirectories matching the search pattern.</returns>
public abstract string[] GetFileSystemEntries(string path, string searchPattern);
/// <summary>
/// Moves a directory.
/// </summary>
/// <param name="sourceDirectoryName">The directory to move.</param>
/// <param name="destinationDirectoryName">The target directory name.</param>
public abstract void MoveDirectory(string sourceDirectoryName, string destinationDirectoryName);
/// <summary>
/// Moves a file.
/// </summary>
/// <param name="sourceName">The file to move.</param>
/// <param name="destinationName">The target file name.</param>
public virtual void MoveFile(string sourceName, string destinationName)
{
MoveFile(sourceName, destinationName, false);
}
/// <summary>
/// Moves a file, allowing an existing file to be overwritten.
/// </summary>
/// <param name="sourceName">The file to move.</param>
/// <param name="destinationName">The target file name.</param>
/// <param name="overwrite">Whether to permit a destination file to be overwritten.</param>
public abstract void MoveFile(string sourceName, string destinationName, bool overwrite);
/// <summary>
/// Opens the specified file.
/// </summary>
/// <param name="path">The full path of the file to open.</param>
/// <param name="mode">The file mode for the created stream.</param>
/// <returns>The new stream.</returns>
public virtual SparseStream OpenFile(string path, FileMode mode)
{
return OpenFile(path, mode, FileAccess.ReadWrite);
}
/// <summary>
/// Opens the specified file.
/// </summary>
/// <param name="path">The full path of the file to open.</param>
/// <param name="mode">The file mode for the created stream.</param>
/// <param name="access">The access permissions for the created stream.</param>
/// <returns>The new stream.</returns>
public abstract SparseStream OpenFile(string path, FileMode mode, FileAccess access);
/// <summary>
/// Gets the attributes of a file or directory.
/// </summary>
/// <param name="path">The file or directory to inspect.</param>
/// <returns>The attributes of the file or directory.</returns>
public abstract FileAttributes GetAttributes(string path);
/// <summary>
/// Sets the attributes of a file or directory.
/// </summary>
/// <param name="path">The file or directory to change.</param>
/// <param name="newValue">The new attributes of the file or directory.</param>
public abstract void SetAttributes(string path, FileAttributes newValue);
/// <summary>
/// Gets the creation time (in local time) of a file or directory.
/// </summary>
/// <param name="path">The path of the file or directory.</param>
/// <returns>The creation time.</returns>
public virtual DateTime GetCreationTime(string path)
{
return GetCreationTimeUtc(path).ToLocalTime();
}
/// <summary>
/// Sets the creation time (in local time) of a file or directory.
/// </summary>
/// <param name="path">The path of the file or directory.</param>
/// <param name="newTime">The new time to set.</param>
public virtual void SetCreationTime(string path, DateTime newTime)
{
SetCreationTimeUtc(path, newTime.ToUniversalTime());
}
/// <summary>
/// Gets the creation time (in UTC) of a file or directory.
/// </summary>
/// <param name="path">The path of the file or directory.</param>
/// <returns>The creation time.</returns>
public abstract DateTime GetCreationTimeUtc(string path);
/// <summary>
/// Sets the creation time (in UTC) of a file or directory.
/// </summary>
/// <param name="path">The path of the file or directory.</param>
/// <param name="newTime">The new time to set.</param>
public abstract void SetCreationTimeUtc(string path, DateTime newTime);
/// <summary>
/// Gets the last access time (in local time) of a file or directory.
/// </summary>
/// <param name="path">The path of the file or directory.</param>
/// <returns>The last access time.</returns>
public virtual DateTime GetLastAccessTime(string path)
{
return GetLastAccessTimeUtc(path).ToLocalTime();
}
/// <summary>
/// Sets the last access time (in local time) of a file or directory.
/// </summary>
/// <param name="path">The path of the file or directory.</param>
/// <param name="newTime">The new time to set.</param>
public virtual void SetLastAccessTime(string path, DateTime newTime)
{
SetLastAccessTimeUtc(path, newTime.ToUniversalTime());
}
/// <summary>
/// Gets the last access time (in UTC) of a file or directory.
/// </summary>
/// <param name="path">The path of the file or directory.</param>
/// <returns>The last access time.</returns>
public abstract DateTime GetLastAccessTimeUtc(string path);
/// <summary>
/// Sets the last access time (in UTC) of a file or directory.
/// </summary>
/// <param name="path">The path of the file or directory.</param>
/// <param name="newTime">The new time to set.</param>
public abstract void SetLastAccessTimeUtc(string path, DateTime newTime);
/// <summary>
/// Gets the last modification time (in local time) of a file or directory.
/// </summary>
/// <param name="path">The path of the file or directory.</param>
/// <returns>The last write time.</returns>
public virtual DateTime GetLastWriteTime(string path)
{
return GetLastWriteTimeUtc(path).ToLocalTime();
}
/// <summary>
/// Sets the last modification time (in local time) of a file or directory.
/// </summary>
/// <param name="path">The path of the file or directory.</param>
/// <param name="newTime">The new time to set.</param>
public virtual void SetLastWriteTime(string path, DateTime newTime)
{
SetLastWriteTimeUtc(path, newTime.ToUniversalTime());
}
/// <summary>
/// Gets the last modification time (in UTC) of a file or directory.
/// </summary>
/// <param name="path">The path of the file or directory.</param>
/// <returns>The last write time.</returns>
public abstract DateTime GetLastWriteTimeUtc(string path);
/// <summary>
/// Sets the last modification time (in UTC) of a file or directory.
/// </summary>
/// <param name="path">The path of the file or directory.</param>
/// <param name="newTime">The new time to set.</param>
public abstract void SetLastWriteTimeUtc(string path, DateTime newTime);
/// <summary>
/// Gets the length of a file.
/// </summary>
/// <param name="path">The path to the file.</param>
/// <returns>The length in bytes.</returns>
public abstract long GetFileLength(string path);
/// <summary>
/// Gets an object representing a possible file.
/// </summary>
/// <param name="path">The file path.</param>
/// <returns>The representing object.</returns>
/// <remarks>The file does not need to exist.</remarks>
public virtual DiscFileInfo GetFileInfo(string path)
{
return new DiscFileInfo(this, path);
}
/// <summary>
/// Gets an object representing a possible directory.
/// </summary>
/// <param name="path">The directory path.</param>
/// <returns>The representing object.</returns>
/// <remarks>The directory does not need to exist.</remarks>
public virtual DiscDirectoryInfo GetDirectoryInfo(string path)
{
return new DiscDirectoryInfo(this, path);
}
/// <summary>
/// Gets an object representing a possible file system object (file or directory).
/// </summary>
/// <param name="path">The file system path.</param>
/// <returns>The representing object.</returns>
/// <remarks>The file system object does not need to exist.</remarks>
public virtual DiscFileSystemInfo GetFileSystemInfo(string path)
{
return new DiscFileSystemInfo(this, path);
}
/// <summary>
/// Reads the boot code of the file system into a byte array.
/// </summary>
/// <returns>The boot code, or <c>null</c> if not available.</returns>
public virtual byte[] ReadBootCode()
{
return null;
}
#region IDisposable Members
/// <summary>
/// Disposes of this instance, releasing all resources.
/// </summary>
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
/// <summary>
/// Disposes of this instance.
/// </summary>
/// <param name="disposing">The value <c>true</c> if Disposing.</param>
protected virtual void Dispose(bool disposing)
{
}
#endregion
}
}
-76
View File
@@ -1,76 +0,0 @@
//
// Copyright (c) 2008-2011, Kenneth Bell
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
namespace DiscUtils
{
using System;
using System.IO;
/// <summary>
/// Flags for the amount of detail to include in a report.
/// </summary>
[Flags]
public enum ReportLevels
{
/// <summary>
/// Report no information.
/// </summary>
None = 0x00,
/// <summary>
/// Report informational level items.
/// </summary>
Information = 0x01,
/// <summary>
/// Report warning level items.
/// </summary>
Warnings = 0x02,
/// <summary>
/// Report error level items.
/// </summary>
Errors = 0x04,
/// <summary>
/// Report all items.
/// </summary>
All = 0x07
}
/// <summary>
/// Base class for objects that validate file system integrity.
/// </summary>
/// <remarks>Instances of this class do not offer the ability to fix/correct
/// file system issues, just to perform a limited number of checks on
/// integrity of the file system.</remarks>
public abstract class DiscFileSystemChecker
{
/// <summary>
/// Checks the integrity of a file system held in a stream.
/// </summary>
/// <param name="reportOutput">A report on issues found.</param>
/// <param name="levels">The amount of detail to report.</param>
/// <returns><c>true</c> if the file system appears valid, else <c>false</c>.</returns>
public abstract bool Check(TextWriter reportOutput, ReportLevels levels);
}
}
-226
View File
@@ -1,226 +0,0 @@
//
// Copyright (c) 2008-2011, Kenneth Bell
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
namespace DiscUtils
{
using System;
using System.IO;
/// <summary>
/// Provides the base class for both <see cref="DiscFileInfo"/> and <see cref="DiscDirectoryInfo"/> objects.
/// </summary>
public class DiscFileSystemInfo
{
private DiscFileSystem _fileSystem;
private string _path;
internal DiscFileSystemInfo(DiscFileSystem fileSystem, string path)
{
if (path == null)
{
throw new ArgumentNullException("path");
}
_fileSystem = fileSystem;
_path = path.Trim('\\');
}
/// <summary>
/// Gets the file system the referenced file or directory exists on.
/// </summary>
public DiscFileSystem FileSystem
{
get { return _fileSystem; }
}
/// <summary>
/// Gets the name of the file or directory.
/// </summary>
public virtual string Name
{
get { return Utilities.GetFileFromPath(_path); }
}
/// <summary>
/// Gets the full path of the file or directory.
/// </summary>
public virtual string FullName
{
get { return _path; }
}
/// <summary>
/// Gets the extension part of the file or directory name.
/// </summary>
public virtual string Extension
{
get
{
string name = Name;
int sepIdx = name.LastIndexOf('.');
if (sepIdx >= 0)
{
return name.Substring(sepIdx + 1);
}
return string.Empty;
}
}
/// <summary>
/// Gets or sets the <see cref="System.IO.FileAttributes"/> of the current <see cref="DiscFileSystemInfo"/> object.
/// </summary>
public virtual FileAttributes Attributes
{
get { return FileSystem.GetAttributes(_path); }
set { FileSystem.SetAttributes(_path, value); }
}
/// <summary>
/// Gets the <see cref="DiscDirectoryInfo"/> of the directory containing the current <see cref="DiscFileSystemInfo"/> object.
/// </summary>
public virtual DiscDirectoryInfo Parent
{
get
{
if (string.IsNullOrEmpty(_path))
{
return null;
}
return new DiscDirectoryInfo(FileSystem, Utilities.GetDirectoryFromPath(_path));
}
}
/// <summary>
/// Gets a value indicating whether the file system object exists.
/// </summary>
public virtual bool Exists
{
get { return FileSystem.Exists(_path); }
}
/// <summary>
/// Gets or sets the creation time (in local time) of the current <see cref="DiscFileSystemInfo"/> object.
/// </summary>
public virtual DateTime CreationTime
{
get { return CreationTimeUtc.ToLocalTime(); }
set { CreationTimeUtc = value.ToUniversalTime(); }
}
/// <summary>
/// Gets or sets the creation time (in UTC) of the current <see cref="DiscFileSystemInfo"/> object.
/// </summary>
public virtual DateTime CreationTimeUtc
{
get { return FileSystem.GetCreationTimeUtc(_path); }
set { FileSystem.SetCreationTimeUtc(_path, value); }
}
/// <summary>
/// Gets or sets the last time (in local time) the file or directory was accessed.
/// </summary>
/// <remarks>Read-only file systems will never update this value, it will remain at a fixed value.</remarks>
public virtual DateTime LastAccessTime
{
get { return LastAccessTimeUtc.ToLocalTime(); }
set { LastAccessTimeUtc = value.ToUniversalTime(); }
}
/// <summary>
/// Gets or sets the last time (in UTC) the file or directory was accessed.
/// </summary>
/// <remarks>Read-only file systems will never update this value, it will remain at a fixed value.</remarks>
public virtual DateTime LastAccessTimeUtc
{
get { return FileSystem.GetLastAccessTimeUtc(_path); }
set { FileSystem.SetLastAccessTimeUtc(_path, value); }
}
/// <summary>
/// Gets or sets the last time (in local time) the file or directory was written to.
/// </summary>
public virtual DateTime LastWriteTime
{
get { return LastWriteTimeUtc.ToLocalTime(); }
set { LastWriteTimeUtc = value.ToUniversalTime(); }
}
/// <summary>
/// Gets or sets the last time (in UTC) the file or directory was written to.
/// </summary>
public virtual DateTime LastWriteTimeUtc
{
get { return FileSystem.GetLastWriteTimeUtc(_path); }
set { FileSystem.SetLastWriteTimeUtc(_path, value); }
}
/// <summary>
/// Gets the path to the referenced file.
/// </summary>
protected string Path
{
get { return _path; }
}
/// <summary>
/// Deletes a file or directory.
/// </summary>
public virtual void Delete()
{
if ((Attributes & FileAttributes.Directory) != 0)
{
FileSystem.DeleteDirectory(_path);
}
else
{
FileSystem.DeleteFile(_path);
}
}
/// <summary>
/// Indicates if <paramref name="obj"/> is equivalent to this object.
/// </summary>
/// <param name="obj">The object to compare.</param>
/// <returns><c>true</c> if <paramref name="obj"/> is equivalent, else <c>false</c>.</returns>
public override bool Equals(object obj)
{
DiscFileSystemInfo asInfo = obj as DiscFileSystemInfo;
if (obj == null)
{
return false;
}
return string.Compare(Path, asInfo.Path, StringComparison.Ordinal) == 0 && DiscFileSystem.Equals(FileSystem, asInfo.FileSystem);
}
/// <summary>
/// Gets the hash code for this object.
/// </summary>
/// <returns>The hash code.</returns>
public override int GetHashCode()
{
return _path.GetHashCode() ^ _fileSystem.GetHashCode();
}
}
}
-56
View File
@@ -1,56 +0,0 @@
//
// Copyright (c) 2008-2011, Kenneth Bell
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
namespace DiscUtils
{
using System;
/// <summary>
/// Common file system options.
/// </summary>
/// <remarks>Not all options are honoured by all file systems.</remarks>
public class DiscFileSystemOptions
{
private Random _rng;
/// <summary>
/// Initializes a new instance of the DiscFileSystemOptions class.
/// </summary>
/// <remarks>You shouldn't normally create a new instance. File systems will provide
/// an instance of the correct derived type.</remarks>
public DiscFileSystemOptions()
{
}
/// <summary>
/// Gets or sets the random number generator the file system should use.
/// </summary>
/// <remarks>This option is normally <c>null</c>, which is fine for most purposes.
/// Use this option when you need to finely control the filesystem for
/// reproducibility of behaviour (for example in a test harness).</remarks>
public Random RandomNumberGenerator
{
get { return _rng; }
set { _rng = value; }
}
}
}
@@ -0,0 +1,23 @@
#if !NET40 && !NET45
using System.Text;
#endif
namespace DiscUtils.CoreCompat
{
public static class EncodingHelper
{
private static bool _registered;
public static void RegisterEncodings()
{
if (_registered)
return;
_registered = true;
#if !NET40 && !NET45
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
#endif
}
}
}
@@ -0,0 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="DiscUtils.Core" Version="0.16.13" />
</ItemGroup>
</Project>
@@ -0,0 +1,459 @@
//
// Copyright (c) 2008-2011, Kenneth Bell
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
namespace DiscUtils.Internal
{
public static class Utilities
{
/// <summary>
/// Converts between two arrays.
/// </summary>
/// <typeparam name="T">The type of the elements of the source array.</typeparam>
/// <typeparam name="U">The type of the elements of the destination array.</typeparam>
/// <param name="source">The source array.</param>
/// <param name="func">The function to map from source type to destination type.</param>
/// <returns>The resultant array.</returns>
public static U[] Map<T, U>(ICollection<T> source, Func<T, U> func)
{
U[] result = new U[source.Count];
int i = 0;
foreach (T sVal in source)
{
result[i++] = func(sVal);
}
return result;
}
/// <summary>
/// Converts between two arrays.
/// </summary>
/// <typeparam name="T">The type of the elements of the source array.</typeparam>
/// <typeparam name="U">The type of the elements of the destination array.</typeparam>
/// <param name="source">The source array.</param>
/// <param name="func">The function to map from source type to destination type.</param>
/// <returns>The resultant array.</returns>
public static U[] Map<T, U>(IEnumerable<T> source, Func<T, U> func)
{
List<U> result = [];
foreach (T sVal in source)
{
result.Add(func(sVal));
}
return [.. result];
}
/// <summary>
/// Filters a collection into a new collection.
/// </summary>
/// <typeparam name="C">The type of the new collection.</typeparam>
/// <typeparam name="T">The type of the collection entries.</typeparam>
/// <param name="source">The collection to filter.</param>
/// <param name="predicate">The predicate to select which entries are carried over.</param>
/// <returns>The new collection, containing all entries where the predicate returns <c>true</c>.</returns>
public static C Filter<C, T>(ICollection<T> source, Func<T, bool> predicate) where C : ICollection<T>, new()
{
C result = new();
foreach (T val in source)
{
if (predicate(val))
{
result.Add(val);
}
}
return result;
}
/// <summary>
/// Indicates if two ranges overlap.
/// </summary>
/// <typeparam name="T">The type of the ordinals.</typeparam>
/// <param name="xFirst">The lowest ordinal of the first range (inclusive).</param>
/// <param name="xLast">The highest ordinal of the first range (exclusive).</param>
/// <param name="yFirst">The lowest ordinal of the second range (inclusive).</param>
/// <param name="yLast">The highest ordinal of the second range (exclusive).</param>
/// <returns><c>true</c> if the ranges overlap, else <c>false</c>.</returns>
public static bool RangesOverlap<T>(T xFirst, T xLast, T yFirst, T yLast) where T : IComparable<T>
{
return !((xLast.CompareTo(yFirst) <= 0) || (xFirst.CompareTo(yLast) >= 0));
}
#region Bit Twiddling
public static bool IsAllZeros(byte[] buffer, int offset, int count)
{
int end = offset + count;
for (int i = offset; i < end; ++i)
{
if (buffer[i] != 0)
{
return false;
}
}
return true;
}
public static bool IsPowerOfTwo(uint val)
{
if (val == 0)
{
return false;
}
while ((val & 1) != 1)
{
val >>= 1;
}
return val == 1;
}
public static bool IsPowerOfTwo(long val)
{
if (val == 0)
{
return false;
}
while ((val & 1) != 1)
{
val >>= 1;
}
return val == 1;
}
public static bool AreEqual(byte[] a, byte[] b)
{
if (a.Length != b.Length)
{
return false;
}
for (int i = 0; i < a.Length; ++i)
{
if (a[i] != b[i])
{
return false;
}
}
return true;
}
public static ushort BitSwap(ushort value)
{
return (ushort)(((value & 0x00FF) << 8) | ((value & 0xFF00) >> 8));
}
public static uint BitSwap(uint value)
{
return ((value & 0xFF) << 24) | ((value & 0xFF00) << 8) | ((value & 0x00FF0000) >> 8) |
((value & 0xFF000000) >> 24);
}
public static ulong BitSwap(ulong value)
{
return ((ulong)BitSwap((uint)(value & 0xFFFFFFFF)) << 32) | BitSwap((uint)(value >> 32));
}
public static short BitSwap(short value)
{
return (short)BitSwap((ushort)value);
}
public static int BitSwap(int value)
{
return (int)BitSwap((uint)value);
}
public static long BitSwap(long value)
{
return (long)BitSwap((ulong)value);
}
#endregion
#region Path Manipulation
/// <summary>
/// Extracts the directory part of a path.
/// </summary>
/// <param name="path">The path to process.</param>
/// <returns>The directory part.</returns>
public static string GetDirectoryFromPath(string path)
{
string trimmed = path.TrimEnd('\\');
int index = trimmed.LastIndexOf('\\');
if (index < 0)
{
return string.Empty; // No directory, just a file name
}
return trimmed.Substring(0, index);
}
/// <summary>
/// Extracts the file part of a path.
/// </summary>
/// <param name="path">The path to process.</param>
/// <returns>The file part of the path.</returns>
public static string GetFileFromPath(string path)
{
string trimmed = path.Trim('\\');
int index = trimmed.LastIndexOf('\\');
if (index < 0)
{
return trimmed; // No directory, just a file name
}
return trimmed.Substring(index + 1);
}
/// <summary>
/// Combines two paths.
/// </summary>
/// <param name="a">The first part of the path.</param>
/// <param name="b">The second part of the path.</param>
/// <returns>The combined path.</returns>
public static string CombinePaths(string a, string b)
{
if (string.IsNullOrEmpty(a) || (b.Length > 0 && b[0] == '\\'))
{
return b;
}
if (string.IsNullOrEmpty(b))
{
return a;
}
return a.TrimEnd('\\') + '\\' + b.TrimStart('\\');
}
/// <summary>
/// Resolves a relative path into an absolute one.
/// </summary>
/// <param name="basePath">The base path to resolve from.</param>
/// <param name="relativePath">The relative path.</param>
/// <returns>The absolute path. If no <paramref name="basePath"/> is specified
/// then relativePath is returned as-is. If <paramref name="relativePath"/>
/// contains more '..' characters than the base path contains levels of
/// directory, the resultant string be the root drive followed by the file name.
/// If no the basePath starts with '\' (no drive specified) then the returned
/// path will also start with '\'.
/// For example: (\TEMP\Foo.txt, ..\..\Bar.txt) gives (\Bar.txt).
/// </returns>
public static string ResolveRelativePath(string basePath, string relativePath)
{
if (string.IsNullOrEmpty(basePath))
{
return relativePath;
}
if (!basePath.EndsWith(@"\"))
basePath = Path.GetDirectoryName(basePath);
string merged = Path.GetFullPath(Path.Combine(basePath, relativePath));
if (basePath.StartsWith(@"\") && merged.Length > 2 && merged[1].Equals(':'))
{
return merged.Substring(2);
}
return merged;
}
public static string ResolvePath(string basePath, string path)
{
if (!path.StartsWith("\\", StringComparison.OrdinalIgnoreCase))
{
return ResolveRelativePath(basePath, path);
}
return path;
}
public static string MakeRelativePath(string path, string basePath)
{
List<string> pathElements =
new(path.Split(new[] { '\\' }, StringSplitOptions.RemoveEmptyEntries));
List<string> basePathElements =
new(basePath.Split(new[] { '\\' }, StringSplitOptions.RemoveEmptyEntries));
if (!basePath.EndsWith("\\", StringComparison.Ordinal) && basePathElements.Count > 0)
{
basePathElements.RemoveAt(basePathElements.Count - 1);
}
// Find first part of paths that don't match
int i = 0;
while (i < Math.Min(pathElements.Count - 1, basePathElements.Count))
{
if (!string.Equals(pathElements[i], basePathElements[i], StringComparison.InvariantCultureIgnoreCase))
{
break;
}
++i;
}
// For each remaining part of the base path, insert '..'
StringBuilder result = new();
if (i == basePathElements.Count)
{
result.Append(@".\");
}
else if (i < basePathElements.Count)
{
for (int j = 0; j < basePathElements.Count - i; ++j)
{
result.Append(@"..\");
}
}
// For each remaining part of the path, add the path element
for (int j = i; j < pathElements.Count - 1; ++j)
{
result.Append(pathElements[j]);
result.Append(@"\");
}
result.Append(pathElements[^1]);
// If the target was a directory, put the terminator back
if (path.EndsWith(@"\", StringComparison.Ordinal))
{
result.Append(@"\");
}
return result.ToString();
}
#endregion
#region Filesystem Support
/// <summary>
/// Indicates if a file name matches the 8.3 pattern.
/// </summary>
/// <param name="name">The name to test.</param>
/// <returns><c>true</c> if the name is 8.3, otherwise <c>false</c>.</returns>
public static bool Is8Dot3(string name)
{
if (name.Length > 12)
{
return false;
}
string[] split = name.Split('.');
if (split.Length > 2 || split.Length < 1)
{
return false;
}
if (split[0].Length > 8)
{
return false;
}
foreach (char ch in split[0])
{
if (!Is8Dot3Char(ch))
{
return false;
}
}
if (split.Length > 1)
{
if (split[1].Length > 3)
{
return false;
}
foreach (char ch in split[1])
{
if (!Is8Dot3Char(ch))
{
return false;
}
}
}
return true;
}
public static bool Is8Dot3Char(char ch)
{
return (ch >= 'A' && ch <= 'Z') || (ch >= '0' && ch <= '9') || "_^$~!#%£-{}()@'`&".IndexOf(ch) != -1;
}
/// <summary>
/// Converts a 'standard' wildcard file/path specification into a regular expression.
/// </summary>
/// <param name="pattern">The wildcard pattern to convert.</param>
/// <returns>The resultant regular expression.</returns>
/// <remarks>
/// The wildcard * (star) matches zero or more characters (including '.'), and ?
/// (question mark) matches precisely one character (except '.').
/// </remarks>
public static Regex ConvertWildcardsToRegEx(string pattern)
{
if (!pattern.Contains("."))
{
pattern += ".";
}
string query = "^" + Regex.Escape(pattern).Replace(@"\*", ".*").Replace(@"\?", "[^.]") + "$";
return new Regex(query, RegexOptions.IgnoreCase | RegexOptions.CultureInvariant);
}
public static FileAttributes FileAttributesFromUnixFileType(UnixFileType fileType)
{
return fileType switch
{
UnixFileType.Fifo => FileAttributes.Device | FileAttributes.System,
UnixFileType.Character => FileAttributes.Device | FileAttributes.System,
UnixFileType.Directory => FileAttributes.Directory,
UnixFileType.Block => FileAttributes.Device | FileAttributes.System,
UnixFileType.Regular => FileAttributes.Normal,
UnixFileType.Link => FileAttributes.ReparsePoint,
UnixFileType.Socket => FileAttributes.Device | FileAttributes.System,
_ => 0,
};
}
#endregion
}
}
@@ -1,94 +1,95 @@
// //
// Copyright (c) 2008-2011, Kenneth Bell // Copyright (c) 2008-2011, Kenneth Bell
// //
// Permission is hereby granted, free of charge, to any person obtaining a // Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"), // copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation // to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, // the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the // and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions: // Software is furnished to do so, subject to the following conditions:
// //
// The above copyright notice and this permission notice shall be included in // The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software. // all copies or substantial portions of the Software.
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
// //
namespace DiscUtils.Fat using System;
{ using System.IO;
using System; using DiscUtils.Streams;
using System.IO;
namespace DiscUtils.Fat
internal sealed class ClusterReader {
{ internal sealed class ClusterReader
private Stream _stream; {
private int _firstDataSector; private readonly int _bytesPerSector;
private int _sectorsPerCluster;
private int _bytesPerSector; /// <summary>
/// Pre-calculated value because of number of uses of this externally.
/// <summary> /// </summary>
/// Pre-calculated value because of number of uses of this externally. private readonly int _clusterSize;
/// </summary>
private int _clusterSize; private readonly int _firstDataSector;
private readonly int _sectorsPerCluster;
public ClusterReader(Stream stream, int firstDataSector, int sectorsPerCluster, int bytesPerSector) private readonly Stream _stream;
{
_stream = stream; public ClusterReader(Stream stream, int firstDataSector, int sectorsPerCluster, int bytesPerSector)
_firstDataSector = firstDataSector; {
_sectorsPerCluster = sectorsPerCluster; _stream = stream;
_bytesPerSector = bytesPerSector; _firstDataSector = firstDataSector;
_sectorsPerCluster = sectorsPerCluster;
_clusterSize = _sectorsPerCluster * _bytesPerSector; _bytesPerSector = bytesPerSector;
}
_clusterSize = _sectorsPerCluster * _bytesPerSector;
public int ClusterSize }
{
get { return _clusterSize; } public int ClusterSize
} {
get { return _clusterSize; }
public void ReadCluster(uint cluster, byte[] buffer, int offset) }
{
if (offset + ClusterSize > buffer.Length) public void ReadCluster(uint cluster, byte[] buffer, int offset)
{ {
throw new ArgumentOutOfRangeException("offset", "buffer is too small - cluster would overflow buffer"); if (offset + ClusterSize > buffer.Length)
} {
throw new ArgumentOutOfRangeException(nameof(offset),
uint firstSector = (uint)(((cluster - 2) * _sectorsPerCluster) + _firstDataSector); "buffer is too small - cluster would overflow buffer");
}
_stream.Position = firstSector * _bytesPerSector;
if (Utilities.ReadFully(_stream, buffer, offset, _clusterSize) != _clusterSize) uint firstSector = (uint)(((cluster - 2) * _sectorsPerCluster) + _firstDataSector);
{
throw new IOException("Failed to read cluster " + cluster); _stream.Position = firstSector * _bytesPerSector;
} StreamUtilities.ReadExact(_stream, buffer, offset, _clusterSize);
} }
internal void WriteCluster(uint cluster, byte[] buffer, int offset) internal void WriteCluster(uint cluster, byte[] buffer, int offset)
{ {
if (offset + ClusterSize > buffer.Length) if (offset + ClusterSize > buffer.Length)
{ {
throw new ArgumentOutOfRangeException("offset", "buffer is too small - cluster would overflow buffer"); throw new ArgumentOutOfRangeException(nameof(offset),
} "buffer is too small - cluster would overflow buffer");
}
uint firstSector = (uint)(((cluster - 2) * _sectorsPerCluster) + _firstDataSector);
uint firstSector = (uint)(((cluster - 2) * _sectorsPerCluster) + _firstDataSector);
_stream.Position = firstSector * _bytesPerSector;
_stream.Position = firstSector * _bytesPerSector;
_stream.Write(buffer, offset, _clusterSize);
} _stream.Write(buffer, offset, _clusterSize);
}
internal void WipeCluster(uint cluster)
{ internal void WipeCluster(uint cluster)
uint firstSector = (uint)(((cluster - 2) * _sectorsPerCluster) + _firstDataSector); {
uint firstSector = (uint)(((cluster - 2) * _sectorsPerCluster) + _firstDataSector);
_stream.Position = firstSector * _bytesPerSector;
_stream.Position = firstSector * _bytesPerSector;
_stream.Write(new byte[_clusterSize], 0, _clusterSize);
} _stream.Write(new byte[_clusterSize], 0, _clusterSize);
} }
} }
}
@@ -1,475 +1,449 @@
// //
// Copyright (c) 2008-2011, Kenneth Bell // Copyright (c) 2008-2011, Kenneth Bell
// //
// Permission is hereby granted, free of charge, to any person obtaining a // Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"), // copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation // to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, // the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the // and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions: // Software is furnished to do so, subject to the following conditions:
// //
// The above copyright notice and this permission notice shall be included in // The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software. // all copies or substantial portions of the Software.
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
// //
namespace DiscUtils.Fat using System;
{ using System.Collections.Generic;
using System; using System.IO;
using System.Collections.Generic;
using System.IO; namespace DiscUtils.Fat
{
internal delegate void FirstClusterChangedDelegate(uint cluster); internal class ClusterStream : Stream
{
internal class ClusterStream : Stream private readonly FileAccess _access;
{ private readonly byte[] _clusterBuffer;
private FileAccess _access; private readonly FileAllocationTable _fat;
private ClusterReader _reader;
private FileAllocationTable _fat; private readonly List<uint> _knownClusters;
private uint _length; private readonly ClusterReader _reader;
private List<uint> _knownClusters; private bool _atEOF;
private long _position;
private uint _currentCluster;
private uint _currentCluster = 0; private uint _length;
private byte[] _clusterBuffer; private long _position;
private bool _atEOF; internal ClusterStream(FatFileSystem fileSystem, FileAccess access, uint firstCluster, uint length)
{
internal ClusterStream(FatFileSystem fileSystem, FileAccess access, uint firstCluster, uint length) _access = access;
{ _reader = fileSystem.ClusterReader;
_access = access; _fat = fileSystem.Fat;
_reader = fileSystem.ClusterReader; _length = length;
_fat = fileSystem.Fat;
_length = length; _knownClusters = [firstCluster != 0 ? firstCluster : FatBuffer.EndOfChain];
_knownClusters = new List<uint>(); if (_length == uint.MaxValue)
if (firstCluster != 0) {
{ _length = DetectLength();
_knownClusters.Add(firstCluster); }
}
else _currentCluster = uint.MaxValue;
{ _clusterBuffer = new byte[_reader.ClusterSize];
_knownClusters.Add(FatBuffer.EndOfChain); }
}
public override bool CanRead
if (_length == uint.MaxValue) {
{ get { return _access == FileAccess.Read || _access == FileAccess.ReadWrite; }
_length = DetectLength(); }
}
public override bool CanSeek
_currentCluster = uint.MaxValue; {
_clusterBuffer = new byte[_reader.ClusterSize]; get { return true; }
} }
public event FirstClusterChangedDelegate FirstClusterChanged; public override bool CanWrite
{
public override bool CanRead get { return _access == FileAccess.ReadWrite || _access == FileAccess.Write; }
{ }
get { return _access == FileAccess.Read || _access == FileAccess.ReadWrite; }
} public override long Length
{
public override bool CanSeek get { return _length; }
{ }
get { return true; }
} public override long Position
{
public override bool CanWrite get { return _position; }
{
get { return _access == FileAccess.ReadWrite || _access == FileAccess.Write; } set
} {
if (value >= 0)
public override long Length {
{ _position = value;
get { return _length; } _atEOF = false;
} }
else
public override long Position {
{ throw new ArgumentOutOfRangeException(nameof(value), "Attempt to move before beginning of stream");
get }
{ }
return _position; }
}
public event FirstClusterChangedDelegate FirstClusterChanged;
set
{ public override void Flush() { }
if (value >= 0)
{ public override int Read(byte[] buffer, int offset, int count)
_position = value; {
_atEOF = false; if (!CanRead)
} {
else throw new IOException("Attempt to read from file not opened for read");
{ }
throw new ArgumentOutOfRangeException("value", "Attempt to move before beginning of stream");
} if (_position > _length)
} {
} throw new IOException("Attempt to read beyond end of file");
}
public override void Flush()
{ if (count < 0)
return; {
} throw new ArgumentOutOfRangeException(nameof(count), "Attempt to read negative number of bytes");
}
public override int Read(byte[] buffer, int offset, int count)
{ int target = count;
if (!CanRead) if (_length - _position < count)
{ {
throw new IOException("Attempt to read from file not opened for read"); target = (int)(_length - _position);
} }
if (_position > _length) if (!TryLoadCurrentCluster())
{ {
throw new IOException("Attempt to read beyond end of file"); if ((_position == _length || _position == DetectLength()) && !_atEOF)
} {
_atEOF = true;
if (count < 0) return 0;
{ }
throw new ArgumentOutOfRangeException("count", "Attempt to read negative number of bytes"); throw new IOException("Attempt to read beyond known clusters");
} }
int target = count; int numRead = 0;
if (_length - _position < count) while (numRead < target)
{ {
target = (int)(_length - _position); int clusterOffset = (int)(_position % _reader.ClusterSize);
} int toCopy = Math.Min(_reader.ClusterSize - clusterOffset, target - numRead);
Array.Copy(_clusterBuffer, clusterOffset, buffer, offset + numRead, toCopy);
if (!TryLoadCurrentCluster())
{ // Remember how many we've read in total
if ((_position == _length || _position == DetectLength()) && !_atEOF) numRead += toCopy;
{
_atEOF = true; // Increment the position
return 0; _position += toCopy;
}
else // Abort if we've hit the end of the file
{ if (!TryLoadCurrentCluster())
throw new IOException("Attempt to read beyond known clusters"); {
} break;
} }
}
int numRead = 0;
while (numRead < target) if (numRead == 0)
{ {
int clusterOffset = (int)(_position % _reader.ClusterSize); _atEOF = true;
int toCopy = Math.Min(_reader.ClusterSize - clusterOffset, target - numRead); }
Array.Copy(_clusterBuffer, clusterOffset, buffer, offset + numRead, toCopy);
return numRead;
// Remember how many we've read in total }
numRead += toCopy;
public override long Seek(long offset, SeekOrigin origin)
// Increment the position {
_position += toCopy; long newPos = offset;
if (origin == SeekOrigin.Current)
// Abort if we've hit the end of the file {
if (!TryLoadCurrentCluster()) newPos += _position;
{ }
break; else if (origin == SeekOrigin.End)
} {
} newPos += Length;
}
if (numRead == 0)
{ _position = newPos;
_atEOF = true; _atEOF = false;
} return newPos;
}
return numRead;
} public override void SetLength(long value)
{
public override long Seek(long offset, SeekOrigin origin) long desiredNumClusters = (value + _reader.ClusterSize - 1) / _reader.ClusterSize;
{ long actualNumClusters = (_length + _reader.ClusterSize - 1) / _reader.ClusterSize;
long newPos = offset;
if (origin == SeekOrigin.Current) if (desiredNumClusters < actualNumClusters)
{ {
newPos += _position; if (!TryGetClusterByPosition(value, out uint cluster))
} {
else if (origin == SeekOrigin.End) throw new IOException("Internal state corrupt - unable to find cluster");
{ }
newPos += Length;
} uint firstToFree = _fat.GetNext(cluster);
_fat.SetEndOfChain(cluster);
_position = newPos; _fat.FreeChain(firstToFree);
_atEOF = false;
return newPos; while (_knownClusters.Count > desiredNumClusters)
} {
_knownClusters.RemoveAt(_knownClusters.Count - 1);
public override void SetLength(long value) }
{
long desiredNumClusters = (value + _reader.ClusterSize - 1) / _reader.ClusterSize; _knownClusters.Add(FatBuffer.EndOfChain);
long actualNumClusters = (_length + _reader.ClusterSize - 1) / _reader.ClusterSize;
if (desiredNumClusters == 0)
if (desiredNumClusters < actualNumClusters) {
{ FireFirstClusterAllocated(0);
uint cluster; }
if (!TryGetClusterByPosition(value, out cluster)) }
{ else if (desiredNumClusters > actualNumClusters)
throw new IOException("Internal state corrupt - unable to find cluster"); {
} while (!TryGetClusterByPosition(value, out uint cluster))
{
uint firstToFree = _fat.GetNext(cluster); cluster = ExtendChain();
_fat.SetEndOfChain(cluster); _reader.WipeCluster(cluster);
_fat.FreeChain(firstToFree); }
}
while (_knownClusters.Count > desiredNumClusters)
{ if (_length != value)
_knownClusters.RemoveAt(_knownClusters.Count - 1); {
} _length = (uint)value;
if (_position > _length)
_knownClusters.Add(FatBuffer.EndOfChain); {
_position = _length;
if (desiredNumClusters == 0) }
{ }
FireFirstClusterAllocated(0); }
}
} public override void Write(byte[] buffer, int offset, int count)
else if (desiredNumClusters > actualNumClusters) {
{ int bytesRemaining = count;
uint cluster;
while (!TryGetClusterByPosition(value, out cluster)) if (!CanWrite)
{ {
cluster = ExtendChain(); throw new IOException("Attempting to write to file not opened for writing");
_reader.WipeCluster(cluster); }
}
} if (count < 0)
{
if (_length != value) throw new ArgumentOutOfRangeException(nameof(count), count,
{ "Attempting to write negative number of bytes");
_length = (uint)value; }
if (_position > _length)
{ if (offset > buffer.Length || offset + count > buffer.Length)
_position = _length; {
} throw new ArgumentException("Attempt to write bytes outside of the buffer");
} }
}
// TODO: Free space check...
public override void Write(byte[] buffer, int offset, int count) try
{ {
int bytesRemaining = count; while (bytesRemaining > 0)
{
if (!CanWrite) // Extend the stream until it encompasses _position
{ uint cluster;
throw new IOException("Attempting to write to file not opened for writing"); while (!TryGetClusterByPosition(_position, out cluster))
} {
cluster = ExtendChain();
if (count < 0) _reader.WipeCluster(cluster);
{ }
throw new ArgumentOutOfRangeException("count", count, "Attempting to write negative number of bytes");
} // Fill this cluster with as much data as we can (WriteToCluster preserves existing cluster
// data, if necessary)
if (offset > buffer.Length || (offset + count) > buffer.Length) int numWritten = WriteToCluster(cluster, (int)(_position % _reader.ClusterSize), buffer, offset,
{ bytesRemaining);
throw new ArgumentException("Attempt to write bytes outside of the buffer"); offset += numWritten;
} bytesRemaining -= numWritten;
_position += numWritten;
// TODO: Free space check... }
try
{ _length = (uint)Math.Max(_length, _position);
while (bytesRemaining > 0) }
{ finally
// Extend the stream until it encompasses _position {
uint cluster; _fat.Flush();
while (!TryGetClusterByPosition(_position, out cluster)) }
{
cluster = ExtendChain(); _atEOF = false;
_reader.WipeCluster(cluster); }
}
/// <summary>
// Fill this cluster with as much data as we can (WriteToCluster preserves existing cluster /// Writes up to the next cluster boundary, making sure to preserve existing data in the cluster
// data, if necessary) /// that falls outside of the updated range.
int numWritten = WriteToCluster(cluster, (int)(_position % _reader.ClusterSize), buffer, offset, bytesRemaining); /// </summary>
offset += numWritten; /// <param name="cluster">The cluster to write to.</param>
bytesRemaining -= numWritten; /// <param name="pos">The file position of the write (within the cluster).</param>
_position += numWritten; /// <param name="buffer">The buffer with the new data.</param>
} /// <param name="offset">Offset into buffer of the first byte to write.</param>
/// <param name="count">The maximum number of bytes to write.</param>
_length = (uint)Math.Max(_length, _position); /// <returns>The number of bytes written - either count, or the number that fit up to
} /// the cluster boundary.</returns>
finally private int WriteToCluster(uint cluster, int pos, byte[] buffer, int offset, int count)
{ {
_fat.Flush(); if (pos == 0 && count >= _reader.ClusterSize)
} {
_currentCluster = cluster;
_atEOF = false; Array.Copy(buffer, offset, _clusterBuffer, 0, _reader.ClusterSize);
}
WriteCurrentCluster();
/// <summary>
/// Writes up to the next cluster boundary, making sure to preserve existing data in the cluster return _reader.ClusterSize;
/// that falls outside of the updated range. }
/// </summary>
/// <param name="cluster">The cluster to write to.</param> // Partial cluster, so need to read existing cluster data first
/// <param name="pos">The file position of the write (within the cluster).</param> LoadCluster(cluster);
/// <param name="buffer">The buffer with the new data.</param>
/// <param name="offset">Offset into buffer of the first byte to write.</param> int copyLength = Math.Min(count, _reader.ClusterSize - (pos % _reader.ClusterSize));
/// <param name="count">The maximum number of bytes to write.</param> Array.Copy(buffer, offset, _clusterBuffer, pos, copyLength);
/// <returns>The number of bytes written - either count, or the number that fit up to
/// the cluster boundary.</returns> WriteCurrentCluster();
private int WriteToCluster(uint cluster, int pos, byte[] buffer, int offset, int count)
{ return copyLength;
if (pos == 0 && count >= _reader.ClusterSize) }
{
_currentCluster = cluster; /// <summary>
Array.Copy(buffer, offset, _clusterBuffer, 0, _reader.ClusterSize); /// Adds a new cluster to the end of the existing chain, by allocating a free cluster.
/// </summary>
WriteCurrentCluster(); /// <returns>The cluster allocated.</returns>
/// <remarks>This method does not initialize the data in the cluster, the caller should
return _reader.ClusterSize; /// perform a write to ensure the cluster data is in known state.</remarks>
} private uint ExtendChain()
else {
{ // Sanity check - make sure the final known cluster is the EOC marker
// Partial cluster, so need to read existing cluster data first if (!_fat.IsEndOfChain(_knownClusters[^1]))
LoadCluster(cluster); {
throw new IOException("Corrupt file system: final cluster isn't End-of-Chain");
int copyLength = Math.Min(count, (int)(_reader.ClusterSize - (pos % _reader.ClusterSize))); }
Array.Copy(buffer, offset, _clusterBuffer, pos, copyLength);
if (!_fat.TryGetFreeCluster(out uint cluster))
WriteCurrentCluster(); {
throw new IOException("Out of disk space");
return copyLength; }
}
} _fat.SetEndOfChain(cluster);
if (_knownClusters.Count == 1)
/// <summary> {
/// Adds a new cluster to the end of the existing chain, by allocating a free cluster. FireFirstClusterAllocated(cluster);
/// </summary> }
/// <returns>The cluster allocated.</returns> else
/// <remarks>This method does not initialize the data in the cluster, the caller should {
/// perform a write to ensure the cluster data is in known state.</remarks> _fat.SetNext(_knownClusters[^2], cluster);
private uint ExtendChain() }
{
// Sanity check - make sure the final known cluster is the EOC marker _knownClusters[^1] = cluster;
if (!_fat.IsEndOfChain(_knownClusters[_knownClusters.Count - 1])) _knownClusters.Add(_fat.GetNext(cluster));
{
throw new IOException("Corrupt file system: final cluster isn't End-of-Chain"); return cluster;
} }
uint cluster; private void FireFirstClusterAllocated(uint cluster)
if (!_fat.TryGetFreeCluster(out cluster)) {
{ if (FirstClusterChanged != null)
throw new IOException("Out of disk space"); {
} FirstClusterChanged(cluster);
}
_fat.SetEndOfChain(cluster); }
if (_knownClusters.Count == 1)
{ private bool TryLoadCurrentCluster()
FireFirstClusterAllocated(cluster); {
} return TryLoadClusterByPosition(_position);
else }
{
_fat.SetNext(_knownClusters[_knownClusters.Count - 2], cluster); private bool TryLoadClusterByPosition(long pos)
} {
if (!TryGetClusterByPosition(pos, out uint cluster))
_knownClusters[_knownClusters.Count - 1] = cluster; {
_knownClusters.Add(_fat.GetNext(cluster)); return false;
}
return cluster;
} // Read the cluster, it's different to the one currently loaded
if (cluster != _currentCluster)
private void FireFirstClusterAllocated(uint cluster) {
{ _reader.ReadCluster(cluster, _clusterBuffer, 0);
if (FirstClusterChanged != null) _currentCluster = cluster;
{ }
FirstClusterChanged(cluster);
} return true;
} }
private bool TryLoadCurrentCluster() private void LoadCluster(uint cluster)
{ {
return TryLoadClusterByPosition(_position); // Read the cluster, it's different to the one currently loaded
} if (cluster != _currentCluster)
{
private bool TryLoadClusterByPosition(long pos) _reader.ReadCluster(cluster, _clusterBuffer, 0);
{ _currentCluster = cluster;
uint cluster; }
if (!TryGetClusterByPosition(pos, out cluster)) }
{
return false; private void WriteCurrentCluster()
} {
_reader.WriteCluster(_currentCluster, _clusterBuffer, 0);
// Read the cluster, it's different to the one currently loaded }
if (cluster != _currentCluster)
{ private bool TryGetClusterByPosition(long pos, out uint cluster)
_reader.ReadCluster(cluster, _clusterBuffer, 0); {
_currentCluster = cluster; int index = (int)(pos / _reader.ClusterSize);
}
if (_knownClusters.Count <= index && !TryPopulateKnownClusters(index))
return true; {
} cluster = uint.MaxValue;
return false;
private void LoadCluster(uint cluster) }
{
// Read the cluster, it's different to the one currently loaded // Chain is shorter than the current stream position
if (cluster != _currentCluster) if (_knownClusters.Count <= index)
{ {
_reader.ReadCluster(cluster, _clusterBuffer, 0); cluster = uint.MaxValue;
_currentCluster = cluster; return false;
} }
}
cluster = _knownClusters[index];
private void WriteCurrentCluster()
{ // This is the 'special' End-of-chain cluster identifer, so the stream position
_reader.WriteCluster(_currentCluster, _clusterBuffer, 0); // is greater than the actual file length.
} if (_fat.IsEndOfChain(cluster))
{
private bool TryGetClusterByPosition(long pos, out uint cluster) return false;
{ }
int index = (int)(pos / _reader.ClusterSize);
return true;
if (_knownClusters.Count <= index) }
{
if (!TryPopulateKnownClusters(index)) private bool TryPopulateKnownClusters(int index)
{ {
cluster = uint.MaxValue; uint lastKnown = _knownClusters[^1];
return false; while (!_fat.IsEndOfChain(lastKnown) && _knownClusters.Count <= index)
} {
} lastKnown = _fat.GetNext(lastKnown);
_knownClusters.Add(lastKnown);
// Chain is shorter than the current stream position }
if (_knownClusters.Count <= index)
{ return _knownClusters.Count > index;
cluster = uint.MaxValue; }
return false;
} private uint DetectLength()
{
cluster = _knownClusters[(int)index]; while (!_fat.IsEndOfChain(_knownClusters[^1]))
{
// This is the 'special' End-of-chain cluster identifer, so the stream position if (!TryPopulateKnownClusters(_knownClusters.Count))
// is greater than the actual file length. {
if (_fat.IsEndOfChain(cluster)) throw new IOException("Corrupt file stream - unable to discover end of cluster chain");
{ }
return false; }
}
return (uint)((_knownClusters.Count - 1) * (long)_reader.ClusterSize);
return true; }
} }
}
private bool TryPopulateKnownClusters(int index)
{
uint lastKnown = _knownClusters[_knownClusters.Count - 1];
while (!_fat.IsEndOfChain(lastKnown) && _knownClusters.Count <= index)
{
lastKnown = _fat.GetNext(lastKnown);
_knownClusters.Add(lastKnown);
}
return _knownClusters.Count > index;
}
private uint DetectLength()
{
while (!_fat.IsEndOfChain(_knownClusters[_knownClusters.Count - 1]))
{
if (!TryPopulateKnownClusters(_knownClusters.Count))
{
throw new IOException("Corrupt file stream - unable to discover end of cluster chain");
}
}
return (uint)((long)(_knownClusters.Count - 1) * (long)_reader.ClusterSize);
}
}
}
@@ -1,223 +1,207 @@
// //
// Copyright (c) 2008-2011, Kenneth Bell // Copyright (c) 2008-2011, Kenneth Bell
// //
// Permission is hereby granted, free of charge, to any person obtaining a // Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"), // copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation // to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, // the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the // and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions: // Software is furnished to do so, subject to the following conditions:
// //
// The above copyright notice and this permission notice shall be included in // The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software. // all copies or substantial portions of the Software.
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
// //
namespace DiscUtils.Fat using System;
{ using System.IO;
using System; using DiscUtils.Streams;
using System.IO;
using System.Text; namespace DiscUtils.Fat
{
internal class DirectoryEntry internal class DirectoryEntry
{ {
private FatFileSystemOptions _options; private readonly FatType _fatVariant;
private FatType _fatVariant; private readonly FatFileSystemOptions _options;
private FileName _name; private byte _attr;
private byte _attr; private ushort _creationDate;
private byte _creationTimeTenth; private ushort _creationTime;
private ushort _creationTime; private byte _creationTimeTenth;
private ushort _creationDate; private uint _fileSize;
private ushort _lastAccessDate; private ushort _firstClusterHi;
private ushort _firstClusterHi; private ushort _firstClusterLo;
private ushort _lastWriteTime; private ushort _lastAccessDate;
private ushort _lastWriteDate; private ushort _lastWriteDate;
private ushort _firstClusterLo; private ushort _lastWriteTime;
private uint _fileSize;
internal DirectoryEntry(FatFileSystemOptions options, Stream stream, FatType fatVariant)
internal DirectoryEntry(FatFileSystemOptions options, Stream stream, FatType fatVariant) {
{ _options = options;
_options = options; _fatVariant = fatVariant;
_fatVariant = fatVariant; byte[] buffer = StreamUtilities.ReadExact(stream, 32);
byte[] buffer = Utilities.ReadFully(stream, 32); Load(buffer, 0);
Load(buffer, 0); }
}
internal DirectoryEntry(FatFileSystemOptions options, FileName name, FatAttributes attrs, FatType fatVariant)
internal DirectoryEntry(FatFileSystemOptions options, FileName name, FatAttributes attrs, FatType fatVariant) {
{ _options = options;
_options = options; _fatVariant = fatVariant;
_fatVariant = fatVariant; Name = name;
_name = name; _attr = (byte)attrs;
_attr = (byte)attrs; }
}
internal DirectoryEntry(DirectoryEntry toCopy)
internal DirectoryEntry(DirectoryEntry toCopy) {
{ _options = toCopy._options;
_options = toCopy._options; _fatVariant = toCopy._fatVariant;
_fatVariant = toCopy._fatVariant; Name = toCopy.Name;
_name = toCopy._name; _attr = toCopy._attr;
_attr = toCopy._attr; _creationTimeTenth = toCopy._creationTimeTenth;
_creationTimeTenth = toCopy._creationTimeTenth; _creationTime = toCopy._creationTime;
_creationTime = toCopy._creationTime; _creationDate = toCopy._creationDate;
_creationDate = toCopy._creationDate; _lastAccessDate = toCopy._lastAccessDate;
_lastAccessDate = toCopy._lastAccessDate; _firstClusterHi = toCopy._firstClusterHi;
_firstClusterHi = toCopy._firstClusterHi; _lastWriteTime = toCopy._lastWriteTime;
_lastWriteTime = toCopy._lastWriteTime; _firstClusterLo = toCopy._firstClusterLo;
_firstClusterLo = toCopy._firstClusterLo; _fileSize = toCopy._fileSize;
_fileSize = toCopy._fileSize; }
}
public FatAttributes Attributes
public FileName Name {
{ get { return (FatAttributes)_attr; }
get set { _attr = (byte)value; }
{ }
return _name;
} public DateTime CreationTime
{
set get { return FileTimeToDateTime(_creationDate, _creationTime, _creationTimeTenth); }
{ set { DateTimeToFileTime(value, out _creationDate, out _creationTime, out _creationTimeTenth); }
_name = value; }
}
} public int FileSize
{
public FatAttributes Attributes get { return (int)_fileSize; }
{ set { _fileSize = (uint)value; }
get { return (FatAttributes)_attr; } }
set { _attr = (byte)value; }
} public uint FirstCluster
{
public DateTime CreationTime get
{ {
get { return FileTimeToDateTime(_creationDate, _creationTime, _creationTimeTenth); } if (_fatVariant == FatType.Fat32)
set { DateTimeToFileTime(value, out _creationDate, out _creationTime, out _creationTimeTenth); } {
} return (uint)(_firstClusterHi << 16) | _firstClusterLo;
}
public DateTime LastAccessTime return _firstClusterLo;
{ }
get { return FileTimeToDateTime(_lastAccessDate, 0, 0); }
set { DateTimeToFileTime(value, out _lastAccessDate); } set
} {
if (_fatVariant == FatType.Fat32)
public DateTime LastWriteTime {
{ _firstClusterHi = (ushort)((value >> 16) & 0xFFFF);
get { return FileTimeToDateTime(_lastWriteDate, _lastWriteTime, 0); } }
set { DateTimeToFileTime(value, out _lastWriteDate, out _lastWriteTime); }
} _firstClusterLo = (ushort)(value & 0xFFFF);
}
public int FileSize }
{
get { return (int)_fileSize; } public DateTime LastAccessTime
set { _fileSize = (uint)value; } {
} get { return FileTimeToDateTime(_lastAccessDate, 0, 0); }
set { DateTimeToFileTime(value, out _lastAccessDate); }
public uint FirstCluster }
{
get public DateTime LastWriteTime
{ {
if (_fatVariant == FatType.Fat32) get { return FileTimeToDateTime(_lastWriteDate, _lastWriteTime, 0); }
{ set { DateTimeToFileTime(value, out _lastWriteDate, out _lastWriteTime); }
return (uint)(_firstClusterHi << 16) | _firstClusterLo; }
}
else public FileName Name { get; set; }
{
return _firstClusterLo; internal void WriteTo(Stream stream)
} {
} byte[] buffer = new byte[32];
set Name.GetBytes(buffer, 0);
{ buffer[11] = _attr;
if (_fatVariant == FatType.Fat32) buffer[13] = _creationTimeTenth;
{ EndianUtilities.WriteBytesLittleEndian(_creationTime, buffer, 14);
_firstClusterHi = (ushort)((value >> 16) & 0xFFFF); EndianUtilities.WriteBytesLittleEndian(_creationDate, buffer, 16);
} EndianUtilities.WriteBytesLittleEndian(_lastAccessDate, buffer, 18);
EndianUtilities.WriteBytesLittleEndian(_firstClusterHi, buffer, 20);
_firstClusterLo = (ushort)(value & 0xFFFF); EndianUtilities.WriteBytesLittleEndian(_lastWriteTime, buffer, 22);
} EndianUtilities.WriteBytesLittleEndian(_lastWriteDate, buffer, 24);
} EndianUtilities.WriteBytesLittleEndian(_firstClusterLo, buffer, 26);
EndianUtilities.WriteBytesLittleEndian(_fileSize, buffer, 28);
internal void WriteTo(Stream stream)
{ stream.Write(buffer, 0, buffer.Length);
byte[] buffer = new byte[32]; }
_name.GetBytes(buffer, 0); private static DateTime FileTimeToDateTime(ushort date, ushort time, byte tenths)
buffer[11] = _attr; {
buffer[13] = _creationTimeTenth; if (date == 0 || date == 0xFFFF)
Utilities.WriteBytesLittleEndian((ushort)_creationTime, buffer, 14); {
Utilities.WriteBytesLittleEndian((ushort)_creationDate, buffer, 16); // Return Epoch - this is an invalid date
Utilities.WriteBytesLittleEndian((ushort)_lastAccessDate, buffer, 18); return FatFileSystem.Epoch;
Utilities.WriteBytesLittleEndian((ushort)_firstClusterHi, buffer, 20); }
Utilities.WriteBytesLittleEndian((ushort)_lastWriteTime, buffer, 22);
Utilities.WriteBytesLittleEndian((ushort)_lastWriteDate, buffer, 24); int year = 1980 + ((date & 0xFE00) >> 9);
Utilities.WriteBytesLittleEndian((ushort)_firstClusterLo, buffer, 26); int month = (date & 0x01E0) >> 5;
Utilities.WriteBytesLittleEndian((uint)_fileSize, buffer, 28); int day = date & 0x001F;
int hour = (time & 0xF800) >> 11;
stream.Write(buffer, 0, buffer.Length); int minute = (time & 0x07E0) >> 5;
} int second = ((time & 0x001F) * 2) + (tenths / 100);
int millis = tenths % 100 * 10;
private static DateTime FileTimeToDateTime(ushort date, ushort time, byte tenths)
{ return new DateTime(year, month, day, hour, minute, second, millis);
if (date == 0 || date == 0xFFFF) }
{
// Return Epoch - this is an invalid date private static void DateTimeToFileTime(DateTime value, out ushort date)
return FatFileSystem.Epoch; {
} DateTimeToFileTime(value, out date, out ushort time, out byte tenths);
}
int year = 1980 + ((date & 0xFE00) >> 9);
int month = (date & 0x01E0) >> 5; private static void DateTimeToFileTime(DateTime value, out ushort date, out ushort time)
int day = date & 0x001F; {
int hour = (time & 0xF800) >> 11; DateTimeToFileTime(value, out date, out time, out byte tenths);
int minute = (time & 0x07E0) >> 5; }
int second = ((time & 0x001F) * 2) + (tenths / 100);
int millis = (tenths % 100) * 10; private static void DateTimeToFileTime(DateTime value, out ushort date, out ushort time, out byte tenths)
{
return new DateTime(year, month, day, hour, minute, second, millis); if (value.Year < 1980)
} {
value = FatFileSystem.Epoch;
private static void DateTimeToFileTime(DateTime value, out ushort date) }
{
byte tenths; date =
ushort time; (ushort)((((value.Year - 1980) << 9) & 0xFE00) | ((value.Month << 5) & 0x01E0) | (value.Day & 0x001F));
DateTimeToFileTime(value, out date, out time, out tenths); time =
} (ushort)(((value.Hour << 11) & 0xF800) | ((value.Minute << 5) & 0x07E0) | ((value.Second / 2) & 0x001F));
tenths = (byte)((value.Second % 2 * 100) + (value.Millisecond / 10));
private static void DateTimeToFileTime(DateTime value, out ushort date, out ushort time) }
{
byte tenths; private void Load(byte[] data, int offset)
DateTimeToFileTime(value, out date, out time, out tenths); {
} Name = new FileName(data, offset);
_attr = data[offset + 11];
private static void DateTimeToFileTime(DateTime value, out ushort date, out ushort time, out byte tenths) _creationTimeTenth = data[offset + 13];
{ _creationTime = EndianUtilities.ToUInt16LittleEndian(data, offset + 14);
if (value.Year < 1980) _creationDate = EndianUtilities.ToUInt16LittleEndian(data, offset + 16);
{ _lastAccessDate = EndianUtilities.ToUInt16LittleEndian(data, offset + 18);
value = FatFileSystem.Epoch; _firstClusterHi = EndianUtilities.ToUInt16LittleEndian(data, offset + 20);
} _lastWriteTime = EndianUtilities.ToUInt16LittleEndian(data, offset + 22);
_lastWriteDate = EndianUtilities.ToUInt16LittleEndian(data, offset + 24);
date = (ushort)((((value.Year - 1980) << 9) & 0xFE00) | ((value.Month << 5) & 0x01E0) | (value.Day & 0x001F)); _firstClusterLo = EndianUtilities.ToUInt16LittleEndian(data, offset + 26);
time = (ushort)(((value.Hour << 11) & 0xF800) | ((value.Minute << 5) & 0x07E0) | ((value.Second / 2) & 0x001F)); _fileSize = EndianUtilities.ToUInt32LittleEndian(data, offset + 28);
tenths = (byte)(((value.Second % 2) * 100) + (value.Millisecond / 10)); }
} }
}
private void Load(byte[] data, int offset)
{
_name = new FileName(data, offset);
_attr = data[offset + 11];
_creationTimeTenth = data[offset + 13];
_creationTime = Utilities.ToUInt16LittleEndian(data, offset + 14);
_creationDate = Utilities.ToUInt16LittleEndian(data, offset + 16);
_lastAccessDate = Utilities.ToUInt16LittleEndian(data, offset + 18);
_firstClusterHi = Utilities.ToUInt16LittleEndian(data, offset + 20);
_lastWriteTime = Utilities.ToUInt16LittleEndian(data, offset + 22);
_lastWriteDate = Utilities.ToUInt16LittleEndian(data, offset + 24);
_firstClusterLo = Utilities.ToUInt16LittleEndian(data, offset + 26);
_fileSize = Utilities.ToUInt32LittleEndian(data, offset + 28);
}
}
}
@@ -0,0 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\DiscUtils.Core\DiscUtils.Core.WPI.csproj" />
</ItemGroup>
</Project>
@@ -1,37 +1,37 @@
// //
// Copyright (c) 2008-2011, Kenneth Bell // Copyright (c) 2008-2011, Kenneth Bell
// //
// Permission is hereby granted, free of charge, to any person obtaining a // Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"), // copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation // to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, // the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the // and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions: // Software is furnished to do so, subject to the following conditions:
// //
// The above copyright notice and this permission notice shall be included in // The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software. // all copies or substantial portions of the Software.
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
// //
namespace DiscUtils.Fat using System;
{
using System; namespace DiscUtils.Fat
{
[Flags] [Flags]
internal enum FatAttributes : byte internal enum FatAttributes : byte
{ {
ReadOnly = 0x01, ReadOnly = 0x01,
Hidden = 0x02, Hidden = 0x02,
System = 0x04, System = 0x04,
VolumeId = 0x08, VolumeId = 0x08,
Directory = 0x10, Directory = 0x10,
Archive = 0x20, Archive = 0x20
} }
} }
@@ -1,262 +1,257 @@
// //
// Copyright (c) 2008-2011, Kenneth Bell // Copyright (c) 2008-2011, Kenneth Bell
// //
// Permission is hereby granted, free of charge, to any person obtaining a // Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"), // copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation // to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, // the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the // and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions: // Software is furnished to do so, subject to the following conditions:
// //
// The above copyright notice and this permission notice shall be included in // The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software. // all copies or substantial portions of the Software.
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
// //
namespace DiscUtils.Fat using System;
{ using System.Collections.Generic;
using System; using System.IO;
using System.Collections.Generic; using DiscUtils.Streams;
using System.IO;
namespace DiscUtils.Fat
internal class FatBuffer {
{ internal class FatBuffer
/// <summary> {
/// The End-of-chain marker to WRITE (SetNext). Don't use this value to test for end of chain. /// <summary>
/// </summary> /// The End-of-chain marker to WRITE (SetNext). Don't use this value to test for end of chain.
/// <remarks> /// </summary>
/// The actual end-of-chain marker bits on disk vary by FAT type, and can end ...F8 through ...FF. /// <remarks>
/// </remarks> /// The actual end-of-chain marker bits on disk vary by FAT type, and can end ...F8 through ...FF.
public const uint EndOfChain = 0xFFFFFFFF; /// </remarks>
public const uint EndOfChain = 0xFFFFFFFF;
/// <summary>
/// The Bad-Cluster marker to WRITE (SetNext). Don't use this value to test for bad clusters. /// <summary>
/// </summary> /// The Bad-Cluster marker to WRITE (SetNext). Don't use this value to test for bad clusters.
/// <remarks> /// </summary>
/// The actual bad-cluster marker bits on disk vary by FAT type. /// <remarks>
/// </remarks> /// The actual bad-cluster marker bits on disk vary by FAT type.
public const uint BadCluster = 0xFFFFFFF7; /// </remarks>
public const uint BadCluster = 0xFFFFFFF7;
/// <summary>
/// The Free-Cluster marker to WRITE (SetNext). Don't use this value to test for free clusters. /// <summary>
/// </summary> /// The Free-Cluster marker to WRITE (SetNext). Don't use this value to test for free clusters.
/// <remarks> /// </summary>
/// The actual free-cluster marker bits on disk vary by FAT type. /// <remarks>
/// </remarks> /// The actual free-cluster marker bits on disk vary by FAT type.
public const uint FreeCluster = 0; /// </remarks>
public const uint FreeCluster = 0;
private const uint DirtyRegionSize = 512;
private const uint DirtyRegionSize = 512;
private FatType _type; private readonly byte[] _buffer;
private byte[] _buffer; private readonly Dictionary<uint, uint> _dirtySectors;
private uint _nextFreeCandidate;
private Dictionary<uint, uint> _dirtySectors; private readonly FatType _type;
private uint _nextFreeCandidate;
public FatBuffer(FatType type, byte[] buffer)
{ public FatBuffer(FatType type, byte[] buffer)
_type = type; {
_buffer = buffer; _type = type;
_dirtySectors = new Dictionary<uint, uint>(); _buffer = buffer;
} _dirtySectors = [];
}
internal int NumEntries
{ internal int NumEntries
get {
{ get
switch (_type) {
{ return _type switch
case FatType.Fat12: {
return (_buffer.Length / 3) * 2; FatType.Fat12 => _buffer.Length / 3 * 2,
case FatType.Fat16: FatType.Fat16 => _buffer.Length / 2,
return _buffer.Length / 2; // FAT32
default: // FAT32 _ => _buffer.Length / 4,
return _buffer.Length / 4; };
} }
} }
}
internal int Size
internal int Size {
{ get { return _buffer.Length; }
get { return _buffer.Length; } }
}
internal bool IsFree(uint val)
internal bool IsFree(uint val) {
{ return val == 0;
return val == 0; }
}
internal bool IsEndOfChain(uint val)
internal bool IsEndOfChain(uint val) {
{ return _type switch
switch (_type) {
{ FatType.Fat12 => (val & 0x0FFF) >= 0x0FF8,
case FatType.Fat12: return (val & 0x0FFF) >= 0x0FF8; FatType.Fat16 => (val & 0xFFFF) >= 0xFFF8,
case FatType.Fat16: return (val & 0xFFFF) >= 0xFFF8; FatType.Fat32 => (val & 0x0FFFFFF8) >= 0x0FFFFFF8,
case FatType.Fat32: return (val & 0x0FFFFFF8) >= 0x0FFFFFF8; _ => throw new ArgumentException("Unknown FAT type"),
default: throw new ArgumentException("Unknown FAT type"); };
} }
}
internal bool IsBadCluster(uint val)
internal bool IsBadCluster(uint val) {
{ return _type switch
switch (_type) {
{ FatType.Fat12 => (val & 0x0FFF) == 0x0FF7,
case FatType.Fat12: return (val & 0x0FFF) == 0x0FF7; FatType.Fat16 => (val & 0xFFFF) == 0xFFF7,
case FatType.Fat16: return (val & 0xFFFF) == 0xFFF7; FatType.Fat32 => (val & 0x0FFFFFF8) == 0x0FFFFFF7,
case FatType.Fat32: return (val & 0x0FFFFFF8) == 0x0FFFFFF7; _ => throw new ArgumentException("Unknown FAT type"),
default: throw new ArgumentException("Unknown FAT type"); };
} }
}
internal uint GetNext(uint cluster)
internal uint GetNext(uint cluster) {
{ if (_type == FatType.Fat16)
if (_type == FatType.Fat16) {
{ return EndianUtilities.ToUInt16LittleEndian(_buffer, (int)(cluster * 2));
return Utilities.ToUInt16LittleEndian(_buffer, (int)(cluster * 2)); }
} if (_type == FatType.Fat32)
else if (_type == FatType.Fat32) {
{ return EndianUtilities.ToUInt32LittleEndian(_buffer, (int)(cluster * 4)) & 0x0FFFFFFF;
return Utilities.ToUInt32LittleEndian(_buffer, (int)(cluster * 4)) & 0x0FFFFFFF; }
}
else // FAT12
{ if ((cluster & 1) != 0)
// FAT12 {
if ((cluster & 1) != 0) return
{ (uint)((EndianUtilities.ToUInt16LittleEndian(_buffer, (int)(cluster + (cluster / 2))) >> 4) & 0x0FFF);
return (uint)((Utilities.ToUInt16LittleEndian(_buffer, (int)(cluster + (cluster / 2))) >> 4) & 0x0FFF); }
} return (uint)(EndianUtilities.ToUInt16LittleEndian(_buffer, (int)(cluster + (cluster / 2))) & 0x0FFF);
else }
{
return (uint)(Utilities.ToUInt16LittleEndian(_buffer, (int)(cluster + (cluster / 2))) & 0x0FFF); internal void SetEndOfChain(uint cluster)
} {
} SetNext(cluster, EndOfChain);
} }
internal void SetEndOfChain(uint cluster) internal void SetBadCluster(uint cluster)
{ {
SetNext(cluster, EndOfChain); SetNext(cluster, BadCluster);
} }
internal void SetBadCluster(uint cluster) internal void SetFree(uint cluster)
{ {
SetNext(cluster, BadCluster); if (cluster < _nextFreeCandidate)
} {
_nextFreeCandidate = cluster;
internal void SetFree(uint cluster) }
{
if (cluster < _nextFreeCandidate) SetNext(cluster, FreeCluster);
{ }
_nextFreeCandidate = cluster;
} internal void SetNext(uint cluster, uint next)
{
SetNext(cluster, FreeCluster); if (_type == FatType.Fat16)
} {
MarkDirty(cluster * 2);
internal void SetNext(uint cluster, uint next) EndianUtilities.WriteBytesLittleEndian((ushort)next, _buffer, (int)(cluster * 2));
{ }
if (_type == FatType.Fat16) else if (_type == FatType.Fat32)
{ {
MarkDirty(cluster * 2); MarkDirty(cluster * 4);
Utilities.WriteBytesLittleEndian((ushort)next, _buffer, (int)(cluster * 2)); uint oldVal = EndianUtilities.ToUInt32LittleEndian(_buffer, (int)(cluster * 4));
} uint newVal = (oldVal & 0xF0000000) | (next & 0x0FFFFFFF);
else if (_type == FatType.Fat32) EndianUtilities.WriteBytesLittleEndian(newVal, _buffer, (int)(cluster * 4));
{ }
MarkDirty(cluster * 4); else
uint oldVal = Utilities.ToUInt32LittleEndian(_buffer, (int)(cluster * 4)); {
uint newVal = (oldVal & 0xF0000000) | (next & 0x0FFFFFFF); uint offset = cluster + (cluster / 2);
Utilities.WriteBytesLittleEndian((uint)newVal, _buffer, (int)(cluster * 4)); MarkDirty(offset);
} MarkDirty(offset + 1); // On alternate sector boundaries, cluster info crosses two sectors
else
{ ushort maskedOldVal;
uint offset = cluster + (cluster / 2); if ((cluster & 1) != 0)
MarkDirty(offset); {
MarkDirty(offset + 1); // On alternate sector boundaries, cluster info crosses two sectors next <<= 4;
maskedOldVal = (ushort)(EndianUtilities.ToUInt16LittleEndian(_buffer, (int)offset) & 0x000F);
ushort maskedOldVal; }
if ((cluster & 1) != 0) else
{ {
next = next << 4; next &= 0x0FFF;
maskedOldVal = (ushort)(Utilities.ToUInt16LittleEndian(_buffer, (int)offset) & 0x000F); maskedOldVal = (ushort)(EndianUtilities.ToUInt16LittleEndian(_buffer, (int)offset) & 0xF000);
} }
else
{ ushort newVal = (ushort)(maskedOldVal | next);
next = next & 0x0FFF;
maskedOldVal = (ushort)(Utilities.ToUInt16LittleEndian(_buffer, (int)offset) & 0xF000); EndianUtilities.WriteBytesLittleEndian(newVal, _buffer, (int)offset);
} }
}
ushort newVal = (ushort)(maskedOldVal | next);
internal bool TryGetFreeCluster(out uint cluster)
Utilities.WriteBytesLittleEndian(newVal, _buffer, (int)offset); {
} // Simple scan - don't hold a free list...
} uint numEntries = (uint)NumEntries;
for (uint i = 0; i < numEntries; i++)
internal bool TryGetFreeCluster(out uint cluster) {
{ uint candidate = (i + _nextFreeCandidate) % numEntries;
// Simple scan - don't hold a free list... if (IsFree(GetNext(candidate)))
uint numEntries = (uint)NumEntries; {
for (uint i = 0; i < numEntries; i++) cluster = candidate;
{ _nextFreeCandidate = candidate + 1;
uint candidate = (i + _nextFreeCandidate) % numEntries; return true;
if (IsFree(GetNext(candidate))) }
{ }
cluster = candidate;
_nextFreeCandidate = candidate + 1; cluster = 0;
return true; return false;
} }
}
internal void FreeChain(uint head)
cluster = 0; {
return false; foreach (uint cluster in GetChain(head))
} {
SetFree(cluster);
internal void FreeChain(uint head) }
{ }
foreach (uint cluster in GetChain(head))
{ internal List<uint> GetChain(uint head)
SetFree(cluster); {
} List<uint> result = [];
}
if (head != 0)
internal List<uint> GetChain(uint head) {
{ uint focus = head;
List<uint> result = new List<uint>(); while (!IsEndOfChain(focus))
{
if (head != 0) result.Add(focus);
{ focus = GetNext(focus);
uint focus = head; }
while (!IsEndOfChain(focus)) }
{
result.Add(focus); return result;
focus = GetNext(focus); }
}
} internal void MarkDirty(uint offset)
{
return result; _dirtySectors[offset / DirtyRegionSize] = offset / DirtyRegionSize;
} }
internal void MarkDirty(uint offset) internal void WriteDirtyRegions(Stream stream, long position)
{ {
_dirtySectors[offset / DirtyRegionSize] = offset / DirtyRegionSize; foreach (uint val in _dirtySectors.Values)
} {
stream.Position = position + (val * DirtyRegionSize);
internal void WriteDirtyRegions(Stream stream, long position) stream.Write(_buffer, (int)(val * DirtyRegionSize), (int)DirtyRegionSize);
{ }
foreach (uint val in _dirtySectors.Values) }
{
stream.Position = position + (val * DirtyRegionSize); internal void ClearDirtyRegions()
stream.Write(_buffer, (int)(val * DirtyRegionSize), (int)DirtyRegionSize); {
} _dirtySectors.Clear();
} }
}
internal void ClearDirtyRegions() }
{
_dirtySectors.Clear();
}
}
}
@@ -1,140 +1,138 @@
// //
// Copyright (c) 2008-2011, Kenneth Bell // Copyright (c) 2008-2011, Kenneth Bell
// //
// Permission is hereby granted, free of charge, to any person obtaining a // Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"), // copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation // to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, // the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the // and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions: // Software is furnished to do so, subject to the following conditions:
// //
// The above copyright notice and this permission notice shall be included in // The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software. // all copies or substantial portions of the Software.
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
// //
namespace DiscUtils.Fat using System;
{ using System.Collections.Generic;
using System; using System.IO;
using System.Collections.Generic; using DiscUtils.Streams;
using System.IO;
namespace DiscUtils.Fat
internal class FatFileStream : SparseStream {
{ internal class FatFileStream : SparseStream
private Directory _dir; {
private long _dirId; private readonly Directory _dir;
private ClusterStream _stream; private readonly long _dirId;
private readonly ClusterStream _stream;
private bool didWrite = false;
private bool didWrite;
public FatFileStream(FatFileSystem fileSystem, Directory dir, long fileId, FileAccess access)
{ public FatFileStream(FatFileSystem fileSystem, Directory dir, long fileId, FileAccess access)
_dir = dir; {
_dirId = fileId; _dir = dir;
_dirId = fileId;
DirectoryEntry dirEntry = _dir.GetEntry(_dirId);
_stream = new ClusterStream(fileSystem, access, (uint)dirEntry.FirstCluster, (uint)dirEntry.FileSize); DirectoryEntry dirEntry = _dir.GetEntry(_dirId);
_stream.FirstClusterChanged += FirstClusterAllocatedHandler; _stream = new ClusterStream(fileSystem, access, dirEntry.FirstCluster, (uint)dirEntry.FileSize);
} _stream.FirstClusterChanged += FirstClusterAllocatedHandler;
}
public override long Position
{ public override bool CanRead
get { return _stream.Position; } {
set { _stream.Position = value; } get { return _stream.CanRead; }
} }
public override bool CanRead public override bool CanSeek
{ {
get { return _stream.CanRead; } get { return _stream.CanSeek; }
} }
public override bool CanSeek public override bool CanWrite
{ {
get { return _stream.CanSeek; } get { return _stream.CanWrite; }
} }
public override bool CanWrite public override IEnumerable<StreamExtent> Extents
{ {
get { return _stream.CanWrite; } get { return new[] { new StreamExtent(0, Length) }; }
} }
public override long Length public override long Length
{ {
get { return _stream.Length; } get { return _stream.Length; }
} }
public override IEnumerable<StreamExtent> Extents public override long Position
{ {
get get { return _stream.Position; }
{ set { _stream.Position = value; }
return new StreamExtent[] { new StreamExtent(0, Length) }; }
}
} protected override void Dispose(bool disposing)
{
public override void Close() if (_dir.FileSystem.CanWrite)
{ {
if (_dir.FileSystem.CanWrite) try
{ {
try DateTime now = _dir.FileSystem.ConvertFromUtc(DateTime.UtcNow);
{
DateTime now = _dir.FileSystem.ConvertFromUtc(DateTime.UtcNow); DirectoryEntry dirEntry = _dir.GetEntry(_dirId);
dirEntry.LastAccessTime = now;
DirectoryEntry dirEntry = _dir.GetEntry(_dirId); if (didWrite)
dirEntry.LastAccessTime = now; {
if (didWrite) dirEntry.FileSize = (int)_stream.Length;
{ dirEntry.LastWriteTime = now;
dirEntry.FileSize = (int)_stream.Length; }
dirEntry.LastWriteTime = now;
} _dir.UpdateEntry(_dirId, dirEntry);
}
_dir.UpdateEntry(_dirId, dirEntry); finally
} {
finally base.Dispose(disposing);
{ }
base.Close(); }
} }
}
} public override void SetLength(long value)
{
public override void SetLength(long value) didWrite = true;
{ _stream.SetLength(value);
didWrite = true; }
_stream.SetLength(value);
} public override void Write(byte[] buffer, int offset, int count)
{
public override void Write(byte[] buffer, int offset, int count) didWrite = true;
{ _stream.Write(buffer, offset, count);
didWrite = true; }
_stream.Write(buffer, offset, count);
} public override void Flush()
{
public override void Flush() _stream.Flush();
{ }
_stream.Flush();
} public override int Read(byte[] buffer, int offset, int count)
{
public override int Read(byte[] buffer, int offset, int count) return _stream.Read(buffer, offset, count);
{ }
return _stream.Read(buffer, offset, count);
} public override long Seek(long offset, SeekOrigin origin)
{
public override long Seek(long offset, SeekOrigin origin) return _stream.Seek(offset, origin);
{ }
return _stream.Seek(offset, origin);
} private void FirstClusterAllocatedHandler(uint cluster)
{
private void FirstClusterAllocatedHandler(uint cluster) DirectoryEntry dirEntry = _dir.GetEntry(_dirId);
{ dirEntry.FirstCluster = cluster;
DirectoryEntry dirEntry = _dir.GetEntry(_dirId); _dir.UpdateEntry(_dirId, dirEntry);
dirEntry.FirstCluster = cluster; }
_dir.UpdateEntry(_dirId, dirEntry); }
} }
}
}
@@ -1,73 +1,70 @@
// //
// Copyright (c) 2008-2011, Kenneth Bell // Copyright (c) 2008-2011, Kenneth Bell
// //
// Permission is hereby granted, free of charge, to any person obtaining a // Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"), // copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation // to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, // the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the // and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions: // Software is furnished to do so, subject to the following conditions:
// //
// The above copyright notice and this permission notice shall be included in // The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software. // all copies or substantial portions of the Software.
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
// //
namespace DiscUtils.Fat using System;
{ using System.Text;
using System;
using System.Text; namespace DiscUtils.Fat
{
/// <summary> /// <summary>
/// FAT file system options. /// FAT file system options.
/// </summary> /// </summary>
public sealed class FatFileSystemOptions : DiscFileSystemOptions public sealed class FatFileSystemOptions : DiscFileSystemOptions
{ {
private Encoding _encoding; private Encoding _encoding;
internal FatFileSystemOptions() internal FatFileSystemOptions()
{ {
FileNameEncoding = Encoding.GetEncoding(437); FileNameEncoding = Encoding.GetEncoding(437);
} }
internal FatFileSystemOptions(FileSystemParameters parameters) internal FatFileSystemOptions(FileSystemParameters parameters)
{ {
if (parameters != null && parameters.FileNameEncoding != null) if (parameters?.FileNameEncoding != null)
{ {
FileNameEncoding = parameters.FileNameEncoding; FileNameEncoding = parameters.FileNameEncoding;
} }
else else
{ {
FileNameEncoding = Encoding.GetEncoding(437); FileNameEncoding = Encoding.GetEncoding(437);
} }
} }
/// <summary> /// <summary>
/// Gets or sets the character encoding used for file names. /// Gets or sets the character encoding used for file names.
/// </summary> /// </summary>
public Encoding FileNameEncoding public Encoding FileNameEncoding
{ {
get get { return _encoding; }
{
return _encoding; set
} {
if (!value.IsSingleByte)
set {
{ throw new ArgumentException(value.EncodingName + " is not a single byte encoding");
if (!value.IsSingleByte) }
{
throw new ArgumentException(value.EncodingName + " is not a single byte encoding"); _encoding = value;
} }
}
_encoding = value; }
} }
}
}
}
@@ -1,50 +1,50 @@
// //
// Copyright (c) 2008-2011, Kenneth Bell // Copyright (c) 2008-2011, Kenneth Bell
// //
// Permission is hereby granted, free of charge, to any person obtaining a // Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"), // copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation // to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, // the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the // and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions: // Software is furnished to do so, subject to the following conditions:
// //
// The above copyright notice and this permission notice shall be included in // The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software. // all copies or substantial portions of the Software.
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
// //
namespace DiscUtils.Fat namespace DiscUtils.Fat
{ {
/// <summary> /// <summary>
/// Enumeration of known FAT types. /// Enumeration of known FAT types.
/// </summary> /// </summary>
public enum FatType public enum FatType
{ {
/// <summary> /// <summary>
/// Represents no known FAT type. /// Represents no known FAT type.
/// </summary> /// </summary>
None = 0, None = 0,
/// <summary> /// <summary>
/// Represents a 12-bit FAT. /// Represents a 12-bit FAT.
/// </summary> /// </summary>
Fat12 = 12, Fat12 = 12,
/// <summary> /// <summary>
/// Represents a 16-bit FAT. /// Represents a 16-bit FAT.
/// </summary> /// </summary>
Fat16 = 16, Fat16 = 16,
/// <summary> /// <summary>
/// Represents a 32-bit FAT. /// Represents a 32-bit FAT.
/// </summary> /// </summary>
Fat32 = 32 Fat32 = 32
} }
} }
@@ -1,101 +1,106 @@
// //
// Copyright (c) 2008-2011, Kenneth Bell // Copyright (c) 2008-2011, Kenneth Bell
// //
// Permission is hereby granted, free of charge, to any person obtaining a // Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"), // copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation // to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, // the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the // and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions: // Software is furnished to do so, subject to the following conditions:
// //
// The above copyright notice and this permission notice shall be included in // The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software. // all copies or substantial portions of the Software.
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
// //
namespace DiscUtils.Fat using System.IO;
{ using DiscUtils.Streams;
using System;
using System.IO; namespace DiscUtils.Fat
{
internal class FileAllocationTable internal class FileAllocationTable
{ {
private Stream _stream; private readonly FatBuffer _buffer;
private ushort _firstFatSector; private readonly ushort _firstFatSector;
private byte _numFats; private readonly byte _numFats;
private readonly Stream _stream;
private FatBuffer _buffer;
public FileAllocationTable(FatType type, Stream stream, ushort firstFatSector, uint fatSize, byte numFats,
public FileAllocationTable(FatType type, Stream stream, ushort firstFatSector, uint fatSize, byte numFats, byte activeFat) byte activeFat)
{ {
_stream = stream; _stream = stream;
_firstFatSector = firstFatSector; _firstFatSector = firstFatSector;
_numFats = numFats; _numFats = numFats;
_stream.Position = (firstFatSector + (fatSize * activeFat)) * Utilities.SectorSize; _stream.Position = (firstFatSector + (fatSize * activeFat)) * Sizes.Sector;
_buffer = new FatBuffer(type, Utilities.ReadFully(_stream, (int)(fatSize * Utilities.SectorSize))); _buffer = new FatBuffer(type, StreamUtilities.ReadExact(_stream, (int)(fatSize * Sizes.Sector)));
} }
internal bool IsFree(uint val) internal bool IsFree(uint val)
{ {
return _buffer.IsFree(val); return _buffer.IsFree(val);
} }
internal bool IsEndOfChain(uint val) internal bool IsEndOfChain(uint val)
{ {
return _buffer.IsEndOfChain(val); return _buffer.IsEndOfChain(val);
} }
internal bool IsBadCluster(uint val) internal bool IsBadCluster(uint val)
{ {
return _buffer.IsBadCluster(val); return _buffer.IsBadCluster(val);
} }
internal uint GetNext(uint cluster) internal uint GetNext(uint cluster)
{ {
return _buffer.GetNext(cluster); return _buffer.GetNext(cluster);
} }
internal void SetEndOfChain(uint cluster) internal void SetEndOfChain(uint cluster)
{ {
_buffer.SetEndOfChain(cluster); _buffer.SetEndOfChain(cluster);
} }
internal void SetBadCluster(uint cluster) internal void SetBadCluster(uint cluster)
{ {
_buffer.SetBadCluster(cluster); _buffer.SetBadCluster(cluster);
} }
internal void SetNext(uint cluster, uint next) internal void SetNext(uint cluster, uint next)
{ {
_buffer.SetNext(cluster, next); _buffer.SetNext(cluster, next);
} }
internal void Flush() internal void Flush()
{ {
for (int i = 0; i < _numFats; ++i) for (int i = 0; i < _numFats; ++i)
{ {
_buffer.WriteDirtyRegions(_stream, (_firstFatSector * Utilities.SectorSize) + (_buffer.Size * i)); _buffer.WriteDirtyRegions(_stream, (_firstFatSector * Sizes.Sector) + (_buffer.Size * i));
} }
_buffer.ClearDirtyRegions(); _buffer.ClearDirtyRegions();
} }
internal bool TryGetFreeCluster(out uint cluster) internal bool TryGetFreeCluster(out uint cluster)
{ {
return _buffer.TryGetFreeCluster(out cluster); return _buffer.TryGetFreeCluster(out cluster);
} }
internal void FreeChain(uint head) internal void FreeChain(uint head)
{ {
_buffer.FreeChain(head); _buffer.FreeChain(head);
} }
}
} internal int NumEntries
{
get { return _buffer.NumEntries; }
}
}
}
@@ -1,212 +1,218 @@
// //
// Copyright (c) 2008-2011, Kenneth Bell // Copyright (c) 2008-2011, Kenneth Bell
// //
// Permission is hereby granted, free of charge, to any person obtaining a // Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"), // copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation // to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, // the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the // and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions: // Software is furnished to do so, subject to the following conditions:
// //
// The above copyright notice and this permission notice shall be included in // The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software. // all copies or substantial portions of the Software.
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
// //
namespace DiscUtils.Fat using System;
{ using System.Text;
using System; using DiscUtils.Internal;
using System.Text;
namespace DiscUtils.Fat
internal sealed class FileName : IEquatable<FileName> {
{ internal sealed class FileName : IEquatable<FileName>
public static readonly FileName SelfEntryName = new FileName(new byte[] { 0x2E, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20 }, 0); {
public static readonly FileName ParentEntryName = new FileName(new byte[] { 0x2E, 0x2E, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20 }, 0); private const byte SpaceByte = 0x20;
public static readonly FileName Null = new FileName(new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 0);
public static readonly FileName SelfEntryName =
private const byte SpaceByte = 0x20; new([0x2E, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20], 0);
private static readonly byte[] InvalidBytes = new byte[] { 0x22, 0x2A, 0x2B, 0x2C, 0x2E, 0x2F, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x5B, 0x5C, 0x5D, 0x7C }; public static readonly FileName ParentEntryName =
new([0x2E, 0x2E, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20], 0);
private byte[] _raw;
public static readonly FileName Null =
public FileName(byte[] data, int offset) new([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], 0);
{
_raw = new byte[11]; private static readonly byte[] InvalidBytes = [0x22, 0x2A, 0x2B, 0x2C, 0x2E, 0x2F, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x5B, 0x5C, 0x5D, 0x7C];
Array.Copy(data, offset, _raw, 0, 11);
} private readonly byte[] _raw;
public FileName(string name, Encoding encoding) public FileName(byte[] data, int offset)
{ {
_raw = new byte[11]; _raw = new byte[11];
byte[] bytes = encoding.GetBytes(name.ToUpperInvariant()); Array.Copy(data, offset, _raw, 0, 11);
}
int nameIdx = 0;
int rawIdx = 0; public FileName(string name, Encoding encoding)
while (nameIdx < bytes.Length && bytes[nameIdx] != '.' && rawIdx < _raw.Length) {
{ _raw = new byte[11];
byte b = bytes[nameIdx++]; byte[] bytes = encoding.GetBytes(name.ToUpperInvariant());
if (b < 0x20 || Contains(InvalidBytes, b))
{ int nameIdx = 0;
throw new ArgumentException("Invalid character in file name '" + (char)b + "'", "name"); int rawIdx = 0;
} while (nameIdx < bytes.Length && bytes[nameIdx] != '.' && rawIdx < _raw.Length)
{
_raw[rawIdx++] = b; byte b = bytes[nameIdx++];
} if (b < 0x20 || Contains(InvalidBytes, b))
{
if (rawIdx > 8) throw new ArgumentException("Invalid character in file name '" + (char)b + "'", nameof(name));
{ }
throw new ArgumentException("File name too long '" + name + "'", "name");
} _raw[rawIdx++] = b;
else if (rawIdx == 0) }
{
throw new ArgumentException("File name too short '" + name + "'", "name"); if (rawIdx > 8)
} {
throw new ArgumentException("File name too long '" + name + "'", nameof(name));
while (rawIdx < 8) }
{ if (rawIdx == 0)
_raw[rawIdx++] = SpaceByte; {
} throw new ArgumentException("File name too short '" + name + "'", nameof(name));
}
if (nameIdx < bytes.Length && bytes[nameIdx] == '.')
{ while (rawIdx < 8)
++nameIdx; {
} _raw[rawIdx++] = SpaceByte;
}
while (nameIdx < bytes.Length && rawIdx < _raw.Length)
{ if (nameIdx < bytes.Length && bytes[nameIdx] == '.')
byte b = bytes[nameIdx++]; {
if (b < 0x20 || Contains(InvalidBytes, b)) ++nameIdx;
{ }
throw new ArgumentException("Invalid character in file extension '" + (char)b + "'", "name");
} while (nameIdx < bytes.Length && rawIdx < _raw.Length)
{
_raw[rawIdx++] = b; byte b = bytes[nameIdx++];
} if (b < 0x20 || Contains(InvalidBytes, b))
{
while (rawIdx < 11) throw new ArgumentException("Invalid character in file extension '" + (char)b + "'", nameof(name));
{ }
_raw[rawIdx++] = SpaceByte;
} _raw[rawIdx++] = b;
}
if (nameIdx != bytes.Length)
{ while (rawIdx < 11)
throw new ArgumentException("File extension too long '" + name + "'", "name"); {
} _raw[rawIdx++] = SpaceByte;
} }
public static FileName FromPath(string path, Encoding encoding) if (nameIdx != bytes.Length)
{ {
return new FileName(Utilities.GetFileFromPath(path), encoding); throw new ArgumentException("File extension too long '" + name + "'", nameof(name));
} }
}
public static bool operator ==(FileName a, FileName b)
{ public bool Equals(FileName other)
return CompareRawNames(a, b) == 0; {
} if (other == null)
{
public static bool operator !=(FileName a, FileName b) return false;
{ }
return CompareRawNames(a, b) != 0;
} return CompareRawNames(this, other) == 0;
}
public string GetDisplayName(Encoding encoding)
{ public static FileName FromPath(string path, Encoding encoding)
return GetSearchName(encoding).TrimEnd('.'); {
} return new FileName(Utilities.GetFileFromPath(path), encoding);
}
public string GetSearchName(Encoding encoding)
{ public static bool operator ==(FileName a, FileName b)
return encoding.GetString(_raw, 0, 8).TrimEnd() + "." + encoding.GetString(_raw, 8, 3).TrimEnd(); {
} return CompareRawNames(a, b) == 0;
}
public string GetRawName(Encoding encoding)
{ public static bool operator !=(FileName a, FileName b)
return encoding.GetString(_raw, 0, 11).TrimEnd(); {
} return CompareRawNames(a, b) != 0;
}
public FileName Deleted()
{ public string GetDisplayName(Encoding encoding)
byte[] data = new byte[11]; {
Array.Copy(_raw, data, 11); return GetSearchName(encoding).TrimEnd('.');
data[0] = 0xE5; }
return new FileName(data, 0); public string GetSearchName(Encoding encoding)
} {
return encoding.GetString(_raw, 0, 8).TrimEnd() + "." + encoding.GetString(_raw, 8, 3).TrimEnd();
public bool IsDeleted() }
{
return _raw[0] == 0xE5; public string GetRawName(Encoding encoding)
} {
return encoding.GetString(_raw, 0, 11).TrimEnd();
public bool IsEndMarker() }
{
return _raw[0] == 0x00; public FileName Deleted()
} {
byte[] data = new byte[11];
public void GetBytes(byte[] data, int offset) Array.Copy(_raw, data, 11);
{ data[0] = 0xE5;
Array.Copy(_raw, 0, data, offset, 11);
} return new FileName(data, 0);
}
public override bool Equals(object other)
{ public bool IsDeleted()
return Equals(other as FileName); {
} return _raw[0] == 0xE5;
}
public bool Equals(FileName other)
{ public bool IsEndMarker()
if (other == null) {
{ return _raw[0] == 0x00;
return false; }
}
public void GetBytes(byte[] data, int offset)
return CompareRawNames(this, other) == 0; {
} Array.Copy(_raw, 0, data, offset, 11);
}
public override int GetHashCode()
{ public override bool Equals(object other)
int val = 0x1A8D3C4E; {
return Equals(other as FileName);
for (int i = 0; i < 11; ++i) }
{
val = (val << 2) ^ _raw[i]; public override int GetHashCode()
} {
int val = 0x1A8D3C4E;
return val;
} for (int i = 0; i < 11; ++i)
{
private static int CompareRawNames(FileName a, FileName b) val = (val << 2) ^ _raw[i];
{ }
for (int i = 0; i < 11; ++i)
{ return val;
if (a._raw[i] != b._raw[i]) }
{
return (int)a._raw[i] - (int)b._raw[i]; private static int CompareRawNames(FileName a, FileName b)
} {
} for (int i = 0; i < 11; ++i)
{
return 0; if (a._raw[i] != b._raw[i])
} {
return a._raw[i] - b._raw[i];
private static bool Contains(byte[] array, byte val) }
{ }
foreach (byte b in array)
{ return 0;
if (b == val) }
{
return true; private static bool Contains(byte[] array, byte val)
} {
} foreach (byte b in array)
{
return false; if (b == val)
} {
} return true;
} }
}
return false;
}
}
}
@@ -1,46 +1,47 @@
// //
// Copyright (c) 2008-2011, Kenneth Bell // Copyright (c) 2008-2011, Kenneth Bell
// //
// Permission is hereby granted, free of charge, to any person obtaining a // Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"), // copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation // to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, // the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the // and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions: // Software is furnished to do so, subject to the following conditions:
// //
// The above copyright notice and this permission notice shall be included in // The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software. // all copies or substantial portions of the Software.
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
// //
namespace DiscUtils.Fat using System.IO;
{ using DiscUtils.Vfs;
using System.IO; using DiscUtils.Streams;
using DiscUtils.Vfs;
namespace DiscUtils.Fat
[VfsFileSystemFactory] {
internal class FileSystemFactory : VfsFileSystemFactory [VfsFileSystemFactory]
{ internal class FileSystemFactory : VfsFileSystemFactory
public override DiscUtils.FileSystemInfo[] Detect(Stream stream, VolumeInfo volume) {
{ public override FileSystemInfo[] Detect(Stream stream, VolumeInfo volume)
if (FatFileSystem.Detect(stream)) {
{ if (FatFileSystem.Detect(stream))
return new DiscUtils.FileSystemInfo[] { new VfsFileSystemInfo("FAT", "Microsoft FAT", Open) }; {
} return [new VfsFileSystemInfo("FAT", "Microsoft FAT", Open)];
}
return new DiscUtils.FileSystemInfo[0];
} return [];
}
private DiscFileSystem Open(Stream stream, VolumeInfo volumeInfo, FileSystemParameters parameters)
{ private DiscFileSystem Open(Stream stream, VolumeInfo volumeInfo, FileSystemParameters parameters)
return new FatFileSystem(stream, Ownership.None, parameters); {
} return new FatFileSystem(stream, Ownership.None, parameters);
} }
} }
}
@@ -0,0 +1,4 @@
namespace DiscUtils.Fat
{
internal delegate void FirstClusterChangedDelegate(uint cluster);
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
-144
View File
@@ -1,144 +0,0 @@
//
// Copyright (c) 2008-2011, Kenneth Bell
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
namespace DiscUtils
{
using System;
using System.Collections.Generic;
using System.Globalization;
/// <summary>
/// Base class for all disk image builders.
/// </summary>
public abstract class DiskImageBuilder
{
private static Dictionary<string, VirtualDiskFactory> s_typeMap;
private SparseStream _content;
private Geometry _geometry;
private Geometry _biosGeometry;
private GenericDiskAdapterType _adaptorType;
/// <summary>
/// Gets or sets the content for this disk, implying the size of the disk.
/// </summary>
public SparseStream Content
{
get { return _content; }
set { _content = value; }
}
/// <summary>
/// Gets or sets the geometry of this disk, will be implied from the content stream if not set.
/// </summary>
public Geometry Geometry
{
get { return _geometry; }
set { _geometry = value; }
}
/// <summary>
/// Gets or sets the geometry of this disk, as reported by the BIOS, will be implied from the content stream if not set.
/// </summary>
public Geometry BiosGeometry
{
get { return _biosGeometry; }
set { _biosGeometry = value; }
}
/// <summary>
/// Gets or sets the adapter type for created virtual disk, for file formats that encode this information.
/// </summary>
public virtual GenericDiskAdapterType GenericAdapterType
{
get { return _adaptorType; }
set { _adaptorType = value; }
}
/// <summary>
/// Gets a value indicating whether this file format preserves BIOS geometry information.
/// </summary>
public virtual bool PreservesBiosGeometry
{
get { return false; }
}
private static Dictionary<string, VirtualDiskFactory> TypeMap
{
get
{
if (s_typeMap == null)
{
InitializeMaps();
}
return s_typeMap;
}
}
/// <summary>
/// Gets an instance that constructs the specified type (and variant) of virtual disk image.
/// </summary>
/// <param name="type">The type of image to build (VHD, VMDK, etc).</param>
/// <param name="variant">The variant type (differencing/dynamic, fixed/static, etc).</param>
/// <returns>The builder instance.</returns>
public static DiskImageBuilder GetBuilder(string type, string variant)
{
VirtualDiskFactory factory;
if (!TypeMap.TryGetValue(type, out factory))
{
throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, "Unknown disk type '{0}'", type), "type");
}
return factory.GetImageBuilder(variant);
}
/// <summary>
/// Initiates the construction of the disk image.
/// </summary>
/// <param name="baseName">The base name for the disk images.</param>
/// <returns>A set of one or more logical files that constitute the
/// disk image. The first file is the 'primary' file that is normally attached to VMs.</returns>
/// <remarks>The supplied <c>baseName</c> is the start of the file name, with no file
/// extension. The set of file specifications will indicate the actual name corresponding
/// to each logical file that comprises the disk image. For example, given a base name
/// 'foo', the files 'foo.vmdk' and 'foo-flat.vmdk' could be returned.</remarks>
public abstract DiskImageFileSpecification[] Build(string baseName);
private static void InitializeMaps()
{
Dictionary<string, VirtualDiskFactory> typeMap = new Dictionary<string, VirtualDiskFactory>();
foreach (var type in typeof(VirtualDisk).Assembly.GetTypes())
{
VirtualDiskFactoryAttribute attr = (VirtualDiskFactoryAttribute)Attribute.GetCustomAttribute(type, typeof(VirtualDiskFactoryAttribute), false);
if (attr != null)
{
VirtualDiskFactory factory = (VirtualDiskFactory)Activator.CreateInstance(type);
typeMap.Add(attr.Type, factory);
}
}
s_typeMap = typeMap;
}
}
}
-56
View File
@@ -1,56 +0,0 @@
//
// Copyright (c) 2008-2011, Kenneth Bell
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
namespace DiscUtils
{
/// <summary>
/// Describes a particular file that is a constituent part of a virtual disk.
/// </summary>
public sealed class DiskImageFileSpecification
{
private string _name;
private StreamBuilder _builder;
internal DiskImageFileSpecification(string name, StreamBuilder builder)
{
_name = name;
_builder = builder;
}
/// <summary>
/// Gets name of the file.
/// </summary>
public string Name
{
get { return _name; }
}
/// <summary>
/// Gets the object that provides access to the file's content.
/// </summary>
/// <returns>A stream object that contains the file's content.</returns>
public SparseStream OpenStream()
{
return _builder.Build();
}
}
}
-61
View File
@@ -1,61 +0,0 @@
//
// Copyright (c) 2008-2011, Kenneth Bell
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
namespace DiscUtils
{
using System;
using System.IO;
internal abstract class FileLocator
{
public abstract bool Exists(string fileName);
public abstract Stream Open(string fileName, FileMode mode, FileAccess access, FileShare share);
public abstract FileLocator GetRelativeLocator(string path);
public abstract string GetFullPath(string path);
public abstract string GetDirectoryFromPath(string path);
public abstract string GetFileFromPath(string path);
public abstract DateTime GetLastWriteTimeUtc(string path);
public abstract bool HasCommonRoot(FileLocator other);
public abstract string ResolveRelativePath(string path);
internal string MakeRelativePath(FileLocator fileLocator, string path)
{
if (!HasCommonRoot(fileLocator))
{
return null;
}
string ourFullPath = GetFullPath(string.Empty) + @"\";
string otherFullPath = fileLocator.GetFullPath(path);
return Utilities.MakeRelativePath(otherFullPath, ourFullPath);
}
}
}
-90
View File
@@ -1,90 +0,0 @@
//
// Copyright (c) 2008-2011, Kenneth Bell
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
namespace DiscUtils
{
using System.IO;
/// <summary>
/// Base class holding information about a file system.
/// </summary>
/// <remarks>
/// File system implementations derive from this class, to provide information about the file system.
/// </remarks>
public abstract class FileSystemInfo
{
/// <summary>
/// Gets the name of the file system.
/// </summary>
public abstract string Name { get; }
/// <summary>
/// Gets a one-line description of the file system.
/// </summary>
public abstract string Description { get; }
/// <summary>
/// Opens a volume using the file system.
/// </summary>
/// <param name="volume">The volume to access.</param>
/// <returns>A file system instance.</returns>
public DiscFileSystem Open(VolumeInfo volume)
{
return Open(volume, null);
}
/// <summary>
/// Opens a stream using the file system.
/// </summary>
/// <param name="stream">The stream to access.</param>
/// <returns>A file system instance.</returns>
public DiscFileSystem Open(Stream stream)
{
return Open(stream, null);
}
/// <summary>
/// Opens a volume using the file system.
/// </summary>
/// <param name="volume">The volume to access.</param>
/// <param name="parameters">Parameters for the file system.</param>
/// <returns>A file system instance.</returns>
public abstract DiscFileSystem Open(VolumeInfo volume, FileSystemParameters parameters);
/// <summary>
/// Opens a stream using the file system.
/// </summary>
/// <param name="stream">The stream to access.</param>
/// <param name="parameters">Parameters for the file system.</param>
/// <returns>A file system instance.</returns>
public abstract DiscFileSystem Open(Stream stream, FileSystemParameters parameters);
/// <summary>
/// Gets the name of the file system.
/// </summary>
/// <returns>The file system name.</returns>
public override string ToString()
{
return Name;
}
}
}
-58
View File
@@ -1,58 +0,0 @@
//
// Copyright (c) 2008-2011, Kenneth Bell
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
namespace DiscUtils
{
using System;
using System.Text;
/// <summary>
/// Converts a time to/from UTC.
/// </summary>
/// <param name="time">The time to convert.</param>
/// <param name="toUtc"><c>true</c> to convert FAT time to UTC, <c>false</c> to convert UTC to FAT time.</param>
/// <returns>The converted time.</returns>
public delegate DateTime TimeConverter(DateTime time, bool toUtc);
/// <summary>
/// Class with generic file system parameters.
/// </summary>
/// <remarks>Note - not all parameters apply to all types of file system.</remarks>
public sealed class FileSystemParameters
{
/// <summary>
/// Gets or sets the character encoding for file names, or <c>null</c> for default.
/// </summary>
/// <remarks>Some file systems, such as FAT, don't specify a particular character set for
/// file names. This parameter determines the character set that will be used for such
/// file systems.</remarks>
public Encoding FileNameEncoding { get; set; }
/// <summary>
/// Gets or sets the algorithm to convert file system time to UTC.
/// </summary>
/// <remarks>Some file system, such as FAT, don't have a defined way to convert from file system
/// time (local time where the file system is authored) to UTC time. This parameter determines
/// the algorithm to use.</remarks>
public TimeConverter TimeConverter { get; set; }
}
}
-45
View File
@@ -1,45 +0,0 @@
//
// Copyright (c) 2008-2011, Kenneth Bell
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
namespace DiscUtils
{
/// <summary>
/// The supported Floppy Disk logical formats.
/// </summary>
public enum FloppyDiskType
{
/// <summary>
/// 720KiB capacity disk.
/// </summary>
DoubleDensity = 0,
/// <summary>
/// 1440KiB capacity disk.
/// </summary>
HighDensity = 1,
/// <summary>
/// 2880KiB capacity disk.
/// </summary>
Extended = 2
}
}
-497
View File
@@ -1,497 +0,0 @@
//
// Copyright (c) 2008-2011, Kenneth Bell
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
namespace DiscUtils
{
using System;
using System.Globalization;
/// <summary>
/// Class whose instances represent disk geometries.
/// </summary>
/// <remarks>Instances of this class are immutable.</remarks>
public sealed class Geometry
{
private int _cylinders;
private int _headsPerCylinder;
private int _sectorsPerTrack;
private int _bytesPerSector;
/// <summary>
/// Initializes a new instance of the Geometry class. The default 512 bytes per sector is assumed.
/// </summary>
/// <param name="cylinders">The number of cylinders of the disk.</param>
/// <param name="headsPerCylinder">The number of heads (aka platters) of the disk.</param>
/// <param name="sectorsPerTrack">The number of sectors per track/cylinder of the disk.</param>
public Geometry(int cylinders, int headsPerCylinder, int sectorsPerTrack)
{
_cylinders = cylinders;
_headsPerCylinder = headsPerCylinder;
_sectorsPerTrack = sectorsPerTrack;
_bytesPerSector = 512;
}
/// <summary>
/// Initializes a new instance of the Geometry class.
/// </summary>
/// <param name="cylinders">The number of cylinders of the disk.</param>
/// <param name="headsPerCylinder">The number of heads (aka platters) of the disk.</param>
/// <param name="sectorsPerTrack">The number of sectors per track/cylinder of the disk.</param>
/// <param name="bytesPerSector">The number of bytes per sector of the disk.</param>
public Geometry(int cylinders, int headsPerCylinder, int sectorsPerTrack, int bytesPerSector)
{
_cylinders = cylinders;
_headsPerCylinder = headsPerCylinder;
_sectorsPerTrack = sectorsPerTrack;
_bytesPerSector = bytesPerSector;
}
/// <summary>
/// Initializes a new instance of the Geometry class.
/// </summary>
/// <param name="capacity">The total capacity of the disk.</param>
/// <param name="headsPerCylinder">The number of heads (aka platters) of the disk.</param>
/// <param name="sectorsPerTrack">The number of sectors per track/cylinder of the disk.</param>
/// <param name="bytesPerSector">The number of bytes per sector of the disk.</param>
public Geometry(long capacity, int headsPerCylinder, int sectorsPerTrack, int bytesPerSector)
{
_cylinders = (int)(capacity / (headsPerCylinder * (long)sectorsPerTrack * bytesPerSector));
_headsPerCylinder = headsPerCylinder;
_sectorsPerTrack = sectorsPerTrack;
_bytesPerSector = bytesPerSector;
}
/// <summary>
/// Gets a null geometry, which has 512-byte sectors but zero sectors, tracks or cylinders.
/// </summary>
public static Geometry Null
{
get { return new Geometry(0, 0, 0, 512); }
}
/// <summary>
/// Gets the number of cylinders.
/// </summary>
public int Cylinders
{
get { return _cylinders; }
}
/// <summary>
/// Gets the number of heads (aka platters).
/// </summary>
public int HeadsPerCylinder
{
get { return _headsPerCylinder; }
}
/// <summary>
/// Gets the number of sectors per track.
/// </summary>
public int SectorsPerTrack
{
get { return _sectorsPerTrack; }
}
/// <summary>
/// Gets the number of bytes in each sector.
/// </summary>
public int BytesPerSector
{
get { return _bytesPerSector; }
}
/// <summary>
/// Gets the total size of the disk (in sectors).
/// </summary>
[Obsolete("Use TotalSectorsLong instead, to support very large disks.")]
public int TotalSectors
{
get { return Cylinders * HeadsPerCylinder * SectorsPerTrack; }
}
/// <summary>
/// Gets the total size of the disk (in sectors).
/// </summary>
public long TotalSectorsLong
{
get { return (long)Cylinders * (long)HeadsPerCylinder * (long)SectorsPerTrack; }
}
/// <summary>
/// Gets the total capacity of the disk (in bytes).
/// </summary>
public long Capacity
{
get { return TotalSectorsLong * (long)BytesPerSector; }
}
/// <summary>
/// Gets the address of the last sector on the disk.
/// </summary>
public ChsAddress LastSector
{
get { return new ChsAddress(_cylinders - 1, _headsPerCylinder - 1, _sectorsPerTrack); }
}
/// <summary>
/// Gets a value indicating whether the Geometry is consistent with the values a BIOS can support.
/// </summary>
public bool IsBiosSafe
{
get { return _cylinders <= 1024 && _headsPerCylinder <= 255 && _sectorsPerTrack <= 63; }
}
/// <summary>
/// Gets a value indicating whether the Geometry is consistent with the values IDE can represent.
/// </summary>
public bool IsIdeSafe
{
get { return _cylinders <= 65536 && _headsPerCylinder <= 16 && _sectorsPerTrack <= 255; }
}
/// <summary>
/// Gets a value indicating whether the Geometry is representable both by the BIOS and by IDE.
/// </summary>
public bool IsBiosAndIdeSafe
{
get { return _cylinders <= 1024 && _headsPerCylinder <= 16 && _sectorsPerTrack <= 63; }
}
/// <summary>
/// Gets the 'Large' BIOS geometry for a disk, given it's physical geometry.
/// </summary>
/// <param name="ideGeometry">The physical (aka IDE) geometry of the disk.</param>
/// <returns>The geometry a BIOS using the 'Large' method for calculating disk geometry will indicate for the disk.</returns>
public static Geometry LargeBiosGeometry(Geometry ideGeometry)
{
int cylinders = ideGeometry.Cylinders;
int heads = ideGeometry.HeadsPerCylinder;
int sectors = ideGeometry.SectorsPerTrack;
while (cylinders > 1024 && heads <= 127)
{
cylinders >>= 1;
heads <<= 1;
}
return new Geometry(cylinders, heads, sectors);
}
/// <summary>
/// Gets the 'LBA Assisted' BIOS geometry for a disk, given it's capacity.
/// </summary>
/// <param name="capacity">The capacity of the disk.</param>
/// <returns>The geometry a BIOS using the 'LBA Assisted' method for calculating disk geometry will indicate for the disk.</returns>
public static Geometry LbaAssistedBiosGeometry(long capacity)
{
int heads;
if (capacity <= 504 * Sizes.OneMiB)
{
heads = 16;
}
else if (capacity <= 1008 * Sizes.OneMiB)
{
heads = 32;
}
else if (capacity <= 2016 * Sizes.OneMiB)
{
heads = 64;
}
else if (capacity <= 4032 * Sizes.OneMiB)
{
heads = 128;
}
else
{
heads = 255;
}
int sectors = 63;
int cylinders = (int)Math.Min(1024, capacity / (sectors * (long)heads * Sizes.Sector));
return new Geometry(cylinders, heads, sectors, Sizes.Sector);
}
/// <summary>
/// Converts a geometry into one that is BIOS-safe, if not already.
/// </summary>
/// <param name="geometry">The geometry to make BIOS-safe.</param>
/// <param name="capacity">The capacity of the disk.</param>
/// <returns>The new geometry.</returns>
/// <remarks>This method returns the LBA-Assisted geometry if the given geometry isn't BIOS-safe.</remarks>
public static Geometry MakeBiosSafe(Geometry geometry, long capacity)
{
if (geometry == null)
{
return LbaAssistedBiosGeometry(capacity);
}
else if (geometry.IsBiosSafe)
{
return geometry;
}
else
{
return LbaAssistedBiosGeometry(capacity);
}
}
/// <summary>
/// Calculates a sensible disk geometry for a disk capacity using the VHD algorithm (errs under).
/// </summary>
/// <param name="capacity">The desired capacity of the disk.</param>
/// <returns>The appropriate disk geometry.</returns>
/// <remarks>The geometry returned tends to produce a disk with less capacity
/// than requested (an exact capacity is not always possible). The geometry returned is the IDE
/// (aka Physical) geometry of the disk, not necessarily the geometry used by the BIOS.</remarks>
public static Geometry FromCapacity(long capacity)
{
return FromCapacity(capacity, Utilities.SectorSize);
}
/// <summary>
/// Calculates a sensible disk geometry for a disk capacity using the VHD algorithm (errs under).
/// </summary>
/// <param name="capacity">The desired capacity of the disk.</param>
/// <param name="sectorSize">The logical sector size of the disk.</param>
/// <returns>The appropriate disk geometry.</returns>
/// <remarks>The geometry returned tends to produce a disk with less capacity
/// than requested (an exact capacity is not always possible). The geometry returned is the IDE
/// (aka Physical) geometry of the disk, not necessarily the geometry used by the BIOS.</remarks>
public static Geometry FromCapacity(long capacity, int sectorSize)
{
int totalSectors;
int cylinders;
int headsPerCylinder;
int sectorsPerTrack;
// If more than ~128GB truncate at ~128GB
if (capacity > 65535 * (long)16 * 255 * sectorSize)
{
totalSectors = 65535 * 16 * 255;
}
else
{
totalSectors = (int)(capacity / sectorSize);
}
// If more than ~32GB, break partition table compatibility.
// Partition table has max 63 sectors per track. Otherwise
// we're looking for a geometry that's valid for both BIOS
// and ATA.
if (totalSectors > 65535 * 16 * 63)
{
sectorsPerTrack = 255;
headsPerCylinder = 16;
}
else
{
sectorsPerTrack = 17;
int cylindersTimesHeads = totalSectors / sectorsPerTrack;
headsPerCylinder = (cylindersTimesHeads + 1023) / 1024;
if (headsPerCylinder < 4)
{
headsPerCylinder = 4;
}
// If we need more than 1023 cylinders, or 16 heads, try more sectors per track
if (cylindersTimesHeads >= (headsPerCylinder * 1024U) || headsPerCylinder > 16)
{
sectorsPerTrack = 31;
headsPerCylinder = 16;
cylindersTimesHeads = totalSectors / sectorsPerTrack;
}
// We need 63 sectors per track to keep the cylinder count down
if (cylindersTimesHeads >= (headsPerCylinder * 1024U))
{
sectorsPerTrack = 63;
headsPerCylinder = 16;
}
}
cylinders = (totalSectors / sectorsPerTrack) / headsPerCylinder;
return new Geometry(cylinders, headsPerCylinder, sectorsPerTrack, sectorSize);
}
/// <summary>
/// Converts a CHS (Cylinder,Head,Sector) address to a LBA (Logical Block Address).
/// </summary>
/// <param name="chsAddress">The CHS address to convert.</param>
/// <returns>The Logical Block Address (in sectors).</returns>
public long ToLogicalBlockAddress(ChsAddress chsAddress)
{
return ToLogicalBlockAddress(chsAddress.Cylinder, chsAddress.Head, chsAddress.Sector);
}
/// <summary>
/// Converts a CHS (Cylinder,Head,Sector) address to a LBA (Logical Block Address).
/// </summary>
/// <param name="cylinder">The cylinder of the address.</param>
/// <param name="head">The head of the address.</param>
/// <param name="sector">The sector of the address.</param>
/// <returns>The Logical Block Address (in sectors).</returns>
public long ToLogicalBlockAddress(int cylinder, int head, int sector)
{
if (cylinder < 0)
{
throw new ArgumentOutOfRangeException("cylinder", cylinder, "cylinder number is negative");
}
if (head >= _headsPerCylinder)
{
throw new ArgumentOutOfRangeException("head", head, "head number is larger than disk geometry");
}
if (head < 0)
{
throw new ArgumentOutOfRangeException("head", head, "head number is negative");
}
if (sector > _sectorsPerTrack)
{
throw new ArgumentOutOfRangeException("sector", sector, "sector number is larger than disk geometry");
}
if (sector < 1)
{
throw new ArgumentOutOfRangeException("sector", sector, "sector number is less than one (sectors are 1-based)");
}
return (((cylinder * (long)_headsPerCylinder) + head) * _sectorsPerTrack) + sector - 1;
}
/// <summary>
/// Converts a LBA (Logical Block Address) to a CHS (Cylinder, Head, Sector) address.
/// </summary>
/// <param name="logicalBlockAddress">The logical block address (in sectors).</param>
/// <returns>The address in CHS form.</returns>
public ChsAddress ToChsAddress(long logicalBlockAddress)
{
if (logicalBlockAddress < 0)
{
throw new ArgumentOutOfRangeException("logicalBlockAddress", logicalBlockAddress, "Logical Block Address is negative");
}
int cylinder = (int)(logicalBlockAddress / (_headsPerCylinder * _sectorsPerTrack));
int temp = (int)(logicalBlockAddress % (_headsPerCylinder * _sectorsPerTrack));
int head = temp / _sectorsPerTrack;
int sector = (temp % _sectorsPerTrack) + 1;
return new ChsAddress(cylinder, head, sector);
}
/// <summary>
/// Translates an IDE (aka Physical) geometry to a BIOS (aka Logical) geometry.
/// </summary>
/// <param name="translation">The translation to perform.</param>
/// <returns>The translated disk geometry.</returns>
public Geometry TranslateToBios(GeometryTranslation translation)
{
return TranslateToBios(0, translation);
}
/// <summary>
/// Translates an IDE (aka Physical) geometry to a BIOS (aka Logical) geometry.
/// </summary>
/// <param name="capacity">The capacity of the disk, required if the geometry is an approximation on the actual disk size.</param>
/// <param name="translation">The translation to perform.</param>
/// <returns>The translated disk geometry.</returns>
public Geometry TranslateToBios(long capacity, GeometryTranslation translation)
{
if (capacity <= 0)
{
capacity = TotalSectorsLong * 512L;
}
switch (translation)
{
case GeometryTranslation.None:
return this;
case GeometryTranslation.Auto:
if (IsBiosSafe)
{
return this;
}
else
{
return Geometry.LbaAssistedBiosGeometry(capacity);
}
case GeometryTranslation.Lba:
return Geometry.LbaAssistedBiosGeometry(capacity);
case GeometryTranslation.Large:
return Geometry.LargeBiosGeometry(this);
default:
throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, "Translation mode '{0}' not yet implemented", translation), "translation");
}
}
/// <summary>
/// Determines if this object is equivalent to another.
/// </summary>
/// <param name="obj">The object to test against.</param>
/// <returns><c>true</c> if the <paramref name="obj"/> is equivalent, else <c>false</c>.</returns>
public override bool Equals(object obj)
{
if (obj == null || obj.GetType() != GetType())
{
return false;
}
Geometry other = (Geometry)obj;
return _cylinders == other._cylinders && _headsPerCylinder == other._headsPerCylinder
&& _sectorsPerTrack == other._sectorsPerTrack && _bytesPerSector == other._bytesPerSector;
}
/// <summary>
/// Calculates the hash code for this object.
/// </summary>
/// <returns>The hash code.</returns>
public override int GetHashCode()
{
return _cylinders.GetHashCode() ^ _headsPerCylinder.GetHashCode()
^ _sectorsPerTrack.GetHashCode() ^ _bytesPerSector.GetHashCode();
}
/// <summary>
/// Gets a string representation of this object, in the form (C/H/S).
/// </summary>
/// <returns>The string representation.</returns>
public override string ToString()
{
if (_bytesPerSector == 512)
{
return "(" + _cylinders + "/" + _headsPerCylinder + "/" + _sectorsPerTrack + ")";
}
else
{
return "(" + _cylinders + "/" + _headsPerCylinder + "/" + _sectorsPerTrack + ":" + _bytesPerSector + ")";
}
}
}
}
-50
View File
@@ -1,50 +0,0 @@
//
// Copyright (c) 2008-2011, Kenneth Bell
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
namespace DiscUtils
{
/// <summary>
/// Enumeration of standard BIOS disk geometry translation methods.
/// </summary>
public enum GeometryTranslation
{
/// <summary>
/// Apply no translation.
/// </summary>
None = 0,
/// <summary>
/// Automatic, based on the physical geometry select the most appropriate translation.
/// </summary>
Auto = 1,
/// <summary>
/// LBA assisted translation, based on just the disk capacity.
/// </summary>
Lba = 2,
/// <summary>
/// Bit-shifting translation, based on the physical geometry of the disk.
/// </summary>
Large = 3,
}
}

Some files were not shown because too many files have changed in this diff Show More