diff options
author | MW | 2007-08-10 13:59:19 +0000 |
---|---|---|
committer | MW | 2007-08-10 13:59:19 +0000 |
commit | 94c7e41ef1978a5be21e1a063c68ffc1c8a89b97 (patch) | |
tree | f40b2951bfbabe0bff2553355e3603450c737b0a /OpenSim/Region | |
parent | Couldn't leave this one alone. Data is now flowing both ways in (diff) | |
download | opensim-SC-94c7e41ef1978a5be21e1a063c68ffc1c8a89b97.zip opensim-SC-94c7e41ef1978a5be21e1a063c68ffc1c8a89b97.tar.gz opensim-SC-94c7e41ef1978a5be21e1a063c68ffc1c8a89b97.tar.bz2 opensim-SC-94c7e41ef1978a5be21e1a063c68ffc1c8a89b97.tar.xz |
Made a few changes so that once we enable the sqlite data store (simple line change in OpenSimMain), then basic ( with a few limits at moment) prim database backup will work.
Diffstat (limited to 'OpenSim/Region')
7 files changed, 123 insertions, 28 deletions
diff --git a/OpenSim/Region/ClientStack/ClientView.API.cs b/OpenSim/Region/ClientStack/ClientView.API.cs index 8a2db98..81c20e8 100644 --- a/OpenSim/Region/ClientStack/ClientView.API.cs +++ b/OpenSim/Region/ClientStack/ClientView.API.cs | |||
@@ -844,7 +844,7 @@ namespace OpenSim.Region.ClientStack | |||
844 | 844 | ||
845 | byte[] rot = rotation.GetBytes(); | 845 | byte[] rot = rotation.GetBytes(); |
846 | Array.Copy(rot, 0, outPacket.ObjectData[0].ObjectData, 36, rot.Length); | 846 | Array.Copy(rot, 0, outPacket.ObjectData[0].ObjectData, 36, rot.Length); |
847 | 847 | ||
848 | OutPacket(outPacket); | 848 | OutPacket(outPacket); |
849 | } | 849 | } |
850 | 850 | ||
diff --git a/OpenSim/Region/ClientStack/RegionApplicationBase.cs b/OpenSim/Region/ClientStack/RegionApplicationBase.cs index c67ae66..05c970a 100644 --- a/OpenSim/Region/ClientStack/RegionApplicationBase.cs +++ b/OpenSim/Region/ClientStack/RegionApplicationBase.cs | |||
@@ -115,7 +115,7 @@ namespace OpenSim.Region.ClientStack | |||
115 | 115 | ||
116 | scene.PhysScene = GetPhysicsScene( ); | 116 | scene.PhysScene = GetPhysicsScene( ); |
117 | scene.PhysScene.SetTerrain(scene.Terrain.GetHeights1D()); | 117 | scene.PhysScene.SetTerrain(scene.Terrain.GetHeights1D()); |
118 | scene.LoadPrimsFromStorage(); | 118 | scene.LoadPrimsFromStorage(); |
119 | 119 | ||
120 | //Master Avatar Setup | 120 | //Master Avatar Setup |
121 | UserProfileData masterAvatar = m_commsManager.UserServer.SetupMasterUser(scene.RegionInfo.MasterAvatarFirstName, scene.RegionInfo.MasterAvatarLastName, scene.RegionInfo.MasterAvatarSandboxPassword); | 121 | UserProfileData masterAvatar = m_commsManager.UserServer.SetupMasterUser(scene.RegionInfo.MasterAvatarFirstName, scene.RegionInfo.MasterAvatarLastName, scene.RegionInfo.MasterAvatarSandboxPassword); |
diff --git a/OpenSim/Region/Environment/Scenes/Scene.cs b/OpenSim/Region/Environment/Scenes/Scene.cs index c2eac60..ef7346d 100644 --- a/OpenSim/Region/Environment/Scenes/Scene.cs +++ b/OpenSim/Region/Environment/Scenes/Scene.cs | |||
@@ -151,15 +151,6 @@ namespace OpenSim.Region.Environment.Scenes | |||
151 | Avatars = new Dictionary<LLUUID, ScenePresence>(); | 151 | Avatars = new Dictionary<LLUUID, ScenePresence>(); |
152 | Prims = new Dictionary<LLUUID, SceneObjectGroup>(); | 152 | Prims = new Dictionary<LLUUID, SceneObjectGroup>(); |
153 | 153 | ||
154 | MainLog.Instance.Verbose("Loading objects from datastore"); | ||
155 | List<SceneObjectGroup> PrimsFromDB = storageManager.DataStore.LoadObjects(); | ||
156 | foreach (SceneObjectGroup prim in PrimsFromDB) | ||
157 | { | ||
158 | AddEntity(prim); | ||
159 | } | ||
160 | MainLog.Instance.Verbose("Loaded " + PrimsFromDB.Count.ToString() + " object(s)"); | ||
161 | |||
162 | |||
163 | MainLog.Instance.Verbose("Creating LandMap"); | 154 | MainLog.Instance.Verbose("Creating LandMap"); |
164 | Terrain = new TerrainEngine((int)this.RegionInfo.RegionLocX, (int)this.RegionInfo.RegionLocY); | 155 | Terrain = new TerrainEngine((int)this.RegionInfo.RegionLocX, (int)this.RegionInfo.RegionLocY); |
165 | 156 | ||
@@ -238,7 +229,7 @@ namespace OpenSim.Region.Environment.Scenes | |||
238 | 229 | ||
239 | //backup scene data | 230 | //backup scene data |
240 | storageCount++; | 231 | storageCount++; |
241 | if (storageCount > 1200) //set to how often you want to backup | 232 | if (storageCount > 600) //set to how often you want to backup |
242 | { | 233 | { |
243 | Backup(); | 234 | Backup(); |
244 | storageCount = 0; | 235 | storageCount = 0; |
@@ -462,12 +453,13 @@ namespace OpenSim.Region.Environment.Scenes | |||
462 | /// </summary> | 453 | /// </summary> |
463 | public void LoadPrimsFromStorage() | 454 | public void LoadPrimsFromStorage() |
464 | { | 455 | { |
465 | MainLog.Instance.Verbose("World.cs: LoadPrimsFromStorage() - Loading primitives"); | 456 | MainLog.Instance.Verbose("Loading objects from datastore"); |
466 | List<SceneObjectGroup> NewObjectsList = storageManager.DataStore.LoadObjects(); | 457 | List<SceneObjectGroup> PrimsFromDB = storageManager.DataStore.LoadObjects(); |
467 | foreach (SceneObjectGroup obj in NewObjectsList) | 458 | foreach (SceneObjectGroup prim in PrimsFromDB) |
468 | { | 459 | { |
469 | this.Objects.Add(obj.UUID, obj); | 460 | AddEntityFromStorage(prim); |
470 | } | 461 | } |
462 | MainLog.Instance.Verbose("Loaded " + PrimsFromDB.Count.ToString() + " object(s)"); | ||
471 | } | 463 | } |
472 | 464 | ||
473 | /// <summary> | 465 | /// <summary> |
@@ -520,6 +512,17 @@ namespace OpenSim.Region.Environment.Scenes | |||
520 | } | 512 | } |
521 | } | 513 | } |
522 | 514 | ||
515 | public void AddEntityFromStorage(SceneObjectGroup sceneObject) | ||
516 | { | ||
517 | sceneObject.RegionHandle = this.m_regionHandle; | ||
518 | sceneObject.SetScene(this); | ||
519 | foreach (SceneObjectPart part in sceneObject.Children.Values) | ||
520 | { | ||
521 | part.LocalID = this.PrimIDAllocate(); | ||
522 | } | ||
523 | this.AddEntity(sceneObject); | ||
524 | } | ||
525 | |||
523 | public void AddEntity(SceneObjectGroup sceneObject) | 526 | public void AddEntity(SceneObjectGroup sceneObject) |
524 | { | 527 | { |
525 | Entities.Add(sceneObject.UUID, sceneObject); | 528 | Entities.Add(sceneObject.UUID, sceneObject); |
@@ -781,7 +784,7 @@ namespace OpenSim.Region.Environment.Scenes | |||
781 | { | 784 | { |
782 | if (ent is SceneObjectGroup) | 785 | if (ent is SceneObjectGroup) |
783 | { | 786 | { |
784 | // ((SceneObject) ent).SendAllChildPrimsToClient(client); | 787 | ((SceneObjectGroup) ent).SendFullUpdateToClient(client); |
785 | } | 788 | } |
786 | } | 789 | } |
787 | } | 790 | } |
diff --git a/OpenSim/Region/Environment/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Environment/Scenes/SceneObjectGroup.cs index 78dd69c..8b761f6 100644 --- a/OpenSim/Region/Environment/Scenes/SceneObjectGroup.cs +++ b/OpenSim/Region/Environment/Scenes/SceneObjectGroup.cs | |||
@@ -44,6 +44,27 @@ namespace OpenSim.Region.Environment.Scenes | |||
44 | set { m_parts = value; } | 44 | set { m_parts = value; } |
45 | } | 45 | } |
46 | 46 | ||
47 | public SceneObjectPart RootPart | ||
48 | { | ||
49 | set { m_rootPart = value; } | ||
50 | } | ||
51 | |||
52 | public ulong RegionHandle | ||
53 | { | ||
54 | get { return m_regionHandle; } | ||
55 | set | ||
56 | { | ||
57 | m_regionHandle = value; | ||
58 | lock (this.m_parts) | ||
59 | { | ||
60 | foreach (SceneObjectPart part in this.m_parts.Values) | ||
61 | { | ||
62 | part.RegionHandle = m_regionHandle; | ||
63 | } | ||
64 | } | ||
65 | } | ||
66 | } | ||
67 | |||
47 | public override LLVector3 Pos | 68 | public override LLVector3 Pos |
48 | { | 69 | { |
49 | get { return m_rootPart.GroupPosition; } | 70 | get { return m_rootPart.GroupPosition; } |
@@ -79,9 +100,9 @@ namespace OpenSim.Region.Environment.Scenes | |||
79 | /// <summary> | 100 | /// <summary> |
80 | /// Added because the Parcel code seems to use it | 101 | /// Added because the Parcel code seems to use it |
81 | /// but not sure a object should have this | 102 | /// but not sure a object should have this |
82 | /// as what does it tell us? that some avatar has selected it | 103 | /// as what does it tell us? that some avatar has selected it (but not what Avatar/user) |
83 | /// think really there should be a list (or whatever) in each scenepresence | 104 | /// think really there should be a list (or whatever) in each scenepresence |
84 | /// saying what prim(s) that user has selected at any time. | 105 | /// saying what prim(s) that user has selected. |
85 | /// </summary> | 106 | /// </summary> |
86 | protected bool m_isSelected = false; | 107 | protected bool m_isSelected = false; |
87 | public bool IsSelected | 108 | public bool IsSelected |
@@ -114,7 +135,7 @@ namespace OpenSim.Region.Environment.Scenes | |||
114 | m_regionHandle = regionHandle; | 135 | m_regionHandle = regionHandle; |
115 | m_scene = scene; | 136 | m_scene = scene; |
116 | 137 | ||
117 | this.Pos = pos; | 138 | // this.Pos = pos; |
118 | LLVector3 rootOffset = new LLVector3(0, 0, 0); | 139 | LLVector3 rootOffset = new LLVector3(0, 0, 0); |
119 | SceneObjectPart newPart = new SceneObjectPart(m_regionHandle, this, ownerID, localID, shape, pos, rootOffset); | 140 | SceneObjectPart newPart = new SceneObjectPart(m_regionHandle, this, ownerID, localID, shape, pos, rootOffset); |
120 | this.m_parts.Add(newPart.UUID, newPart); | 141 | this.m_parts.Add(newPart.UUID, newPart); |
@@ -136,6 +157,7 @@ namespace OpenSim.Region.Environment.Scenes | |||
136 | dupe.m_regionHandle = this.m_regionHandle; | 157 | dupe.m_regionHandle = this.m_regionHandle; |
137 | 158 | ||
138 | dupe.CopyRootPart(this.m_rootPart); | 159 | dupe.CopyRootPart(this.m_rootPart); |
160 | m_scene.EventManager.OnBackup += dupe.ProcessBackup; | ||
139 | 161 | ||
140 | foreach (SceneObjectPart part in this.m_parts.Values) | 162 | foreach (SceneObjectPart part in this.m_parts.Values) |
141 | { | 163 | { |
@@ -148,6 +170,23 @@ namespace OpenSim.Region.Environment.Scenes | |||
148 | } | 170 | } |
149 | 171 | ||
150 | /// <summary> | 172 | /// <summary> |
173 | /// Added as a way for the storage provider to reset the scene, | ||
174 | /// most likely a better way to do this sort of thing but for now... | ||
175 | /// </summary> | ||
176 | /// <param name="scene"></param> | ||
177 | public void SetScene(Scene scene) | ||
178 | { | ||
179 | m_scene = scene; | ||
180 | m_scene.EventManager.OnBackup += this.ProcessBackup; | ||
181 | } | ||
182 | |||
183 | public void AddPart(SceneObjectPart part) | ||
184 | { | ||
185 | part.SetParent(this); | ||
186 | this.m_parts.Add(part.UUID, part); | ||
187 | } | ||
188 | |||
189 | /// <summary> | ||
151 | /// | 190 | /// |
152 | /// </summary> | 191 | /// </summary> |
153 | /// <param name="part"></param> | 192 | /// <param name="part"></param> |
@@ -619,6 +658,17 @@ namespace OpenSim.Region.Environment.Scenes | |||
619 | return m_scene.RequestAvatarList(); | 658 | return m_scene.RequestAvatarList(); |
620 | } | 659 | } |
621 | 660 | ||
661 | public void SendFullUpdateToClient(IClientAPI remoteClient) | ||
662 | { | ||
663 | lock (this.m_parts) | ||
664 | { | ||
665 | foreach (SceneObjectPart part in this.m_parts.Values) | ||
666 | { | ||
667 | this.SendPartFullUpdate(remoteClient, part); | ||
668 | } | ||
669 | } | ||
670 | } | ||
671 | |||
622 | /// <summary> | 672 | /// <summary> |
623 | /// | 673 | /// |
624 | /// </summary> | 674 | /// </summary> |
diff --git a/OpenSim/Region/Environment/Scenes/SceneObjectPart.cs b/OpenSim/Region/Environment/Scenes/SceneObjectPart.cs index 5e62082..1b373aa 100644 --- a/OpenSim/Region/Environment/Scenes/SceneObjectPart.cs +++ b/OpenSim/Region/Environment/Scenes/SceneObjectPart.cs | |||
@@ -249,6 +249,14 @@ namespace OpenSim.Region.Environment.Scenes | |||
249 | } | 249 | } |
250 | #endregion | 250 | #endregion |
251 | 251 | ||
252 | /// <summary> | ||
253 | /// | ||
254 | /// </summary> | ||
255 | public void SetParent(SceneObjectGroup parent) | ||
256 | { | ||
257 | m_parentGroup = parent; | ||
258 | } | ||
259 | |||
252 | #region Copying | 260 | #region Copying |
253 | /// <summary> | 261 | /// <summary> |
254 | /// | 262 | /// |
diff --git a/OpenSim/Region/Environment/Scenes/ScenePresence.cs b/OpenSim/Region/Environment/Scenes/ScenePresence.cs index b021b44..114623a 100644 --- a/OpenSim/Region/Environment/Scenes/ScenePresence.cs +++ b/OpenSim/Region/Environment/Scenes/ScenePresence.cs | |||
@@ -556,6 +556,7 @@ namespace OpenSim.Region.Environment.Scenes | |||
556 | } | 556 | } |
557 | } | 557 | } |
558 | #endregion | 558 | #endregion |
559 | |||
559 | #region Border Crossing Methods | 560 | #region Border Crossing Methods |
560 | /// <summary> | 561 | /// <summary> |
561 | /// | 562 | /// |
diff --git a/OpenSim/Region/Storage/OpenSim.DataStore.MonoSqlite/MonoSqliteDataStore.cs b/OpenSim/Region/Storage/OpenSim.DataStore.MonoSqlite/MonoSqliteDataStore.cs index 66ca56d..18ff54d 100644 --- a/OpenSim/Region/Storage/OpenSim.DataStore.MonoSqlite/MonoSqliteDataStore.cs +++ b/OpenSim/Region/Storage/OpenSim.DataStore.MonoSqlite/MonoSqliteDataStore.cs | |||
@@ -1,6 +1,7 @@ | |||
1 | using System; | 1 | using System; |
2 | using System.Collections.Generic; | 2 | using System.Collections.Generic; |
3 | using System.Text; | 3 | using System.Text; |
4 | using System.IO; | ||
4 | 5 | ||
5 | using OpenSim.Region.Environment.Scenes; | 6 | using OpenSim.Region.Environment.Scenes; |
6 | using OpenSim.Region.Environment.LandManagement; | 7 | using OpenSim.Region.Environment.LandManagement; |
@@ -8,11 +9,12 @@ using OpenSim.Region.Environment; | |||
8 | using OpenSim.Region.Interfaces; | 9 | using OpenSim.Region.Interfaces; |
9 | using OpenSim.Framework.Console; | 10 | using OpenSim.Framework.Console; |
10 | using OpenSim.Framework.Types; | 11 | using OpenSim.Framework.Types; |
12 | using OpenSim.Framework.Utilities; | ||
11 | using libsecondlife; | 13 | using libsecondlife; |
12 | 14 | ||
13 | using System.Data; | 15 | using System.Data; |
14 | using System.Data.SqlTypes; | 16 | using System.Data.SqlTypes; |
15 | // Yes, this won't compile on MS, need to deal with that later | 17 | |
16 | using Mono.Data.SqliteClient; | 18 | using Mono.Data.SqliteClient; |
17 | 19 | ||
18 | namespace OpenSim.DataStore.MonoSqliteStorage | 20 | namespace OpenSim.DataStore.MonoSqliteStorage |
@@ -47,6 +49,7 @@ namespace OpenSim.DataStore.MonoSqliteStorage | |||
47 | // TODO: see if the linkage actually holds. | 49 | // TODO: see if the linkage actually holds. |
48 | // primDa.FillSchema(ds, SchemaType.Source, "PrimSchema"); | 50 | // primDa.FillSchema(ds, SchemaType.Source, "PrimSchema"); |
49 | primDa.Fill(ds, "prims"); | 51 | primDa.Fill(ds, "prims"); |
52 | shapeDa.Fill(ds, "primshapes"); | ||
50 | ds.AcceptChanges(); | 53 | ds.AcceptChanges(); |
51 | 54 | ||
52 | DataTable prims = ds.Tables["prims"]; | 55 | DataTable prims = ds.Tables["prims"]; |
@@ -54,7 +57,6 @@ namespace OpenSim.DataStore.MonoSqliteStorage | |||
54 | setupPrimCommands(primDa, conn); | 57 | setupPrimCommands(primDa, conn); |
55 | 58 | ||
56 | // shapeDa.FillSchema(ds, SchemaType.Source, "ShapeSchema"); | 59 | // shapeDa.FillSchema(ds, SchemaType.Source, "ShapeSchema"); |
57 | shapeDa.Fill(ds, "primshapes"); | ||
58 | DataTable shapes = ds.Tables["primshapes"]; | 60 | DataTable shapes = ds.Tables["primshapes"]; |
59 | shapes.PrimaryKey = new DataColumn[] { shapes.Columns["UUID"] }; | 61 | shapes.PrimaryKey = new DataColumn[] { shapes.Columns["UUID"] }; |
60 | setupShapeCommands(shapeDa, conn); | 62 | setupShapeCommands(shapeDa, conn); |
@@ -378,6 +380,11 @@ namespace OpenSim.DataStore.MonoSqliteStorage | |||
378 | // text TODO: this isn't right] = but I'm not sure the right | 380 | // text TODO: this isn't right] = but I'm not sure the right |
379 | // way to specify this as a blob atm | 381 | // way to specify this as a blob atm |
380 | // s.TextureEntry = (byte[])row["Texture"]; | 382 | // s.TextureEntry = (byte[])row["Texture"]; |
383 | |||
384 | //following hack will only save the default face texture, any other textures on other faces | ||
385 | //won't be saved or restored. | ||
386 | LLObject.TextureEntry texture = new LLObject.TextureEntry( new LLUUID((string)row["Texture"])); | ||
387 | s.TextureEntry = texture.ToBytes(); | ||
381 | return s; | 388 | return s; |
382 | } | 389 | } |
383 | 390 | ||
@@ -414,7 +421,15 @@ namespace OpenSim.DataStore.MonoSqliteStorage | |||
414 | row["ProfileHollow"] = s.ProfileHollow; | 421 | row["ProfileHollow"] = s.ProfileHollow; |
415 | // text TODO: this isn't right] = but I'm not sure the right | 422 | // text TODO: this isn't right] = but I'm not sure the right |
416 | // way to specify this as a blob atm | 423 | // way to specify this as a blob atm |
417 | row["Texture"] = s.TextureEntry; | 424 | |
425 | // And I couldn't work out how to save binary data either | ||
426 | // seems that the texture colum is being treated as a string in the Datarow | ||
427 | // if you do a .getType() on it, it returns string, while the other columns return correct type | ||
428 | //following hack will only save the default face texture, any other textures on other faces | ||
429 | //won't be saved or restored. | ||
430 | // MW[10-08-07] | ||
431 | LLObject.TextureEntry text = new LLObject.TextureEntry(s.TextureEntry, 0, s.TextureEntry.Length); | ||
432 | row["Texture"] = text.DefaultTexture.TextureID.ToStringHyphenated(); | ||
418 | 433 | ||
419 | } | 434 | } |
420 | 435 | ||
@@ -449,9 +464,10 @@ namespace OpenSim.DataStore.MonoSqliteStorage | |||
449 | addPrim(prim); | 464 | addPrim(prim); |
450 | } | 465 | } |
451 | 466 | ||
452 | MainLog.Instance.Verbose("Attempting to do update...."); | 467 | MainLog.Instance.Verbose("Attempting to do database update...."); |
453 | primDa.Update(ds, "prims"); | 468 | primDa.Update(ds, "prims"); |
454 | MainLog.Instance.Verbose("Dump of prims:", ds.GetXml()); | 469 | shapeDa.Update(ds, "primshapes"); |
470 | // MainLog.Instance.Verbose("Dump of prims:", ds.GetXml()); | ||
455 | } | 471 | } |
456 | 472 | ||
457 | public void RemoveObject(LLUUID obj) | 473 | public void RemoveObject(LLUUID obj) |
@@ -472,15 +488,23 @@ namespace OpenSim.DataStore.MonoSqliteStorage | |||
472 | SceneObjectGroup group = new SceneObjectGroup(); | 488 | SceneObjectGroup group = new SceneObjectGroup(); |
473 | SceneObjectPart prim = buildPrim(primRow); | 489 | SceneObjectPart prim = buildPrim(primRow); |
474 | DataRow shapeRow = shapes.Rows.Find(prim.UUID); | 490 | DataRow shapeRow = shapes.Rows.Find(prim.UUID); |
475 | if (shapeRow != null) { | 491 | if (shapeRow != null) |
492 | { | ||
476 | prim.Shape = buildShape(shapeRow); | 493 | prim.Shape = buildShape(shapeRow); |
477 | } | 494 | } |
478 | group.Children.Add(prim.UUID, prim); | 495 | else |
496 | { | ||
497 | Console.WriteLine("No shape found for prim in storage, so setting default box shape"); | ||
498 | prim.Shape = BoxShape.Default; | ||
499 | } | ||
500 | group.AddPart(prim); | ||
479 | // TODO: there are a couple of known issues to get this to work | 501 | // TODO: there are a couple of known issues to get this to work |
480 | // * While we can add Children, we can't set the root part (or | 502 | // * While we can add Children, we can't set the root part (or |
481 | // or even figure out which should be the root part) | 503 | // or even figure out which should be the root part) |
482 | // * region handle may need to be persisted, it isn't now | 504 | // * region handle may need to be persisted, it isn't now |
483 | // retvals.Add(group); | 505 | group.RootPart = prim; |
506 | |||
507 | retvals.Add(group); | ||
484 | } | 508 | } |
485 | 509 | ||
486 | MainLog.Instance.Verbose("DATASTORE", "Sqlite - LoadObjects found " + prims.Rows.Count + " objects"); | 510 | MainLog.Instance.Verbose("DATASTORE", "Sqlite - LoadObjects found " + prims.Rows.Count + " objects"); |
@@ -517,5 +541,14 @@ namespace OpenSim.DataStore.MonoSqliteStorage | |||
517 | { | 541 | { |
518 | // TODO: DataSet commit | 542 | // TODO: DataSet commit |
519 | } | 543 | } |
544 | |||
545 | private void SaveAssetToFile(string filename, byte[] data) | ||
546 | { | ||
547 | FileStream fs = File.Create(filename); | ||
548 | BinaryWriter bw = new BinaryWriter(fs); | ||
549 | bw.Write(data); | ||
550 | bw.Close(); | ||
551 | fs.Close(); | ||
552 | } | ||
520 | } | 553 | } |
521 | } | 554 | } |