regis3

package module
v0.0.0-...-9cc701f Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 4, 2026 License: MIT Imports: 16 Imported by: 0

README

go-regis3

A Go library for parsing, manipulating, and exporting Windows Registry (.REG) files.

Why Does This Exist?

Most "registry libraries" wrap RegOpenKeyEx so you don't forget RegCloseKey. That's not what this is.

go-regis3 is a complete toolkit for .REG file parsing, in-memory representation, and diff/merge operations:

  • State machine parser that handles both REGEDIT4 (ANSI) and Windows Registry Editor 5.00 (UTF-16LE) formats
  • In-memory tree representation (KeyEntry) with full navigation and manipulation
  • Diff/merge API: AskToAddValue(), AskToRemoveValue() - designed for comparing registry snapshots
  • Round-trip fidelity: parse → modify → export preserves structure
  • WiX XML generation for MSI installer authoring
  • Handles all the quirks - line continuation, hex encoding, escaped strings, variable substitution

Sister Implementations

All three implementations share the same design philosophy and API structure.

Installation

go get github.com/gersonkurz/go-regis3

Quick Start

package main

import (
    "fmt"
    "strings"
    "github.com/gersonkurz/go-regis3"
)

func main() {
    // Parse a .REG file (pass nil for default options)
    root, err := regis3.ParseFile("settings.reg", nil)
    if err != nil {
        panic(err)
    }

    // Navigate the tree
    key := root.FindKey("Software\\MyApp")
    if key != nil {
        val := key.Values()["setting"]
        fmt.Println(val.GetString("default"))
    }

    // Export back to .REG format (UTF-16LE for Windows 5.00 format)
    writer := regis3.NewRegWriter(regis3.HeaderWindows5, regis3.ExportOptions{}, true)
    var sb strings.Builder
    writer.Write(&sb, root)
    fmt.Println(sb.String())
}

API Overview

Getting Registry Data Into Memory

Your first decision is where the .REG content comes from. You have two options:

From a file on disk - the common case when you're working with exported registry snapshots:

root, err := regis3.ParseFile("settings.reg", nil)

ParseFile handles encoding detection automatically. Windows .REG files come in two flavors: ANSI (older REGEDIT4 format) and UTF-16LE with BOM (modern Windows Registry Editor Version 5.00 format). You don't need to care which one you have.

From a string - useful when the content doesn't live on disk. Maybe you extracted it from a ZIP archive, received it over a network, or generated it programmatically:

content := `Windows Registry Editor Version 5.00

[HKEY_CURRENT_USER\Software\MyApp]
"Setting"="Value"
`
root, err := regis3.Parse(content, nil)

Both functions return a *KeyEntry - the root of a tree representing the registry structure.

Understanding the Tree Structure

A parsed .REG file becomes a tree of KeyEntry nodes. Each key can have:

  • Subkeys - child KeyEntry nodes (like folders)
  • Values - ValueEntry nodes containing actual data (like files)
  • A default value - the unnamed @ value that every key can have

Think of it like a filesystem: keys are directories, values are files, and the default value is like a directory's own metadata.

The root you get back typically represents a registry hive like HKEY_CURRENT_USER or HKEY_LOCAL_MACHINE. If your .REG file contains multiple hives, the root will be an unnamed container with each hive as a child.

Navigating to a Specific Key

If you know the path you're looking for, use FindKey:

key := root.FindKey("Software\\MyApp\\Settings")
if key == nil {
    // Key doesn't exist in this .REG file
}

The path is relative to whatever root represents. If root is HKEY_CURRENT_USER, then FindKey("Software\\MyApp") looks for HKEY_CURRENT_USER\Software\MyApp.

FindKey is read-only - it returns nil if the path doesn't exist rather than creating it. This is what you want when exploring an existing file.

Enumerating Keys and Values

Often you don't know exactly what's in a .REG file and need to explore it. The tree exposes its contents through accessor methods:

// Iterate over all subkeys
for name, subkey := range key.SubKeys() {
    fmt.Printf("Subkey: %s (full path: %s)\n", name, subkey.GetPath())
}

