C# と VB.NET の質問掲示板

わんくま同盟

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト


(過去ログ 27 を表示中)
■12372 / )  Re[11]: 添え字がInt64(long)の可変長リストが欲しい
□投稿者/ Hirotow (126回)-(2008/01/08(Tue) 18:39:18)
<s>こうですか? わかりません><</s>こんな感じですかね?
うまく動く自信がないorz

using System;
using System.Collections.Generic;
using System.Text;
using System.IO;

namespace BinaryEditor
{
	class BinaryBuffer
	{
		const int PAGE_LEN = 0x00002000;

		Stream stream;

		public Stream Stream
		{
			get { return stream; }
		}

		LinkedList<BinaryPage> pages;

		bool bReadOnly;
		public bool ReadOnly
		{
			get { return bReadOnly; }
			set { bReadOnly = value; }
		}

		long Length
		{
			get
			{
				long len = 0;
				foreach (BinaryPage p in pages) {
					len += p.Length;
				}
				return len;
			}
		}

		public BinaryBuffer()
		{
			stream = new MemoryStream();
		}

		public BinaryBuffer(Stream s)
		{
			if (!s.CanRead || !s.CanSeek) {
				throw new ArgumentException(
					"読み込みおよびシークの可能なストリームのみでBinaryBufferを初期化できます。");
			}
			if (!s.CanWrite) {
				bReadOnly = true;
			}
			stream = s;

			//ページの論理情報を作成
			pages = new LinkedList<BinaryPage>();
			for (long i = 0; i < s.Length / PAGE_LEN - 1; i++) {
				pages.AddLast(new BinaryPage(i * PAGE_LEN, PAGE_LEN));
			}
			pages.AddLast(new BinaryPage((s.Length / PAGE_LEN) * PAGE_LEN,
				(int)((s.Length / PAGE_LEN + 1) * PAGE_LEN - s.Length)));
		}

		private BinaryPage GetPageByPos(long pos)
		{
			BinaryPage page = null;
			foreach (BinaryPage p in pages) {
				if (p.Position < pos) {
					page = p;
					break;
				}
			}
			return page;
		}

		private BinaryPage GetPageByPos(long pos, out IEnumerator<BinaryPage> ie)
		{
			ie = pages.GetEnumerator();
			BinaryPage p = null, page = null;
			while (ie.MoveNext()) {
				p = ie.Current;
				if (p.Position < pos) {
					page = p;
					break;
				}
			}
			return page;
		}

		public byte GetByteAt(long pos)
		{
			BinaryPage page = GetPageByPos(pos);
			if (page.Modified) {
				return page.Buffer[(int)(pos - page.Position)];
			} else {
				stream.Seek(pos - page.Position + page.SourcePosition, SeekOrigin.Begin);
				return (byte)stream.ReadByte();
			}
		}

		public byte[] GetBytesAt(long pos, int len)
		{
			byte[] buf = new byte[len];
			int tlen = 0, offset = 0;
			foreach (BinaryPage p in pages) {
				if (p.Position < pos) {
					tlen = Math.Min((int)(p.Length - (pos - p.Position)), len);
					if (p.Modified) {
						p.Buffer.CopyTo((int)(pos - p.Position), buf, offset, tlen);
					} else {
						stream.Seek(pos - p.Position + p.SourcePosition, SeekOrigin.Begin);
						stream.Read(buf, offset, tlen);
					}
					pos += tlen;
					offset += tlen;

					if (offset >= len)
						break;
				}
			}
			return buf;
		}

		public void MakeBuffer(BinaryPage page)
		{
			if (!page.Modified) {
				byte[] buf = new byte[page.Length];
				stream.Seek(page.SourcePosition, SeekOrigin.Begin);
				stream.Read(buf, 0, page.Length);
				page.Buffer = new List<byte>(buf);
			}
		}

		public void Insert(long pos, byte data)
		{
			IEnumerator<BinaryPage> ie;
			BinaryPage page = GetPageByPos(pos, out ie);
			MakeBuffer(page);
			page.Buffer.Insert((int)(pos - page.Position), data);
			while (ie.MoveNext()) {
				ie.Current.Position++;
			}
		}

		public void InsertRange(byte[] data, long pos, int len)
		{
			IEnumerator<BinaryPage> ie;
			BinaryPage page = GetPageByPos(pos, out ie);
			MakeBuffer(page);
			page.Buffer.InsertRange((int)(pos - page.Position), data);
			while (ie.MoveNext()) {
				ie.Current.Position += data.Length;
			}
		}

		void Delete(long pos)
		{
			IEnumerator<BinaryPage> ie;
			BinaryPage page = GetPageByPos(pos, out ie);
			MakeBuffer(page);
			while (ie.MoveNext()) {
				ie.Current.Position--;
			}
			if (page.Length > 1) {
				page.Buffer.RemoveAt((int)(pos - page.Position));
			} else {
				pages.Remove(page);
			}
		}

		void RemoveRange(long pos, long len)
		{
			int tlen = 0, deleted = 0;
			IEnumerator<BinaryPage> ie = pages.GetEnumerator();
			BinaryPage p;
			while (ie.MoveNext()) {
				p = ie.Current;
				if (p.Position < pos) {
					tlen = (int)Math.Min(p.Length - (pos - p.Position), len);
					if (tlen == p.Length) {
						pages.Remove(p);
					} else {
						MakeBuffer(p);
						p.Buffer.RemoveRange((int)(pos - p.Position), tlen);
					}
					pos += tlen;
					deleted += tlen;

					if (deleted >= len) {
						p.Position = pos;
						break;
					}
				}
			}
			while (ie.MoveNext()) {
				p = ie.Current;
				p.Position -= len;
			}
		}

		void OverWrite(byte data, long pos)
		{
			BinaryPage p = GetPageByPos(pos);
			MakeBuffer(p);
			p.Buffer.RemoveAt((int)(pos - p.Position));
			p.Buffer.Insert((int)(pos - p.Position), data);
		}

		void OverWriteRange(byte[] data, long pos, int len)
		{
			int tlen = 0, offset = 0;
			foreach (BinaryPage p in pages) {
				if (p.Position < pos) {
					tlen = (int)Math.Min(p.Length - (pos - p.Position), len);
					MakeBuffer(p);
					p.Buffer.RemoveRange(offset, tlen);
					byte[] buf = new byte[tlen];
					Array.Copy(data, offset, buf, 0, tlen);
					p.Buffer.InsertRange(offset, buf);
					pos += tlen;
					offset += tlen;

					if (offset >= len)
						break;
				}
			}
		}
	}
	
	class BinaryPage
	{
		public BinaryPage(long pos, int len)
		{
			this.position = pos;
			this.sourcePosition = pos;
			this.length = len;
		}

		long position;

		public long Position
		{
			get { return position; }
			set { position = value; }
		}

		long sourcePosition;

		public long SourcePosition
		{
			get { return sourcePosition; }
		}

		int length;

		public int Length
		{
			get
			{
				if (Modified) {
					return buffer.Count;
				} else {
					return length;
				}
			}
		}

		public bool Modified
		{
			get { return buffer != null; }
		}

		List<byte> buffer;

		public List<byte> Buffer
		{
			get { return buffer; }
			set { buffer = value; }
		}
	}
}

返信 編集キー/


管理者用

- Child Tree -