// // RecipeStore.cpp - レシピの保存/読込。行ベースの UTF-8 テキスト。 // // ImgTestSystem Recipe v1 // ROI // STEP // PARAM // ... // #include "stdafx.h" #include "RecipeStore.h" #include "StepCatalog.h" namespace core { namespace { void WriteUtf8(CFile& f, const CString& s) { int n = WideCharToMultiByte(CP_UTF8, 0, s, s.GetLength(), NULL, 0, NULL, NULL); if (n <= 0) return; CStringA a; WideCharToMultiByte(CP_UTF8, 0, s, s.GetLength(), a.GetBuffer(n), n, NULL, NULL); a.ReleaseBuffer(n); f.Write((LPCSTR)a, a.GetLength()); } CString ReadAllUtf8(LPCWSTR path) { CFile f; if (!f.Open(path, CFile::modeRead | CFile::shareDenyWrite)) return L""; ULONGLONG len = f.GetLength(); if (len == 0 || len > (50 * 1024 * 1024)) return L""; CStringA a; UINT got = f.Read(a.GetBuffer((int)len), (UINT)len); a.ReleaseBuffer(got); // BOM 除去 if (a.GetLength() >= 3 && (BYTE)a[0] == 0xEF && (BYTE)a[1] == 0xBB && (BYTE)a[2] == 0xBF) a = a.Mid(3); int wn = MultiByteToWideChar(CP_UTF8, 0, a, a.GetLength(), NULL, 0); CString w; MultiByteToWideChar(CP_UTF8, 0, a, a.GetLength(), w.GetBuffer(wn), wn); w.ReleaseBuffer(wn); return w; } } // namespace bool SaveRecipe(LPCWSTR path, const Recipe& r) { CFile f; if (!f.Open(path, CFile::modeCreate | CFile::modeWrite)) return false; // UTF-8 BOM const unsigned char bom[3] = { 0xEF, 0xBB, 0xBF }; f.Write(bom, 3); WriteUtf8(f, L"ImgTestSystem Recipe v1\r\n"); for (const CRect& roi : r.rois) { CString line; line.Format(L"ROI %d %d %d %d\r\n", (int)roi.left, (int)roi.top, (int)roi.right, (int)roi.bottom); WriteUtf8(f, line); } for (const Step& s : r.steps) { WriteUtf8(f, L"STEP " + StepKindId(s.kind) + L"\r\n"); for (const StepParam& p : s.params) { CString pl; pl.Format(L"PARAM %s %.6g\r\n", (LPCWSTR)p.key, p.value); WriteUtf8(f, pl); } } f.Close(); return true; } bool LoadRecipe(LPCWSTR path, Recipe& out) { CString text = ReadAllUtf8(path); if (text.IsEmpty()) return false; Recipe r; bool sawHeader = false; Step* cur = nullptr; int pos = 0; while (pos < text.GetLength()) { int nl = text.Find(L'\n', pos); CString line = (nl < 0) ? text.Mid(pos) : text.Mid(pos, nl - pos); pos = (nl < 0) ? text.GetLength() : nl + 1; line.TrimRight(L"\r"); line.TrimLeft(); if (line.IsEmpty()) continue; if (line.Find(L"ImgTestSystem Recipe") == 0) { sawHeader = true; continue; } if (line.Left(4) == L"ROI ") { // 新形式: ROI l t r b(4値) / 旧形式: ROI enabled l t r b(5値) int a = 0, bb = 0, c = 0, d = 0, e = 0; int got = swscanf_s((LPCWSTR)line, L"ROI %d %d %d %d %d", &a, &bb, &c, &d, &e); if (got == 5) { if (a != 0) r.rois.push_back(CRect(bb, c, d, e)); } else if (got == 4) { r.rois.push_back(CRect(a, bb, c, d)); } continue; } if (line.Left(5) == L"STEP ") { CString id = line.Mid(5); id.Trim(); StepKind k; if (StepKindFromId(id, k)) { r.steps.push_back(MakeStep(k)); cur = &r.steps.back(); } else cur = nullptr; continue; } if (line.Left(6) == L"PARAM " && cur) { CString rest = line.Mid(6); rest.Trim(); int sp = rest.Find(L' '); if (sp <= 0) continue; CString key = rest.Left(sp); double val = _wtof(rest.Mid(sp + 1)); cur->SetParam(key, val); // 既定パラメータのうち一致キーのみ上書き continue; } } if (r.steps.empty() && !sawHeader) return false; out = r; return true; } } // namespace core