// Iterate over all named values
for name, value := range key.Values() {
    fmt.Printf("Value: %s = %v\n", name, value.GetString(""))
}

// Check for the default value (the @ value in .REG syntax)
if def := key.DefaultValue(); def != nil {
    fmt.Printf("Default value: %s\n", def.GetString(""))
}

Note: The map keys are lowercase for case-insensitive lookup, but each entry preserves its original name via Name(). The Windows Registry is case-insensitive but case-preserving, and go-regis3 mirrors this behavior.

Reading Value Data

Values have different types (string, DWORD, binary, etc.), and you access them through type-specific getters. Each getter takes a default value to return if the type doesn't match:

// String values (REG_SZ, REG_EXPAND_SZ)
str := value.GetString("fallback")

// Integer values
dword := value.GetDword(0)    // REG_DWORD (32-bit)
qword := value.GetQword(0)    // REG_QWORD (64-bit)

// Multi-string (REG_MULTI_SZ) - returns nil if wrong type
strings := value.GetMultiString()

// Raw bytes for anything else
raw := value.Data()

If you need to check the type explicitly:

switch value.Kind() {
case regis3.RegSz:
    // It's a string
case regis3.RegDword:
    // It's a 32-bit integer
case regis3.RegBinary:
    // It's raw binary data
// ... etc
}
Creating and Modifying Data

When you want to build or modify a registry tree, use FindOrCreateKey and FindOrCreateValue. Unlike the read-only FindKey, these create missing nodes:

// This creates the entire path if it doesn't exist
key := root.FindOrCreateKey("Software\\MyApp\\Settings")

// Create or update a value
val := key.FindOrCreateValue("InstallPath")
val.SetString("C:\\Program Files\\MyApp")

// Other value types
key.FindOrCreateValue("LaunchCount").SetDword(42)
key.FindOrCreateValue("SearchPaths").SetMultiString([]string{"C:\\bin", "D:\\tools"})
key.FindOrCreateValue("License").SetBinaryType(regis3.RegBinary, licenseBytes)

To mark something for deletion (which exports as [-KEY] or "value"=-):

key.SetRemoveFlag(true)    // Marks the entire key for deletion
value.SetRemoveFlag(true)  // Marks just this value for deletion
Variable Substitution ($$VAR$$ Syntax)

Sometimes you need registry values that aren't fully known until install time. Consider an installer that writes mostly fixed settings, but some values - like a license key, installation path, or machine-specific ID - come from an INI file or are generated during setup.

go-regis3 supports a $$VARIABLE$$ syntax for this. Instead of a literal value, you write a placeholder that your installer resolves later:

[HKEY_LOCAL_MACHINE\SOFTWARE\MyApp]
"InstallPath"="C:\\Program Files\\MyApp"
"LicenseKey"=dword:$$LICENSE_DWORD$$
"MachineId"=hex(b):$$MACHINE_QWORD$$

To parse files containing this syntax, enable the option:

root, err := regis3.ParseFile("template.reg", &regis3.ParseOptions{
    AllowVariableSubstitution: true,
})

The parser stores these as special types (RegEscapedDword, RegEscapedQword) with the variable name as the payload. When you export, the $$VAR$$ syntax is preserved:

val := key.FindOrCreateValue("LicenseKey")
val.SetEscapedDwordValue("$$LICENSE_DWORD$$")  // Stored as variable reference, not a number

Your installer then:

  1. Parses the template .REG file
  2. Walks the tree looking for escaped values (val.Kind() == regis3.RegEscapedDword)
  3. Replaces them with actual values from your INI file or generator
  4. Exports the final .REG or applies it to the registry

This keeps your .REG templates readable and version-controllable while deferring machine-specific values to install time.

Building Diff Trees

The AskTo* methods are designed for comparing two registry snapshots and building a diff. They copy nodes from a source tree into a result tree:

diff := regis3.NewKeyEntry(nil, "")  // Empty result tree

