/// <summary> /// FS(0x1C) started variable bytes printer command sequence tokenize routine /// </summary> private void TokenizeFS() { if (s_PrtFSType.ContainsKey(ctlByte1)) { ctlType = s_PrtFSType[ctlByte1].seqtype; blockLength = s_PrtFSType[ctlByte1].length; } else { blockLength = 2; switch (ctlByte1) { case 0x28: // FS ( blockLength = 3; switch (ctlByte2) { case 0x41: // FS ( A case 0x43: // FS ( C case 0x45: // FS ( E case 0x4C: // FS ( L case 0x65: // FS ( e case 0x66: // FS ( f case 0x67: // FS ( g ctlType = EscPosCmdType.None; break; default: // FS ( ?? ctlType = EscPosCmdType.FsUnknown; break; } if (ctlType != EscPosCmdType.FsUnknown) { byte ctlByte5 = (byte)(((curIndex + 5) < dataLength) ? baData[curIndex + 5] : 0xFF); // byte ctlByte6 = (byte)(((curIndex + 6) < dataLength) ? baData[curIndex + 6] : 0xFF); blockLength = 5 + ctlByte4 * 0x100 + ctlByte3; switch (ctlByte2) { case 0x41: // FS ( A 02 00 '0' xx if (blockLength == 7) { if (KanjiFontList.ContainsKey(baData[curIndex + 6])) { KanjiFontSizeInfo info = KanjiFontList[(baData[curIndex + 6])]; ctlType = EscPosCmdType.FsSelectKanjiCharacterFont; CurrentKanjiFontInfo = info; } else { ctlType = EscPosCmdType.FsUnknown; } } else { ctlType = EscPosCmdType.FsUnknown; } break; case 0x43: // FS ( C ctlType = ctlByte5 switch { // FS ( C 02 00 '0' xx 0x30 => (blockLength == 7) ? EscPosCmdType.FsSelectCharacterEncodeSystem : EscPosCmdType.FsUnknown, // FS ( C 03 00 '<' xx xx 0x3C => (blockLength == 8) ? EscPosCmdType.FsSetFontPriority : EscPosCmdType.FsUnknown, _ => EscPosCmdType.FsUnknown, }; break; case 0x45: // FS ( E if (remainLength >= blockLength) { if (s_PrtFSEType.ContainsKey(ctlByte5)) { ctlType = s_PrtFSEType[ctlByte5]; } else // FS ( E dL dH ?? { ctlType = EscPosCmdType.FsUnknown; } } break; case 0x4C: // FS ( L if (remainLength >= blockLength) { if (s_PrtFSLType.ContainsKey(ctlByte5)) { ctlType = s_PrtFSLType[ctlByte5]; } else // FS ( L dL dH ?? { ctlType = EscPosCmdType.FsUnknown; } } break; case 0x65: // FS ( e ctlType = (blockLength == 7) ? EscPosCmdType.FsEnableDisableAutomaticStatusBackOptional : EscPosCmdType.FsUnknown; break; case 0x66: // FS ( f ctlType = EscPosCmdType.FsSelectMICRDataHandling; break; case 0x67: // FS ( g if (remainLength >= blockLength) { if (s_PrtFSgType.ContainsKey(ctlByte5)) { ctlType = s_PrtFSgType[ctlByte5]; } else // FS ( g dL dH ?? { ctlType = EscPosCmdType.FsUnknown; } } break; default: // FS ( ?? ctlType = EscPosCmdType.FsUnknown; break; } } break; case 0x32: // FS 2 --depends on KanjiFontType 72(FontA)/60(FontB)/32(FontC) ctlType = CurrentKanjiFontInfo.seqtype; blockLength = 4 + (CurrentKanjiFontInfo.xbytes * CurrentKanjiFontInfo.ybytes); break; case 0x61: // FS a ctlType = ctlByte2 switch { // FS a 0 0x30 => EscPosCmdType.FsObsoleteReadCheckPaper, // FS a 1 0x31 => EscPosCmdType.FsObsoleteLoadCheckPaperToPrintStartingPosition, // FS a 2 0x32 => EscPosCmdType.FsObsoleteEjectCheckPaper, // FS ( ?? _ => EscPosCmdType.FsUnknown, }; blockLength = ctlType == EscPosCmdType.FsObsoleteReadCheckPaper ? 4 : 3; break; case 0x67: // FS g if ((ctlByte2 == 0x31) && (ctlByte3 == 0x00)) { if (remainLength < 10) { blockLength = 10; break; } ctlType = EscPosCmdType.FsObsoleteWriteNVUserMemory; blockLength = 10 + BitConverter.ToUInt16(baData, (int)(curIndex + 8)); } else if ((ctlByte2 == 0x32) && (ctlByte3 == 0x00)) { ctlType = EscPosCmdType.FsObsoleteReadNVUserMemory; blockLength = 10; } else // FS g ?? ?? { ctlType = EscPosCmdType.FsUnknown; blockLength = 4; } break; case 0x71: // FS q if ((ctlByte2 > 0) && (remainLength >= 15)) { ctlType = EscPosCmdType.None; long imageCount = ctlByte2; long count; long workIndex = curIndex + 3; for (count = 0; (count < imageCount) && (workIndex < dataLength); count++) { long Xbytes = BitConverter.ToUInt16(baData, (int)workIndex); long Ybytes = BitConverter.ToUInt16(baData, (int)(workIndex + 2)); workIndex += 4 + (Xbytes * Ybytes * 8); if (workIndex > dataLength) { ctlType = EscPosCmdType.NotEnough; blockLength = remainLength; break; } } if (ctlType == EscPosCmdType.None) { if (count >= imageCount) { ctlType = EscPosCmdType.FsObsoleteDefineNVBitimage; blockLength = workIndex - curIndex; } else { ctlType = EscPosCmdType.NotEnough; blockLength = remainLength; } } } else // FS 00 or NotEnough { ctlType = EscPosCmdType.FsUnknown; blockLength = 3; } break; default: // FS ?? ctlType = EscPosCmdType.FsUnknown; break; } } }
/// <summary> /// entry point method of EscPosTokenizerr object /// </summary> /// <param name="data">byte array data</param> /// <param name="initialDevice">indicate initial device type</param> /// <returns></returns> public List <EscPosCmd> Scan(byte[] data, long initialDevice = EscPosPrinter, int SbcsFontPattern = 1, int KanjiFontPattern = 1, int LineDisplayFontPattern = 1) { if (data is null) { throw new ArgumentNullException(nameof(data)); } List <EscPosCmd> result = new List <EscPosCmd> { }; long targetDevice = initialDevice; long prtHead = -1; long ctlHead = -1; dataLength = data.Length; baData = data; ctlType = EscPosCmdType.None; SbcsFontList = SbcsFontPattern switch { 1 => s_SbcsFontType01, 2 => s_SbcsFontType02, 3 => s_SbcsFontType03, 4 => s_SbcsFontType04, 5 => s_SbcsFontType05, 6 => s_SbcsFontType06, 7 => s_SbcsFontType07, 8 => s_SbcsFontType08, 9 => s_SbcsFontType09, _ => s_SbcsFontType01, }; CurrentSbcsFontInfo = SbcsFontList[0]; KanjiFontList = KanjiFontPattern switch { 1 => s_KanjiFontType01, 2 => s_KanjiFontType02, 3 => s_KanjiFontType03, 4 => s_KanjiFontType04, 5 => s_KanjiFontType05, _ => s_KanjiFontType01, }; CurrentKanjiFontInfo = KanjiFontList[0]; CurrentVfdFontInfo = LineDisplayFontPattern switch { 1 => s_VfdFontType01, 2 => s_VfdFontType02, _ => s_VfdFontType01, }; for (curIndex = 0; curIndex < dataLength; curIndex += blockLength) { blockLength = 0; ctlByte0 = baData[curIndex]; remainLength = dataLength - curIndex; // special handling for select perihperal device sequence to update process target device type if ((ctlByte0 == 0x1B) && ((((curIndex + 1) < dataLength) ? baData[curIndex + 1] : 0xFF) == 0x3D)) { AddPrintablesAndControls(result, ref ctlHead, ref prtHead); if ((curIndex + 2) < dataLength) { targetDevice = baData[curIndex + 2]; } } // special handling for realtime commands else if (ctlByte0 == 0x10) { AddPrintablesAndControls(result, ref ctlHead, ref prtHead); prtHead = -1; ctlHead = -1; if (remainLength < 2) { ctlType = EscPosCmdType.NotEnough; blockLength = 1; } else { ctlByte1 = (byte)(((curIndex + 1) < dataLength) ? baData[curIndex + 1] : 0xFF); ctlByte2 = (byte)(((curIndex + 2) < dataLength) ? baData[curIndex + 2] : 0xFF); ctlByte3 = (byte)(((curIndex + 3) < dataLength) ? baData[curIndex + 3] : 0xFF); ctlByte4 = (byte)(((curIndex + 4) < dataLength) ? baData[curIndex + 4] : 0xFF); TokenizeDLE(); result.Add(new EscPosCmd(ctlType, ref baData, curIndex, blockLength)); ctlType = EscPosCmdType.None; prtHead = -1; ctlHead = -1; } } // for Printer if ((targetDevice & EscPosPrinter) == EscPosPrinter) { switch (ctlByte0) { // single byte control code case 0x09: // HT case 0x0C: // FF case 0x18: // CAN AddPrintablesAndControls(result, ref ctlHead, ref prtHead); blockLength = 1; ctlType = s_Prt1ByteType[ctlByte0]; result.Add(new EscPosCmd(ctlType, ref baData, curIndex, blockLength)); ctlType = EscPosCmdType.None; prtHead = -1; ctlHead = -1; break; case 0x0A: // LF case 0x0D: // CR AddPrintablesAndControls(result, ref ctlHead, ref prtHead); blockLength = 1; // Consecutive carriage returns and line feeds and vice versa are processed in combination // so that they do not appear redundant. ctlType = s_Prt1ByteType[ctlByte0]; ctlByte1 = (byte)(((curIndex + 1) < dataLength) ? baData[curIndex + 1] : 0); if ((ctlByte0 == 0x0D) && (ctlByte1 == 0x0A)) { blockLength = 2; ctlType = EscPosCmdType.PrintAndCarriageReturnLineFeed; } else if ((ctlByte0 == 0x0A) && (ctlByte1 == 0x0D)) { blockLength = 2; ctlType = EscPosCmdType.PrintAndLineFeedCarriageReturn; } result.Add(new EscPosCmd(ctlType, ref baData, curIndex, blockLength)); ctlType = EscPosCmdType.None; prtHead = -1; ctlHead = -1; break; case 0x10: // DLE break; // Since it is already specially processed as a realtime command, it will not be processed. // muntiple bytes control data sequence case 0x1B: // ESC case 0x1C: // FS case 0x1D: // GS AddPrintablesAndControls(result, ref ctlHead, ref prtHead); if (remainLength < 2) { ctlType = EscPosCmdType.NotEnough; blockLength = 1; } else { ctlByte1 = (byte)(((curIndex + 1) < dataLength) ? baData[curIndex + 1] : 0xFF); ctlByte2 = (byte)(((curIndex + 2) < dataLength) ? baData[curIndex + 2] : 0xFF); ctlByte3 = (byte)(((curIndex + 3) < dataLength) ? baData[curIndex + 3] : 0xFF); ctlByte4 = (byte)(((curIndex + 4) < dataLength) ? baData[curIndex + 4] : 0xFF); switch (ctlByte0) { case 0x1B: TokenizeESCprt(); break; case 0x1C: TokenizeFS(); break; case 0x1D: TokenizeGS(); break; } } if (remainLength < blockLength) { ctlType = EscPosCmdType.NotEnough; blockLength = remainLength; } result.Add(new EscPosCmd(ctlType, ref baData, curIndex, blockLength)); ctlType = EscPosCmdType.None; prtHead = -1; ctlHead = -1; break; default: // printable data if (ctlByte0 >= 0x20) { if (ctlHead >= 0) { result.Add(new EscPosCmd(ctlType, ref baData, ctlHead, (curIndex - ctlHead))); ctlHead = -1; } if (prtHead < 0) { prtHead = curIndex; ctlType = EscPosCmdType.PrtPrintables; } } // unused control code else { if (prtHead >= 0) { result.Add(new EscPosCmd(ctlType, ref baData, prtHead, (curIndex - prtHead))); prtHead = -1; } if (ctlHead < 0) { ctlHead = curIndex; ctlType = EscPosCmdType.Controls; } } blockLength = 1; break; } } // for LineDisplay else if ((targetDevice & EscPosLineDisplay) == EscPosLineDisplay) { switch (ctlByte0) { // single byte control code case 0x08: // BS case 0x09: // HT case 0x0A: // LF case 0x0B: // HOM case 0x0C: // CLR case 0x0D: // CR case 0x18: // CAN AddPrintablesAndControls(result, ref ctlHead, ref prtHead); blockLength = 1; ctlType = s_Vfd1ByteType[ctlByte0]; result.Add(new EscPosCmd(ctlType, ref baData, curIndex, blockLength)); ctlType = EscPosCmdType.None; prtHead = -1; ctlHead = -1; break; case 0x10: // DLE break; // guard for printer already specially processed as a realtime command, it will not be processed. // muntiple bytes control data sequence case 0x1B: // ESC case 0x1F: // US AddPrintablesAndControls(result, ref ctlHead, ref prtHead); if (remainLength < 2) { ctlType = EscPosCmdType.NotEnough; blockLength = 1; } else { ctlByte1 = (byte)(((curIndex + 1) < dataLength) ? baData[curIndex + 1] : 0xFF); ctlByte2 = (byte)(((curIndex + 2) < dataLength) ? baData[curIndex + 2] : 0xFF); ctlByte3 = (byte)(((curIndex + 3) < dataLength) ? baData[curIndex + 3] : 0xFF); ctlByte4 = (byte)(((curIndex + 4) < dataLength) ? baData[curIndex + 4] : 0xFF); switch (ctlByte0) { case 0x1B: TokenizeESCvfd(); break; case 0x1F: TokenizeUS(); break; } } if (remainLength < blockLength) { ctlType = EscPosCmdType.NotEnough; blockLength = remainLength; } result.Add(new EscPosCmd(ctlType, ref baData, curIndex, blockLength)); ctlType = EscPosCmdType.None; prtHead = -1; ctlHead = -1; break; default: // printable data if (ctlByte0 >= 0x20) { if (ctlHead >= 0) { result.Add(new EscPosCmd(ctlType, ref baData, ctlHead, (curIndex - ctlHead))); ctlHead = -1; } if (prtHead < 0) { prtHead = curIndex; ctlType = EscPosCmdType.VfdDisplayables; } } // unused control code else { if (prtHead >= 0) { result.Add(new EscPosCmd(ctlType, ref baData, prtHead, (curIndex - prtHead))); prtHead = -1; } if (ctlHead < 0) { ctlHead = curIndex; ctlType = EscPosCmdType.Controls; } } blockLength = 1; break; } } else { blockLength = 1; } } AddPrintablesAndControls(result, ref ctlHead, ref prtHead); baData = null; return(result); }