param(
  [string]$PrinterName = "Xprinter XP-420B",
  [string]$InputFile = ""
)

if (-not (Test-Path $InputFile)) {
  Write-Host "ERR_INPUT_NOT_FOUND"
  exit 1
}

Add-Type -TypeDefinition @"
using System;
using System.Runtime.InteropServices;

public class RawPrinter {
  [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)]
  public class DOCINFOA {
    [MarshalAs(UnmanagedType.LPWStr)] public string pDocName;
    [MarshalAs(UnmanagedType.LPWStr)] public string pOutputFile;
    [MarshalAs(UnmanagedType.LPWStr)] public string pDataType;
  }

  [DllImport("winspool.Drv", EntryPoint="OpenPrinterW", SetLastError=true, CharSet=CharSet.Unicode)]
  public static extern bool OpenPrinter(string pPrinterName, out IntPtr phPrinter, IntPtr pDefault);

  [DllImport("winspool.Drv", SetLastError=true)]
  public static extern bool ClosePrinter(IntPtr hPrinter);

  [DllImport("winspool.Drv", EntryPoint="StartDocPrinterW", SetLastError=true, CharSet=CharSet.Unicode)]
  public static extern int StartDocPrinter(IntPtr hPrinter, int level, [In] DOCINFOA di);

  [DllImport("winspool.Drv", SetLastError=true)]
  public static extern bool EndDocPrinter(IntPtr hPrinter);

  [DllImport("winspool.Drv", SetLastError=true)]
  public static extern bool StartPagePrinter(IntPtr hPrinter);

  [DllImport("winspool.Drv", SetLastError=true)]
  public static extern bool EndPagePrinter(IntPtr hPrinter);

  [DllImport("winspool.Drv", SetLastError=true)]
  public static extern bool WritePrinter(IntPtr hPrinter, byte[] pBytes, int dwCount, out int dwWritten);
}
"@ -ErrorAction Stop

$bytes = [System.IO.File]::ReadAllBytes($InputFile)
$h = [IntPtr]::Zero

if (-not [RawPrinter]::OpenPrinter($PrinterName, [ref]$h, [IntPtr]::Zero)) {
  Write-Host ("ERR_OPEN_PRINTER " + [Runtime.InteropServices.Marshal]::GetLastWin32Error())
  exit 1
}

try {
  $doc = New-Object RawPrinter+DOCINFOA
  $doc.pDocName = "V2_Bridge_Raw"
  $doc.pDataType = "RAW"

  $job = [RawPrinter]::StartDocPrinter($h, 1, $doc)
  if ($job -eq 0) {
    Write-Host ("ERR_START_DOC " + [Runtime.InteropServices.Marshal]::GetLastWin32Error())
    exit 1
  }

  if (-not [RawPrinter]::StartPagePrinter($h)) {
    Write-Host ("ERR_START_PAGE " + [Runtime.InteropServices.Marshal]::GetLastWin32Error())
    [RawPrinter]::EndDocPrinter($h) | Out-Null
    exit 1
  }

  $written = 0
  if (-not [RawPrinter]::WritePrinter($h, $bytes, $bytes.Length, [ref]$written)) {
    Write-Host ("ERR_WRITE " + [Runtime.InteropServices.Marshal]::GetLastWin32Error())
    [RawPrinter]::EndPagePrinter($h) | Out-Null
    [RawPrinter]::EndDocPrinter($h) | Out-Null
    exit 1
  }

  [RawPrinter]::EndPagePrinter($h) | Out-Null
  [RawPrinter]::EndDocPrinter($h) | Out-Null

  if ($written -ne $bytes.Length) {
    Write-Host "ERR_PARTIAL_WRITE"
    exit 1
  }

  Write-Host "OK"
  exit 0
}
finally {
  [RawPrinter]::ClosePrinter($h) | Out-Null
}