// When comparing old vs new, for each difference:
diff.AskToAddKey(newKey)           // Key was added
diff.AskToRemoveKey(oldKey)        // Key was removed
diff.AskToAddValue(parentKey, newValue)     // Value was added/changed
diff.AskToRemoveValue(parentKey, oldValue)  // Value was removed

The result is a tree containing only the changes, which you can export to create a .REG file that transforms "old" into "new".

Exporting Back to .REG Format

Once you have a tree (parsed, modified, or built from scratch), export it. The header and encoding must match:

// Modern format: UTF-16LE with BOM (recommended)
writer := regis3.NewRegWriter(regis3.HeaderWindows5, regis3.ExportOptions{}, true)

// Legacy format: ANSI encoding
writer := regis3.NewRegWriter(regis3.HeaderRegedit4, regis3.ExportOptions{}, false)

// Skip keys that have no values
writer := regis3.NewRegWriter(regis3.HeaderWindows5, regis3.ExportOptions{NoEmptyKeys: true}, true)

file, _ := os.Create("output.reg")
defer file.Close()
writer.Write(file, root)
Exporting to WiX XML for MSI Installers

If you're building Windows installers with WiX (Windows Installer XML), you often need to include registry operations. Instead of hand-writing XML fragments, you can author your registry settings as a .REG file - which is easier to read, test, and diff - then convert it to WiX format:

wixWriter := regis3.NewWixWriter()
wixWriter.Write(file, root)

Given this .REG content:

[HKEY_LOCAL_MACHINE\SOFTWARE\MyApp]
"InstallPath"="C:\Program Files\MyApp"
"Version"=dword:00000001

[-HKEY_LOCAL_MACHINE\SOFTWARE\MyApp\OldFeature]

The WiX writer produces:

<RemoveRegistryKey Action="removeOnInstall" Root="HKLM" Key="SOFTWARE\MyApp\OldFeature"/>
<RegistryKey Root="HKLM" Key="SOFTWARE\MyApp">
  <RegistryValue Name="InstallPath" Value="C:\Program Files\MyApp" Type="string"/>
  <RegistryValue Name="Version" Value="1" Type="integer"/>
</RegistryKey>

The output uses WiX 4.x syntax and handles:

  • Key hierarchy - nested <RegistryKey> elements
  • All value types - strings, integers, binary, multi-string, expandable strings
  • Deletions - <RemoveRegistryKey> and <RemoveRegistryValue> elements
  • Root mapping - HKEY_LOCAL_MACHINEHKLM, HKEY_CURRENT_USERHKCU, etc.

The writer does two passes: first emitting all removal operations (so they execute before additions), then the key/value additions as a nested hierarchy. This matches how you'd typically structure WiX components.

Parse Options

Pass nil for default parsing behavior, or provide a *ParseOptions struct:

type ParseOptions struct {
    AllowHashtagComments      bool  // Allow # line comments
    AllowSemicolonComments    bool  // Allow ; line comments
    IgnoreWhitespaces         bool  // Relaxed whitespace handling
    AllowVariableSubstitution bool  // Enable dword:$$VAR$$ syntax
    AnsiCodePage              string // Optional ANSI code page (e.g., "windows-1252") for REGEDIT4 files
}

Example with multiple options:

root, err := regis3.Parse(content, &regis3.ParseOptions{
    AllowHashtagComments: true,
    IgnoreWhitespaces:    true,
})

Export Options

Pass ExportOptions{} for default export behavior:

type ExportOptions struct {
    NoEmptyKeys bool  // Skip keys that have no values
}

Registry Value Types

Standard Windows types (matching winnt.h):

Constant Value Description
RegNone 0 No type
RegSz 1 String
RegExpandSz 2 Expandable string (%VAR%)
RegBinary 3 Binary data
RegDword 4 32-bit integer
RegMultiSz 7 Multi-string
RegQword 11 64-bit integer

Extended types for variable substitution:

Constant Description
RegEscapedDword DWORD with variable (e.g., $$VAR$$)
RegEscapedQword QWORD with variable

Testing

# Run unit tests
go test

