Quantcast
Channel: C#タグが付けられた新着記事 - Qiita
Viewing all articles
Browse latest Browse all 9749

C# - ブランク領域を含むmotファイル(S-Record)を入力として複数のbinファイルを出力する - 自分用

$
0
0

入出力のイメージ

入力

sample.mot
S113000000000100000001000000010000000100E8
S113001000000100000001000000010000000100D8
S113002000000100000001000000010000000100C8
S11300D00000010000000100000001000000010018
S11300E00000010000000100000001000000010008
S10700F00000010007

出力(中身はただのバイナリ)

生成されるファイル
_00000000_0000002F.bin
_000000D0_000000F3.bin

入力motに対する前提条件

  • アドレスが昇順になっていない場合の連結は未サポート(つながった領域でも細切れにbinが生成されるはず。)
  • intの最大値の半分(1024MB相当)以上の大きさのデータは多分扱えないです。1

ソースコード

なぐり書きコードでろくにテストもしてないので、参考程度ということにしてください。

usingSystem;usingSystem.Collections;usingSystem.Collections.Generic;usingSystem.IO;usingSystem.Text;usingSystem.Text.RegularExpressions;internalclassDataBlocks{// Key: addresspublicSortedList<long,DataBlock>Blocks{get;privateset;}DataBlock_lastAdded;publicboolConsistencyPassed{get;privateset;}publicDataBlocks(){Blocks=newSortedList<long,DataBlock>();_lastAdded=null;ConsistencyPassed=false;}// エラー(重複検出時)は return falsepublicboolAppend(DataBlockb){if(b.Size==0){returntrue;// 長さがないデータは無視する(正常扱い)}if(_lastAdded==null){// まだデータがないBlocks.Add(b.Address,b);_lastAdded=b;returntrue;}ConsistencyPassed=false;if(Blocks.ContainsKey(b.Address)){// overlapreturnfalse;}if(_lastAdded.TryAppendBlock(b)){// 最終要素に連結できた。// nothing to do.returntrue;}else{Blocks.Add(b.Address,b);_lastAdded=b;returntrue;}}// overlapがないかチェック。// (memo: 連結できれば連結するようにしたい TryToConcatAndCheckNoOverlap ... これは未実装)publicboolCheckNoOverlap(){DataBlockprevBlock=null;foreach(varbinBlocks.Values){if(prevBlock!=null){if(b.IsOverlap(prevBlock)){returnfalse;}//else if ( prevBlock.EndAddress+1 == b.Address ) {  // 連結可能//  ただ、foreach内でこれをやると不整合が起きそう// 未実装//}}prevBlock=b;}ConsistencyPassed=true;returntrue;}publicstaticDataBlocksFromMotFile(stringfileName){varres=newDataBlocks();string[]ss=File.ReadAllLines(fileName);intlineNo=0;foreach(stringsinss){lineNo++;if(String.IsNullOrWhiteSpace(s)){continue;}varoneRecord=OneRecord.FromString(s);if(oneRecord==null){Console.WriteLine("Warning: Line "+lineNo.ToString()+" is ignored.");}else{if(!res.Append(DataBlock.FromOneRecord(oneRecord))){// conflicted(overlapp)Console.WriteLine("Warning: Line "+lineNo.ToString()+" is ignored (start address conflicted).");}}}returnres;}}internalclassDataBlock{publiclongAddress{get;privateset;}publiclongEndAddress{get{returnAddress+Size-1;}}publiclongSize{get;privateset;}// 有効データ部分のサイズlongInternalSize{get{returnData.Length;}}// Array.Resize が ref を使っており、実体をフィールド宣言せざるをえない。// (プロパティはref/outで参照できない。)byte[]_data;publicbyte[]Data{get{return_data;}privateset{_data=value;}}// バッファとして確保しているサイズを含むpublicDataBlock(longaddr,byte[]data){Address=addr;Size=data.Length;Data=newbyte[data.Length];Array.Copy(data,0,Data,0,Size);}publicstaticDataBlockFromOneRecord(OneRecordrecord){returnnewDataBlock(record.Address,record.DataBytes);}// 有効データが入っている部分のデータを返すpublicbyte[]GetActualDataBytes(){if(Size==InternalSize){returnData;}else{byte[]t=newbyte[Size];Array.Copy(Data,0,t,0,Size);returnt;}}publicvoidSaveAsBinaryFile(stringdestPath){File.WriteAllBytes(destPath,GetActualDataBytes());}// アドレスが後ろ側につながっていれば連結する。// 結合できる(=できた)場合は true を返す。publicboolTryAppendBlock(DataBlockb){if(EndAddress+1==b.Address){if(InternalSize<Size+b.Size){// サイズが足りない。intnewInternalSize;checked{// リサイズするnewInternalSize=(int)(Size+b.Size);if(newInternalSize<(int)(2*Size)){// リサイズが必要となる頻度を抑制するため、大きめに確保しておくnewInternalSize=(int)(2*Size);}}Array.Resize(ref_data,newInternalSize);}Array.Copy(b.Data,0,Data,Size,b.Size);// bの有効データを、thisの有効データの末尾(位置=Size)以降にコピーするSize+=b.Size;returntrue;}returnfalse;}publicboolIsOverlap(DataBlockb){return!IsExclusive(b);}boolIsExclusive(DataBlockb){if(EndAddress<b.Address){returntrue;}if(b.EndAddress<Address){returntrue;}returnfalse;}}// S-Record 1行分のデータを扱うclassOneRecord{// This program ignores S5, S7, S8, S9.staticRegexrSn=newRegex(@"^S([01235789])");staticRegexrS0=newRegex(@"^S(0)([0-9A-Fa-f]{2})((?:[0-9A-Fa-f]{2})*)([0-9A-Fa-f]{2})$");staticRegexrS1=newRegex(@"^S(1)([0-9A-Fa-f]{2})([0-9A-Fa-f]{4})((?:[0-9A-Fa-f]{2})+)([0-9A-Fa-f]{2})$");staticRegexrS2=newRegex(@"^S(2)([0-9A-Fa-f]{2})([0-9A-Fa-f]{6})((?:[0-9A-Fa-f]{2})+)([0-9A-Fa-f]{2})$");staticRegexrS3=newRegex(@"^S(3)([0-9A-Fa-f]{2})([0-9A-Fa-f]{8})((?:[0-9A-Fa-f]{2})+)([0-9A-Fa-f]{2})$");publicintRecordType{get;privateset;}publicintRecordLength{get;privateset;}publiclongAddress{get;privateset;}publicbyte[]DataBytes{get;privateset;}publicbyteCheckSum{get;privateset;}publicintDataLength{get{returnDataBytes.Length;}}publiclongEndAddress{get{returnAddress+DataBytes.Length-1;}}publicboolIsValidSum{get{returnCalcCheckSum()==CheckSum;}}byteCalcCheckSum(){intsum=0;sum+=RecordLength;sum+=(byte)(Address>>24);sum+=(byte)(Address>>16);sum+=(byte)(Address>>8);sum+=(byte)Address;foreach(bytebinDataBytes){sum+=b;}return(byte)(~sum);}OneRecord(){}publicstaticOneRecordFromString(strings,boolcheckFormat=true){Matchm;m=rSn.Match(s);if(!m.Success){returnnull;}m=rS1.Match(s);if(!m.Success){m=rS2.Match(s);}if(!m.Success){m=rS3.Match(s);}if(!m.Success){returnnull;}varret=newOneRecord();ret.RecordType=Convert.ToInt32(m.Groups[1].Value);ret.RecordLength=Convert.ToInt32(m.Groups[2].Value,16);ret.Address=Convert.ToInt64(m.Groups[3].Value,16);ret.DataBytes=HexStrToByteArray(m.Groups[4].Value);ret.CheckSum=Convert.ToByte(m.Groups[5].Value,16);if(checkFormat){if(ret.RecordLength*2!=s.Length-4){Console.WriteLine("LengthError");returnnull;}if(!ret.IsValidSum){Console.WriteLine("ChkSumError");returnnull;}}returnret;}staticintHexCharToInt(charc){if('0'<=c&&c<='9'){returnc-'0';}if('A'<=c&&c<='F'){return(c-'A')+10;}if('a'<=c&&c<='f'){return(c-'a')+10;}return-1;}staticbyte[]HexStrToByteArray(strings){// length of the argument `s` must be even value. byte[]a=newbyte[s.Length/2];for(intpos=0;pos+1<s.Length;pos+=2){a[pos/2]=(byte)((HexCharToInt(s[pos])<<4)|HexCharToInt(s[pos+1]));}returna;}}classMotFileTest{[STAThread]staticvoidMain(string[]args){if(args.Length!=1){return;}vardataBlocks=DataBlocks.FromMotFile(args[0]);if(dataBlocks.CheckNoOverlap()){foreach(varblockindataBlocks.Blocks.Values){stringfileName=Path.GetFullPath("_"+block.Address.ToString("X08")+"_"+block.EndAddress.ToString("X08")+".bin");Console.WriteLine(fileName);block.SaveAsBinaryFile(fileName);}}}}

ひとりごと

アドレスでソートしておいたほうがデータを扱いやすいかなと思い、SortedListを初めて使ってみた。
ListよりDictionaryに近い感じ(?)

参考サイト


  1. おそらく下記コードのTryAppendBlockあたりの処理でオーバーフローするはず。 


Viewing all articles
Browse latest Browse all 9749

Trending Articles