Browse Source
* Mostly complete header coverage, albeit with no real display options. * Does not currently read the publisher data.master
Ian Burgmyer
4 years ago
commit
d02496d44b
11 changed files with 655 additions and 0 deletions
@ -0,0 +1,261 @@
|
||||
## Ignore Visual Studio temporary files, build results, and |
||||
## files generated by popular Visual Studio add-ons. |
||||
|
||||
# User-specific files |
||||
*.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 cache/options directory |
||||
.vs/ |
||||
# Uncomment if you have tasks that create the project's static files in wwwroot |
||||
#wwwroot/ |
||||
|
||||
# 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 |
||||
|
||||
# DNX |
||||
project.lock.json |
||||
project.fragment.lock.json |
||||
artifacts/ |
||||
|
||||
*_i.c |
||||
*_p.c |
||||
*_i.h |
||||
*.ilk |
||||
*.meta |
||||
*.obj |
||||
*.pch |
||||
*.pdb |
||||
*.pgc |
||||
*.pgd |
||||
*.rsp |
||||
*.sbr |
||||
*.tlb |
||||
*.tli |
||||
*.tlh |
||||
*.tmp |
||||
*.tmp_proj |
||||
*.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 |
||||
|
||||
# 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 |
||||
|
||||
# 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 |
||||
# TODO: 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 |
||||
**/packages/* |
||||
# except build/, which is used as an MSBuild target. |
||||
!**/packages/build/ |
||||
# Uncomment if necessary however generally it will be regenerated when needed |
||||
#!**/packages/repositories.config |
||||
# NuGet v3's project.json files produces more ignoreable 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 |
||||
|
||||
# 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 |
||||
node_modules/ |
||||
orleans.codegen.cs |
||||
|
||||
# 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 |
||||
|
||||
# SQL Server files |
||||
*.mdf |
||||
*.ldf |
||||
|
||||
# Business Intelligence projects |
||||
*.rdl.data |
||||
*.bim.layout |
||||
*.bim_*.settings |
||||
|
||||
# Microsoft Fakes |
||||
FakesAssemblies/ |
||||
|
||||
# GhostDoc plugin setting file |
||||
*.GhostDoc.xml |
||||
|
||||
# Node.js Tools for Visual Studio |
||||
.ntvs_analysis.dat |
||||
|
||||
# Visual Studio 6 build log |
||||
*.plg |
||||
|
||||
# Visual Studio 6 workspace options file |
||||
*.opt |
||||
|
||||
# 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 |
||||
.cr/ |
||||
|
||||
# Python Tools for Visual Studio (PTVS) |
||||
__pycache__/ |
||||
*.pyc |
@ -0,0 +1,16 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00 |
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DMGHeader", "DMGHeader\DMGHeader.csproj", "{4FF16F68-6FAD-4924-935B-78322B35BF6C}" |
||||
EndProject |
||||
Global |
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution |
||||
Debug|Any CPU = Debug|Any CPU |
||||
Release|Any CPU = Release|Any CPU |
||||
EndGlobalSection |
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution |
||||
{4FF16F68-6FAD-4924-935B-78322B35BF6C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU |
||||
{4FF16F68-6FAD-4924-935B-78322B35BF6C}.Debug|Any CPU.Build.0 = Debug|Any CPU |
||||
{4FF16F68-6FAD-4924-935B-78322B35BF6C}.Release|Any CPU.ActiveCfg = Release|Any CPU |
||||
{4FF16F68-6FAD-4924-935B-78322B35BF6C}.Release|Any CPU.Build.0 = Release|Any CPU |
||||
EndGlobalSection |
||||
EndGlobal |
@ -0,0 +1,8 @@
|
||||
namespace DMGHeader { |
||||
public enum CgbMode { |
||||
Disabled, |
||||
PaletteOnly, |
||||
Enhanced, |
||||
Required |
||||
} |
||||
} |
@ -0,0 +1,8 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk"> |
||||
|
||||
<PropertyGroup> |
||||
<OutputType>Exe</OutputType> |
||||
<TargetFramework>netcoreapp3.1</TargetFramework> |
||||
</PropertyGroup> |
||||
|
||||
</Project> |
@ -0,0 +1,7 @@
|
||||
namespace DMGHeader { |
||||
public enum DestinationCode { |
||||
Japanese, |
||||
NonJapanese, |
||||
Unknown |
||||
} |
||||
} |
@ -0,0 +1,6 @@
|
||||
namespace DMGHeader { |
||||
public class DmgEntryPoint { |
||||
public JumpType Jump { get; set; } = JumpType.None; |
||||
public int JumpAddress { get; set; } = -1; |
||||
} |
||||
} |
@ -0,0 +1,198 @@
|
||||
using System; |
||||
using System.IO; |
||||
using System.Linq; |
||||
using System.Text; |
||||
|
||||
namespace DMGHeader { |
||||
public class DmgHeader { |
||||
public DmgEntryPoint EntryPoint { get; set; } |
||||
public bool ValidLogo { get; set; } |
||||
public string Title { get; set; } |
||||
public CgbMode CgbMode { get; set; } |
||||
public bool SgbSupport { get; set; } |
||||
public string CartridgeType { get; set; } |
||||
public MemorySize RomSize { get; set; } |
||||
public MemorySize ExternalRamSize { get; set; } |
||||
public DestinationCode DestinationCode { get; set; } |
||||
public byte MaskRomVersion { get; set; } |
||||
public byte HeaderChecksum { get; set; } |
||||
public bool ValidHeaderChecksum { get; set; } |
||||
public UInt16 CartridgeChecksum { get; set; } |
||||
|
||||
private byte[] _validLogo = { |
||||
0xCE, 0xED, 0x66, 0x66, 0xCC, 0x0D, 0x00, 0x0B, 0x03, 0x73, 0x00, 0x83, 0x00, 0x0C, 0x00, 0x0D, |
||||
0x00, 0x08, 0x11, 0x1F, 0x88, 0x89, 0x00, 0x0E, 0xDC, 0xCC, 0x6E, 0xE6, 0xDD, 0xDD, 0xD9, 0x99, |
||||
0xBB, 0xBB, 0x67, 0x63, 0x6E, 0x0E, 0xEC, 0xCC, 0xDD, 0xDC, 0x99, 0x9F, 0xBB, 0xB9, 0x33, 0x3E |
||||
}; |
||||
|
||||
public DmgHeader(string filename) { |
||||
using var fs = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read); |
||||
using var br = new BinaryReader(fs); |
||||
|
||||
fs.Seek(0x100, SeekOrigin.Begin); |
||||
EntryPoint = ReadEntryPoint(br.ReadBytes(4)); |
||||
ValidLogo = ValidateLogo(br.ReadBytes(_validLogo.Length)); |
||||
|
||||
// See if the upper bit of the CGB flag is set to see how much of the title field to read. |
||||
fs.Seek(0x143, SeekOrigin.Begin); |
||||
var cgb = (br.ReadByte() & 0b10000000) != 0; |
||||
fs.Seek(0x134, SeekOrigin.Begin); |
||||
var titleLen = cgb ? 15 : 16; |
||||
|
||||
Title = ReadTitle(br.ReadBytes(titleLen)); |
||||
CgbMode = cgb ? ReadCgbMode(br.ReadByte()) : CgbMode.Disabled; |
||||
|
||||
fs.Seek(0x146, SeekOrigin.Begin); |
||||
SgbSupport = br.ReadByte() == 0x03; |
||||
|
||||
CartridgeType = ReadCartridgeType(br.ReadByte()); |
||||
RomSize = ReadRomSize(br.ReadByte()); |
||||
ExternalRamSize = ReadExternalRamSize(br.ReadByte()); |
||||
DestinationCode = ReadDestinationCode(br.ReadByte()); |
||||
|
||||
fs.Seek(0x14C, SeekOrigin.Begin); |
||||
MaskRomVersion = br.ReadByte(); |
||||
|
||||
HeaderChecksum = br.ReadByte(); |
||||
fs.Seek(0x134, SeekOrigin.Begin); |
||||
ValidHeaderChecksum = HeaderChecksum == CalculateHeaderChecksum(br.ReadBytes(0x19)); |
||||
|
||||
fs.Seek(0x14E, SeekOrigin.Begin); |
||||
CartridgeChecksum = br.ReadUInt16(); |
||||
} |
||||
|
||||
private byte CalculateHeaderChecksum(byte[] data) { |
||||
byte x = 0; |
||||
|
||||
unchecked { |
||||
x = data.Aggregate(x, (current, b) => (byte)(current - b - 1)); |
||||
} |
||||
|
||||
return x; |
||||
} |
||||
|
||||
private string ReadCartridgeType(byte type) { |
||||
switch(type) { |
||||
case 0x00: return "ROM ONLY"; |
||||
case 0x01: return "MBC1"; |
||||
case 0x02: return "MBC1+RAM"; |
||||
case 0x03: return "MBC1+RAM+BATTERY"; |
||||
case 0x05: return "MBC2"; |
||||
case 0x06: return "MBC2+BATTERY"; |
||||
case 0x08: return "ROM+RAM"; |
||||
case 0x09: return "ROM+RAM+BATTERY"; |
||||
case 0x0B: return "MMM01"; |
||||
case 0x0C: return "MMM01+RAM"; |
||||
case 0x0D: return "MMM01+RAM+BATTERY"; |
||||
case 0x0F: return "MBC3+TIMER+BATTERY"; |
||||
case 0x10: return "MBC3+TIMER+RAM+BATTERY"; |
||||
case 0x11: return "MBC3"; |
||||
case 0x12: return "MBC3+RAM"; |
||||
case 0x13: return "MBC3+RAM+BATTERY"; |
||||
case 0x19: return "MBC5"; |
||||
case 0x1A: return "MBC5+RAM"; |
||||
case 0x1B: return "MBC5+RAM+BATTERY"; |
||||
case 0x1C: return "MBC5+RUMBLE"; |
||||
case 0x1D: return "MBC5+RUMBLE+RAM"; |
||||
case 0x1E: return "MBC5+RUMBLE+RAM+BATTERY"; |
||||
case 0x20: return "MBC6"; |
||||
case 0x22: return "MBC7+SENSOR+RUMBLE+RAM+BATTERY"; |
||||
case 0xFC: return "POCKET CAMERA"; |
||||
case 0xFD: return "BANDAI TAMA5"; |
||||
case 0xFE: return "HuC3"; |
||||
case 0xFF: return "HuC1+RAM+BATTERY"; |
||||
default: return "Unknown"; |
||||
} |
||||
} |
||||
|
||||
private CgbMode ReadCgbMode(byte mode) { |
||||
if((mode & 0b10000000) == 0) return CgbMode.Disabled; |
||||
if((mode & 0b01000000) != 0) return CgbMode.Required; |
||||
if((mode & 0b00001100) != 0) return CgbMode.PaletteOnly; |
||||
return CgbMode.Enhanced; |
||||
} |
||||
|
||||
private DestinationCode ReadDestinationCode(byte data) { |
||||
switch(data) { |
||||
case 0x00: return DestinationCode.Japanese; |
||||
case 0x01: return DestinationCode.NonJapanese; |
||||
default: return DestinationCode.Unknown; |
||||
} |
||||
} |
||||
|
||||
private DmgEntryPoint ReadEntryPoint(byte[] data) { |
||||
var entry = new DmgEntryPoint(); |
||||
|
||||
var i = 0; |
||||
|
||||
for(; i < data.Length; i++) { |
||||
if(data[i] != 0xC3 && data[i] != 0x18) continue; |
||||
|
||||
entry.Jump = data[i] == 0xC3 ? JumpType.Absolute : JumpType.Relative; |
||||
break; |
||||
} |
||||
|
||||
if(entry.Jump == JumpType.None) return entry; |
||||
|
||||
var addrLen = entry.Jump == JumpType.Absolute ? 2 : 1; |
||||
var addr = data.Skip(++i).Take(addrLen).ToArray(); |
||||
|
||||
if(addr.Length != addrLen) return entry; |
||||
|
||||
if(entry.Jump == JumpType.Absolute) { |
||||
// Stitch the values into a 16-bit value. |
||||
entry.JumpAddress = addr[1] << 8 | addr[0]; |
||||
} else { |
||||
entry.JumpAddress = addr[0] + 0x100 + i; |
||||
} |
||||
|
||||
return entry; |
||||
} |
||||
|
||||
private MemorySize ReadExternalRamSize(byte data) { |
||||
var size = new MemorySize(8); |
||||
|
||||
switch(data) { |
||||
case 0x00: size.Size = 0; return size; |
||||
case 0x01: size.Size = 2; return size; |
||||
case 0x02: size.Size = 8; return size; |
||||
case 0x03: size.Size = 32; return size; |
||||
case 0x04: size.Size = 128; return size; |
||||
case 0x05: size.Size = 64; return size; |
||||
default: return null; |
||||
} |
||||
} |
||||
|
||||
private MemorySize ReadRomSize(byte data) { |
||||
var size = new MemorySize(16); |
||||
|
||||
switch(data) { |
||||
case 0x00: size.Size = 32; return size; |
||||
case 0x01: size.Size = 64; return size; |
||||
case 0x02: size.Size = 128; return size; |
||||
case 0x03: size.Size = 256; return size; |
||||
case 0x04: size.Size = 512; return size; |
||||
case 0x05: size.Size = 1024; return size; |
||||
case 0x06: size.Size = 2048; return size; |
||||
case 0x07: size.Size = 4096; return size; |
||||
case 0x08: size.Size = 8192; return size; |
||||
case 0x52: size.Size = 1152; return size; |
||||
case 0x53: size.Size = 1280; return size; |
||||
case 0x54: size.Size = 1536; return size; |
||||
default: return null; |
||||
} |
||||
} |
||||
|
||||
private string ReadTitle(byte[] data) { |
||||
// Convert nulls to spaces. |
||||
for(var i = 0; i < data.Length; i++) { |
||||
if(data[i] == 0) data[i] = 32; |
||||
} |
||||
|
||||
return Encoding.ASCII.GetString(data).Trim(); |
||||
} |
||||
|
||||
private bool ValidateLogo(byte[] data) => |
||||
data != null && data.Length == _validLogo.Length && data.SequenceEqual(_validLogo); |
||||
} |
||||
} |
@ -0,0 +1,7 @@
|
||||
namespace DMGHeader { |
||||
public enum JumpType { |
||||
None, |
||||
Absolute, |
||||
Relative |
||||
} |
||||
} |
@ -0,0 +1,34 @@
|
||||
namespace DMGHeader { |
||||
public class MemorySize { |
||||
private int _size; |
||||
|
||||
public int Banks { get; private set; } |
||||
|
||||
public int BankSize { get; } |
||||
|
||||
public int Size { |
||||
get => _size; |
||||
set { |
||||
_size = value; |
||||
if(_size <= BankSize * 2) |
||||
Banks = 0; |
||||
else |
||||
Banks = _size / BankSize; |
||||
} |
||||
} |
||||
|
||||
public MemorySize(int bankSize) { |
||||
BankSize = bankSize; |
||||
} |
||||
|
||||
public override string ToString() { |
||||
var ret = $"{Size} KB "; |
||||
if(Banks == 0) |
||||
ret += "(no bank switching)"; |
||||
else |
||||
ret += $"({Banks} banks of {BankSize} KB each)"; |
||||
|
||||
return ret; |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,85 @@
|
||||
using System; |
||||
using System.IO; |
||||
|
||||
namespace DMGHeader { |
||||
internal static class Program { |
||||
internal static void DumpHeader(DmgHeader header) { |
||||
Console.Write("Entry Point: "); |
||||
if(header.EntryPoint.Jump == JumpType.None) { |
||||
Console.WriteLine("No jump found."); |
||||
} else { |
||||
var jumpType = header.EntryPoint.Jump == JumpType.Absolute ? "Absolute" : "Relative"; |
||||
Console.WriteLine($"{jumpType} jump to ROM position 0x{header.EntryPoint.JumpAddress:X4}"); |
||||
} |
||||
|
||||
Console.WriteLine($"Logo Check: {(header.ValidLogo ? "PASSED" : "FAILED")}"); |
||||
Console.WriteLine($"Title/Manufacturer Code: {header.Title}"); |
||||
|
||||
Console.Write("CGB Mode: "); |
||||
switch(header.CgbMode) { |
||||
case CgbMode.Disabled: |
||||
Console.WriteLine("Disabled"); |
||||
break; |
||||
case CgbMode.PaletteOnly: |
||||
Console.WriteLine("Palette Only"); |
||||
break; |
||||
case CgbMode.Enhanced: |
||||
Console.WriteLine("Enhanced"); |
||||
break; |
||||
case CgbMode.Required: |
||||
Console.WriteLine("Required"); |
||||
break; |
||||
default: |
||||
Console.WriteLine("Unknown"); |
||||
break; |
||||
} |
||||
|
||||
Console.WriteLine($"SGB: {(header.SgbSupport ? "Supported" : "Not Supported")}"); |
||||
Console.WriteLine($"Cartridge Type: {header.CartridgeType}"); |
||||
Console.WriteLine($"ROM Size: {header.RomSize}"); |
||||
Console.WriteLine($"Cartridge RAM Size: {header.ExternalRamSize}"); |
||||
|
||||
Console.Write("Destination Code: "); |
||||
switch(header.DestinationCode) { |
||||
case DestinationCode.Japanese: |
||||
Console.WriteLine("Japanese"); |
||||
break; |
||||
case DestinationCode.NonJapanese: |
||||
Console.WriteLine("Non-Japanese"); |
||||
break; |
||||
case DestinationCode.Unknown: |
||||
Console.WriteLine("Unknown/Invalid Code"); |
||||
break; |
||||
default: |
||||
Console.WriteLine("-- INVALID ENUM VALUE -- "); |
||||
break; |
||||
} |
||||
|
||||
Console.WriteLine($"Mask ROM Version: 0x{header.MaskRomVersion:X2}"); |
||||
Console.WriteLine($"Header Checksum: 0x{header.HeaderChecksum:X2}"); |
||||
Console.WriteLine($"Header Checksum Status: {(header.ValidHeaderChecksum ? "VALID" : "NOT VALID")}"); |
||||
Console.WriteLine($"Cartridge Checksum: 0x{header.CartridgeChecksum:X4}"); |
||||
Console.WriteLine(); |
||||
|
||||
} |
||||
|
||||
private static int Main(string[] args) { |
||||
if(args.Length == 0) { |
||||
Console.WriteLine("usage: DMGHeader [filename]"); |
||||
return 0; |
||||
} |
||||
|
||||
var filename = args[0]; |
||||
|
||||
if(!File.Exists(filename)) { |
||||
Console.WriteLine("File not found!"); |
||||
return 1; |
||||
} |
||||
|
||||
var header = new DmgHeader(filename); |
||||
DumpHeader(header); |
||||
|
||||
return 0; |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,25 @@
|
||||
This is free and unencumbered software released into the public domain. |
||||
|
||||
Anyone is free to copy, modify, publish, use, compile, sell, or |
||||
distribute this software, either in source code form or as a compiled |
||||
binary, for any purpose, commercial or non-commercial, and by any |
||||
means. |
||||
|
||||
In jurisdictions that recognize copyright laws, the author or authors |
||||
of this software dedicate any and all copyright interest in the |
||||
software to the public domain. We make this dedication for the benefit |
||||
of the public at large and to the detriment of our heirs and |
||||
successors. We intend this dedication to be an overt act of |
||||
relinquishment in perpetuity of all present and future rights to this |
||||
software under copyright law. |
||||
|
||||
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 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. |
||||
|
||||
For more information, please refer to <http://unlicense.org/> |
||||
|
Loading…
Reference in new issue