# Run with production test files
go test -testdata=/path/to/reg/files

# Or via environment variable
REGIS3_TESTDATA=/path/to/reg/files go test

API Reference

Package Functions
  • Parse(content string, options *ParseOptions) (*KeyEntry, error) - Parse .REG content
  • ParseFile(filename string, options *ParseOptions) (*KeyEntry, error) - Parse .REG file
  • NewRegWriter(header string, options ExportOptions, useUtf16 bool) *RegWriter - Create .REG exporter
  • NewWixWriter() *WixWriter - Create WiX XML exporter
  • EscapeString(input string) string - Escape string for .REG format
  • IsStringType(kind uint32) bool - Check if type is REG_SZ or REG_EXPAND_SZ
  • IsParseError(err error) *ParseError - Check if error is a ParseError
KeyEntry Methods
Method Description
Name() string Key name (not full path)
Parent() *KeyEntry Parent key
SetParent(*KeyEntry) Set parent (for tree grafting)
GetPath() string Full registry path
SubKeys() map[string]*KeyEntry Child keys
Values() map[string]*ValueEntry Named values
DefaultValue() *ValueEntry Default (unnamed) value
FindKey(path string) *KeyEntry Find existing key (read-only)
FindOrCreateKey(path string) *KeyEntry Find or create key path
FindOrCreateValue(name string) *ValueEntry Find or create value
Clone(newParent *KeyEntry) *KeyEntry Deep copy
RemoveFlag() bool Check if marked for deletion
SetRemoveFlag(bool) Mark for deletion
AskToAddKey(*KeyEntry) *KeyEntry Add key for diff/merge
AskToRemoveKey(*KeyEntry) *KeyEntry Remove key for diff/merge
AskToAddValue(*KeyEntry, *ValueEntry) Add value for diff/merge
AskToRemoveValue(*KeyEntry, *ValueEntry) Remove value for diff/merge
ValueEntry Methods
Method Description
Name() string Value name
IsDefaultValue() bool True if unnamed (default) value
Kind() uint32 Registry type constant
Data() []byte Raw data bytes
RemoveFlag() bool Check if marked for deletion
SetRemoveFlag(bool) Mark for deletion
GetString(default string) string Get as string
GetDword(default uint32) uint32 Get as DWORD
GetQword(default uint64) uint64 Get as QWORD
GetMultiString() []string Get as string list
SetNone() Set as REG_NONE
SetString(string) Set as REG_SZ
SetExpandString(string) Set as REG_EXPAND_SZ
SetDword(uint32) Set as REG_DWORD
SetQword(uint64) Set as REG_QWORD
SetMultiString([]string) Set as REG_MULTI_SZ
SetBinaryType(kind uint32, data []byte) Set raw binary with type
SetEscapedDwordValue(string) Set DWORD variable reference
SetEscapedQwordValue(string) Set QWORD variable reference
RegWriter
type RegWriter struct {
    Header   string        // HeaderRegedit4 or HeaderWindows5
    Options  ExportOptions
}

func NewRegWriter(header string, options ExportOptions, useUtf16 bool) *RegWriter
func (w *RegWriter) Write(out io.Writer, root *KeyEntry) error
WixWriter
type WixWriter struct{}

func NewWixWriter() *WixWriter
func (w *WixWriter) Write(out io.Writer, root *KeyEntry) error

Generates WiX 4.x compatible XML fragments with:

  • <RegistryKey> elements for key hierarchy
  • <RegistryValue> elements for values
  • <RemoveRegistryKey> for key deletions
  • <RemoveRegistryValue> for value deletions

License

MIT License - see LICENSE file for details.

Documentation

Overview

Package regis3 provides a high-fidelity toolkit for parsing, manipulating, and exporting Windows Registry (.REG) files.

Unlike standard registry libraries that wrap the Windows Registry API (RegOpenKeyEx, etc.), go-regis3 treats .REG files as structured text documents. It uses a character-at-a-time state machine parser to build an in-memory tree representation (KeyEntry) that can be manipulated, compared (diff/merge), and exported back to .REG or WiX XML formats.

