b75439c以"命令行是多余的"为由把读取改成 FileStream+StreamReader,是错误前提: 项目存在无法用标准文件 I/O 读取的加密 txt/钻带文件(CLAUDE.md "Encrypted file reading"、 Docs/readme.md "读取加密钻带(使用cmd命令type读取)"、 Docs/刀具列表拖动排序功能说明.md "加密文件:使用 cmd 命令读取"均有记录), 该改动会导致这些文件读取失败。本次回退。 改动: - 还原 CommandTypeFileReader.cs:cmd.exe /d /c type(ANSI/936 解码), 失败时退出码与 stderr 保留在异常消息里 - 删除 ForbiddenPathChars 与两处字符校验(本次报错根因): ( ) & ^ @ 空格在双引号内对 type 安全,黑名单只会误伤 (D2-f)、(1) 等正常文件名 - 保留"非空路径""文件存在"校验与 ReadAllText(path, encoding) 重载 - 删除 AnsiFileReader.cs,15 处调用点改回 - CLAUDE.md / .trellis/spec/:恢复"加密文件必须用 cmd type"的说明, 并标注为不可优化掉的硬约束(含b75439c反例) 验证:demo_drl 全部 36 个文件与2335894实现逐字符一致、行数一致; 含 ( ) & 空格路径实测可读(旧黑名单实现抛"文件路径包含不允许的命令行特殊字符"); cmd 失败消息含退出码与 stderr;dotnet build -p:Platform=x86 0 错误, 警告集与 HEAD 基线完全一致。
118 lines
3.9 KiB
C#
118 lines
3.9 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Text;
|
|
using System.Text.RegularExpressions;
|
|
|
|
namespace DrillTools
|
|
{
|
|
internal static class DrillTapeParameterCleaner
|
|
{
|
|
private const int Gb2312CodePage = 936;
|
|
private static readonly Regex HeaderToolDefinitionStartPattern = new(
|
|
@"^T\d+C",
|
|
RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
|
private static readonly Regex ToolDefinitionPattern = new(
|
|
@"^(?<prefix>\s*T\d+C\d+(?:\.\d+)?)(?<parameters>H.+)$",
|
|
RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
|
|
|
public static bool CanClearParameters(string drillTapeContent)
|
|
{
|
|
var lines = DrillTapeLineParser.SplitLines(drillTapeContent);
|
|
if (lines.Count < 2)
|
|
return false;
|
|
|
|
string secondLine = lines[1].Text.Trim();
|
|
if (!secondLine.StartsWith(";") || secondLine.Length == 1)
|
|
return false;
|
|
|
|
var toolDefinitionLines = GetHeaderToolDefinitionLines(lines);
|
|
if (toolDefinitionLines.Count == 0)
|
|
return false;
|
|
|
|
foreach (var line in toolDefinitionLines)
|
|
{
|
|
if (!ToolDefinitionPattern.IsMatch(line.Text.TrimEnd()))
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
public static string ClearParameters(string drillTapeContent)
|
|
{
|
|
if (!CanClearParameters(drillTapeContent))
|
|
throw new InvalidOperationException("钻带文件不符合清空参数条件");
|
|
|
|
var lines = DrillTapeLineParser.SplitLines(drillTapeContent);
|
|
var builder = new StringBuilder(drillTapeContent.Length);
|
|
|
|
for (int i = 0; i < lines.Count; i++)
|
|
{
|
|
if (i == 1)
|
|
continue;
|
|
|
|
string text = lines[i].Text;
|
|
var match = ToolDefinitionPattern.Match(text.TrimEnd());
|
|
if (match.Success && IsBeforeHeaderEnd(lines, i))
|
|
{
|
|
int trailingWhitespaceLength = text.Length - text.TrimEnd().Length;
|
|
string trailingWhitespace = trailingWhitespaceLength > 0 ? text[^trailingWhitespaceLength..] : string.Empty;
|
|
text = match.Groups["prefix"].Value + trailingWhitespace;
|
|
}
|
|
|
|
builder.Append(text);
|
|
builder.Append(lines[i].LineEnding);
|
|
}
|
|
|
|
return builder.ToString();
|
|
}
|
|
|
|
public static void ClearParametersAndSave(string filePath)
|
|
{
|
|
string content = CommandTypeFileReader.ReadAllText(filePath);
|
|
string cleanedContent = ClearParameters(content);
|
|
|
|
string backupFilePath = filePath + ".bak";
|
|
File.Copy(filePath, backupFilePath, true);
|
|
|
|
using var writer = new StreamWriter(filePath, false, CreateAnsiEncoding());
|
|
writer.Write(cleanedContent);
|
|
}
|
|
|
|
private static List<DrillTapeLine> GetHeaderToolDefinitionLines(IReadOnlyList<DrillTapeLine> lines)
|
|
{
|
|
var toolDefinitionLines = new List<DrillTapeLine>();
|
|
|
|
foreach (var line in lines)
|
|
{
|
|
string trimmedLine = line.Text.Trim();
|
|
if (trimmedLine == "%")
|
|
break;
|
|
|
|
if (HeaderToolDefinitionStartPattern.IsMatch(trimmedLine))
|
|
toolDefinitionLines.Add(line);
|
|
}
|
|
|
|
return toolDefinitionLines;
|
|
}
|
|
|
|
private static bool IsBeforeHeaderEnd(IReadOnlyList<DrillTapeLine> lines, int lineIndex)
|
|
{
|
|
for (int i = 0; i < lineIndex; i++)
|
|
{
|
|
if (lines[i].Text.Trim() == "%")
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
private static Encoding CreateAnsiEncoding()
|
|
{
|
|
return Encoding.GetEncoding(Gb2312CodePage);
|
|
}
|
|
|
|
}
|
|
}
|