|
<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; }
}
}
}
|