Core Features:

  • Supports both REGEDIT4 (ANSI) and Windows Registry Editor 5.00 (UTF-16LE) formats.
  • High-fidelity internal storage using UTF-16LE to preserve exact byte sequences.
  • Case-insensitive but case-preserving key and value handling.
  • Advanced features like variable substitution ($$VAR$$ syntax) and WiX XML generation.
  • Robust error reporting with line/column numbers and context snippets.

The library is designed for cross-platform use, allowing registry files to be processed on non-Windows systems (e.g., for installer generation or snapshot analysis).

Index

Constants

View Source
const (
	HeaderRegedit4 = "REGEDIT4"
	HeaderWindows5 = "Windows Registry Editor Version 5.00"
)
View Source
const (
	RegNone                     = 0
	RegSz                       = 1
	RegExpandSz                 = 2
	RegBinary                   = 3
	RegDword                    = 4
	RegDwordLittleEndian        = 4
	RegDwordBigEndian           = 5
	RegLink                     = 6
	RegMultiSz                  = 7
	RegResourceList             = 8
	RegFullResourceDescriptor   = 9
	RegResourceRequirementsList = 10
	RegQword                    = 11
	RegQwordLittleEndian        = 11
)

Registry Value Types These constants match the standard Windows API values found in winnt.h

View Source
const (
	// RegTypeUnknown is a sentinel value indicating unknown/uninitialized registry value type.
	RegTypeUnknown = 0xFFFFFFFF // -1

	// RegEscapedDword is a marker for escaped DWORD variables ($$VAR$$ syntax in .REG files).
	// The actual value is stored as a string to be expanded at write time.
	RegEscapedDword = 0xFFFFFFFE // -2

	// RegEscapedQword is a marker for escaped QWORD variables ($$VAR$$ syntax in .REG files).
	RegEscapedQword = 0xFFFFFFFD // -3
)

pnq-specific Constants

Variables

This section is empty.

Functions

func EscapeString

func EscapeString(input string) string

EscapeString escapes backslashes and double quotes for .REG files.

func Is64BitOperatingSystem

func Is64BitOperatingSystem() bool

Is64BitOperatingSystem checks if the OS is 64-bit. On non-Windows platforms, we determine this based on the architecture.

func Is64BitProcess

func Is64BitProcess() bool

Is64BitProcess checks if the current process is 64-bit.

func IsStringType

func IsStringType(kind uint32) bool

IsStringType checks if a registry value type is a string type (REG_SZ or REG_EXPAND_SZ).

Types

type ExportOptions

type ExportOptions struct {
	// NoEmptyKeys skips keys that have no values when exporting.
	NoEmptyKeys bool
}

ExportOptions configures the behavior of the .REG file exporter.

type KeyEntry

type KeyEntry struct {
	// contains filtered or unexported fields
}

KeyEntry represents a registry key tree node. Keys and values are stored case-insensitively (lowercase keys).

func NewKeyEntry

func NewKeyEntry(parent *KeyEntry, name string) *KeyEntry

NewKeyEntry creates a new named key with a parent. Pass nil for parent to create a root key.

func Parse

func Parse(content string, options *ParseOptions) (*KeyEntry, error)

Parse parses a .REG file content string. It automatically detects the header (REGEDIT4 or Windows Registry Editor Version 5.00). Pass nil for options to use defaults, or provide a ParseOptions struct.

func ParseFile

func ParseFile(filename string, options *ParseOptions) (*KeyEntry, error)

ParseFile reads and parses a .REG file. It handles UTF-16LE to UTF-8 conversion if necessary. Pass nil for options to use defaults, or provide a ParseOptions struct.

func (*KeyEntry) AskToAddKey

func (k *KeyEntry) AskToAddKey(addThis *KeyEntry) *KeyEntry

AskToAddKey creates or finds a key for adding content (for diff/merge operations).

The "Ask" naming reflects that you're not modifying the source key - you're "asking" this tree (typically a diff/merge result) to record that the given key should be added. The method copies the source key's structure into this tree.

This naming convention originates from the C# implementation and is preserved for API compatibility across the C#/C++/Go implementations.

func (*KeyEntry) AskToAddValue

func (k *KeyEntry) AskToAddValue(key *KeyEntry, val *ValueEntry)

AskToAddValue adds a value to the key (for diff/merge operations).

The "Ask" naming reflects that you're not modifying the source - you're "asking" this tree to record that the given value should be added. See AskToAddKey for more details on the naming convention.

func (*KeyEntry) AskToRemoveKey

func (k *KeyEntry) AskToRemoveKey(removeThis *KeyEntry) *KeyEntry

AskToRemoveKey creates a key entry marked for removal (for diff/merge operations).

The "Ask" naming reflects that you're not modifying the source key - you're "asking" this tree (typically a diff/merge result) to record that the given key should be removed. See AskToAddKey for more details on the naming convention.

func (*KeyEntry) AskToRemoveValue

func (k *KeyEntry) AskToRemoveValue(key *KeyEntry, val *ValueEntry)

AskToRemoveValue adds a value marked for removal (for diff/merge operations).

The "Ask" naming reflects that you're not modifying the source - you're "asking" this tree to record that the given value should be removed. See AskToAddKey for more details on the naming convention.

func (*KeyEntry) Clone

func (k *KeyEntry) Clone(newParent *KeyEntry) *KeyEntry

Clone creates a deep copy of this key entry.

func (*KeyEntry) DefaultValue

func (k *KeyEntry) DefaultValue() *ValueEntry

DefaultValue returns the default value (if any).

func (*KeyEntry) FindKey

func (k *KeyEntry) FindKey(path string) *KeyEntry

FindKey finds a subkey by path (read-only). Returns nil if not found.

func (*KeyEntry) FindOrCreateKey

func (k *KeyEntry) FindOrCreateKey(path string) *KeyEntry

FindOrCreateKey finds or creates a subkey by path. Handles "-PATH" syntax for remove flag.

func (*KeyEntry) FindOrCreateValue

func (k *KeyEntry) FindOrCreateValue(name string) *ValueEntry

FindOrCreateValue finds or creates a named value. Empty string name creates/returns the default value.

func (*KeyEntry) GetPath

func (k *KeyEntry) GetPath() string

GetPath returns the full registry path.

func (*KeyEntry) Name

func (k *KeyEntry) Name() string

Name returns the key name (not the full path).

func (*KeyEntry) Parent

func (k *KeyEntry) Parent() *KeyEntry

Parent returns the parent key.

func (*KeyEntry) RemoveFlag

func (k *KeyEntry) RemoveFlag() bool

RemoveFlag checks if this key should be removed.

func (*KeyEntry) SetParent

func (k *KeyEntry) SetParent(parent *KeyEntry)

SetParent sets the parent key. This is useful when grafting a subtree onto another tree.

func (*KeyEntry) SetRemoveFlag

func (k *KeyEntry) SetRemoveFlag(flag bool)

SetRemoveFlag sets the remove flag.

func (*KeyEntry) SubKeys

func (k *KeyEntry) SubKeys() map[string]*KeyEntry

SubKeys returns the map of subkeys.

Note: This returns the actual internal map, not a copy. Callers can modify it directly. This matches the C# implementation (public readonly Dictionary) where the map contents are mutable. The C++ sibling returns const refs instead. This design allows external code (like registry importers) to populate the tree. Map keys are lowercase; use the KeyEntry.Name() method to get the original casing.

func (*KeyEntry) Values

func (k *KeyEntry) Values() map[string]*ValueEntry

Values returns the map of values.

Note: This returns the actual internal map, not a copy. Callers can modify it directly. This matches the C# implementation (public readonly Dictionary) where the map contents are mutable. The C++ sibling returns const refs instead. This design allows external code (like registry importers) to populate the tree. Map keys are lowercase; use the ValueEntry.Name() method to get the original casing.

type ParseError

type ParseError struct {
	// Line number where the error occurred (1-based).
	Line int

	// Column number where the error occurred (1-based).
	Column int

	// Message describing what went wrong.
	Message string

	// Context shows the problematic line from the input.
	Context string

	// ContextPointer is a line with a ^ pointing to the error position.
	ContextPointer string
}

ParseError represents an error that occurred during .REG file parsing. It includes location information (line, column) and context from the input.

func IsParseError

func IsParseError(err error) *ParseError

IsParseError checks if an error is a ParseError and returns it. Returns nil if the error is not a ParseError.

func (*ParseError) Error

func (e *ParseError) Error() string

Error implements the error interface.

func (*ParseError) Unwrap

func (e *ParseError) Unwrap() error

Unwrap returns nil as ParseError doesn't wrap other errors.

type ParseOptions

type ParseOptions struct {
	// AllowHashtagComments allows # style line comments.
	// Standard .REG files don't support comments; enable this for hand-edited files.
	AllowHashtagComments bool

	// AllowSemicolonComments allows ; style line comments.
	// Standard .REG files don't support comments; enable this for hand-edited files.
	AllowSemicolonComments bool

	// IgnoreWhitespaces is more relaxed about whitespace in .REG files.
	// Recommended for manually edited files that may have extra spaces.
	IgnoreWhitespaces bool

	// AllowVariableSubstitution allows variable names for non-string values.
	// Enables syntax like: "value"=dword:$$VARIABLE$$
	// Useful for installer templates where some values are filled in at install time.
	AllowVariableSubstitution bool

	// AnsiCodePage controls decoding for REGEDIT4 (ANSI) files when using ParseFile.
	// If empty, the decoder falls back to raw bytes (best-effort UTF-8/ASCII behavior).
	// Examples: "windows-1252", "windows-1250".
	// This is intentionally lenient and may accept data that regedit itself would.
	AnsiCodePage string
}

ParseOptions configures the behavior of the .REG file parser.

type ParserContext

type ParserContext struct {
	Line   int
	Column int
	Index  int
	Buffer []rune
	// contains filtered or unexported fields
}

ParserContext provides the base functionality for a state-machine parser. It mimics the C++ abstract_parser class.

func NewParserContext

func NewParserContext() *ParserContext

NewParserContext creates a new ParserContext.

func (*ParserContext) BufferAppend

func (p *ParserContext) BufferAppend(r rune)

BufferAppend appends a rune to the buffer.

func (*ParserContext) BufferAsString

func (p *ParserContext) BufferAsString() string

BufferAsString returns the current buffer contents as a string.

func (*ParserContext) BufferClear

func (p *ParserContext) BufferClear()

BufferClear clears the buffer.

func (*ParserContext) FormatError

func (p *ParserContext) FormatError(err error) error

FormatError augments an error with context information (line, column, snippet). Returns a *ParseError with location and context details.

func (*ParserContext) LastState

func (p *ParserContext) LastState() ParserState

LastState returns the parser's last known state function. This is used by concrete parsers to apply lenient EOF finalization.

func (*ParserContext) ParseText

func (p *ParserContext) ParseText(text string, initialState ParserState) error

ParseText processes the input string starting with the given initial state.

type ParserState

type ParserState func(r rune) (ParserState, error)

ParserState is a function representing a state in the state machine. It takes a rune and returns the next state, or an error.

type RegParser

type RegParser struct {
	*ParserContext
	// contains filtered or unexported fields
}

RegParser parses Windows .REG files.

func NewRegParser

func NewRegParser(expectedHeader string, options *ParseOptions) *RegParser

NewRegParser creates a new parser.

func (*RegParser) Parse

func (p *RegParser) Parse(content string) (*KeyEntry, error)

Parse parses the given content.

type RegWriter

type RegWriter struct {
	Header  string
	Options ExportOptions
	// contains filtered or unexported fields
}

RegWriter handles exporting KeyEntry trees to .REG format.

func NewRegWriter

func NewRegWriter(header string, options ExportOptions, useUtf16 bool) *RegWriter

NewRegWriter creates a new RegWriter. For Windows 5.00 format, use HeaderWindows5 and useUtf16=true. For REGEDIT4 format, use HeaderRegedit4 and useUtf16=false.

func (*RegWriter) Write

func (w *RegWriter) Write(out io.Writer, root *KeyEntry) error

Write exports the key entry tree to the provided writer.

type ValueEntry

type ValueEntry struct {
	// contains filtered or unexported fields
}

ValueEntry represents a registry value with name, type, and data. Data is stored internally as UTF-16LE bytes (matching Windows registry format).

func NewValueEntry

func NewValueEntry(name string) *ValueEntry

NewValueEntry creates a new ValueEntry.

func (*ValueEntry) Data

func (v *ValueEntry) Data() []byte

Data returns the raw data bytes.

func (*ValueEntry) GetDword

func (v *ValueEntry) GetDword(defaultValue uint32) uint32

GetDword returns the value as DWORD.

func (*ValueEntry) GetMultiString

func (v *ValueEntry) GetMultiString() []string

GetMultiString returns the value as a list of strings.

func (*ValueEntry) GetQword

func (v *ValueEntry) GetQword(defaultValue uint64) uint64

GetQword returns the value as QWORD.

func (*ValueEntry) GetString

func (v *ValueEntry) GetString(defaultValue string) string

GetString returns the value as string.

func (*ValueEntry) IsDefaultValue

func (v *ValueEntry) IsDefaultValue() bool

IsDefaultValue checks if this is the default (unnamed) value for a key.

func (*ValueEntry) Kind

func (v *ValueEntry) Kind() uint32

Kind returns the registry type.

func (*ValueEntry) Name

func (v *ValueEntry) Name() string

Name returns the value name.

func (*ValueEntry) RemoveFlag

func (v *ValueEntry) RemoveFlag() bool

RemoveFlag checks if this value should be removed.

func (*ValueEntry) SetBinaryType

func (v *ValueEntry) SetBinaryType(kind uint32, data []byte)

SetBinaryType sets raw binary data with specified type.

func (*ValueEntry) SetDword

func (v *ValueEntry) SetDword(val uint32)

SetDword sets the value as REG_DWORD.

func (*ValueEntry) SetEscapedDwordValue

func (v *ValueEntry) SetEscapedDwordValue(variableRef string)

SetEscapedDwordValue sets escaped DWORD value (variable name stored as string).

func (*ValueEntry) SetEscapedQwordValue

func (v *ValueEntry) SetEscapedQwordValue(variableRef string)

SetEscapedQwordValue sets escaped QWORD value (variable name stored as string).

func (*ValueEntry) SetExpandString

func (v *ValueEntry) SetExpandString(val string)

SetExpandString sets the value as REG_EXPAND_SZ.

func (*ValueEntry) SetMultiString

func (v *ValueEntry) SetMultiString(stringsList []string)

SetMultiString sets the value as REG_MULTI_SZ.

func (*ValueEntry) SetNone

func (v *ValueEntry) SetNone()

SetNone sets the value as REG_NONE.

func (*ValueEntry) SetQword

func (v *ValueEntry) SetQword(val uint64)

SetQword sets the value as REG_QWORD.

func (*ValueEntry) SetRemoveFlag

func (v *ValueEntry) SetRemoveFlag(flag bool)

SetRemoveFlag sets the remove flag.

func (*ValueEntry) SetString

func (v *ValueEntry) SetString(val string)

SetString sets the value as REG_SZ.

type WixWriter

type WixWriter struct {
}

WixWriter handles exporting KeyEntry trees to WiX XML format.

func NewWixWriter

func NewWixWriter() *WixWriter

NewWixWriter creates a new WixWriter.

func (*WixWriter) Write

func (w *WixWriter) Write(out io.Writer, root *KeyEntry) error

Write exports the key entry tree to the provided writer as WiX XML fragments. It performs two passes: 1. Writes <RemoveRegistryKey> and <RemoveRegistryValue> elements (flattened). 2. Writes <RegistryKey> hierarchy for additions/modifications.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL