* Add the abilty to load and save iar item nodes where folders have identical names
parent
e57ac6e0bf
commit
b52ac542ad
|
@ -76,7 +76,7 @@ namespace OpenSim
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The file used to load and save an opensim archive if no filename has been specified
|
/// The file used to load and save an opensim archive if no filename has been specified
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected const string DEFAULT_OAR_BACKUP_FILENAME = "scene_oar.tar.gz";
|
protected const string DEFAULT_OAR_BACKUP_FILENAME = "scene.oar";
|
||||||
|
|
||||||
public ConfigSettings ConfigurationSettings
|
public ConfigSettings ConfigurationSettings
|
||||||
{
|
{
|
||||||
|
|
|
@ -50,6 +50,11 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static readonly string ASSET_EXTENSION_SEPARATOR = "_";
|
public static readonly string ASSET_EXTENSION_SEPARATOR = "_";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Used to separate components in an inventory node name
|
||||||
|
/// </summary>
|
||||||
|
public static readonly string INVENTORY_NODE_NAME_COMPONENT_SEPARATOR = "__";
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Extensions used for asset types in the archive
|
/// Extensions used for asset types in the archive
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -85,7 +85,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
|
||||||
|
|
||||||
if (contents.Equals("")) return null;
|
if (contents.Equals("")) return null;
|
||||||
|
|
||||||
reader.ReadStartElement("InventoryObject");
|
reader.ReadStartElement("InventoryItem");
|
||||||
reader.ReadStartElement("Name");
|
reader.ReadStartElement("Name");
|
||||||
item.Name = reader.ReadString();
|
item.Name = reader.ReadString();
|
||||||
reader.ReadEndElement();
|
reader.ReadEndElement();
|
||||||
|
@ -138,10 +138,6 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
|
||||||
reader.ReadStartElement("GroupOwned");
|
reader.ReadStartElement("GroupOwned");
|
||||||
item.GroupOwned = Convert.ToBoolean(reader.ReadString());
|
item.GroupOwned = Convert.ToBoolean(reader.ReadString());
|
||||||
reader.ReadEndElement();
|
reader.ReadEndElement();
|
||||||
//reader.ReadStartElement("ParentFolderID");
|
|
||||||
//item.Folder = UUID.Parse(reader.ReadString());
|
|
||||||
//reader.ReadEndElement();
|
|
||||||
//reader.ReadEndElement();
|
|
||||||
|
|
||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
|
@ -187,7 +183,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
|
||||||
|
|
||||||
if (null == rootDestinationFolder)
|
if (null == rootDestinationFolder)
|
||||||
{
|
{
|
||||||
// TODO: Later on, automatically create this folder if it does not exist
|
// Possibly provide an option later on to automatically create this folder if it does not exist
|
||||||
m_log.ErrorFormat("[INVENTORY ARCHIVER]: Inventory path {0} does not exist", m_invPath);
|
m_log.ErrorFormat("[INVENTORY ARCHIVER]: Inventory path {0} does not exist", m_invPath);
|
||||||
|
|
||||||
return nodesLoaded;
|
return nodesLoaded;
|
||||||
|
@ -195,6 +191,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
|
||||||
|
|
||||||
archive = new TarArchiveReader(m_loadStream);
|
archive = new TarArchiveReader(m_loadStream);
|
||||||
|
|
||||||
|
// In order to load identically named folders, we need to keep track of the folders that we have already
|
||||||
|
// created
|
||||||
|
Dictionary <string, InventoryFolderImpl> foldersCreated = new Dictionary<string, InventoryFolderImpl>();
|
||||||
|
|
||||||
byte[] data;
|
byte[] data;
|
||||||
TarArchiveReader.TarEntryType entryType;
|
TarArchiveReader.TarEntryType entryType;
|
||||||
while ((data = archive.ReadEntry(out filePath, out entryType)) != null)
|
while ((data = archive.ReadEntry(out filePath, out entryType)) != null)
|
||||||
|
@ -222,11 +222,71 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
|
||||||
item.Creator = m_userInfo.UserProfile.ID;
|
item.Creator = m_userInfo.UserProfile.ID;
|
||||||
item.Owner = m_userInfo.UserProfile.ID;
|
item.Owner = m_userInfo.UserProfile.ID;
|
||||||
|
|
||||||
filePath = filePath.Substring(InventoryArchiveConstants.INVENTORY_PATH.Length);
|
string fsPath = filePath.Substring(InventoryArchiveConstants.INVENTORY_PATH.Length);
|
||||||
filePath = filePath.Remove(filePath.LastIndexOf("/"));
|
fsPath = fsPath.Remove(fsPath.LastIndexOf("/") + 1);
|
||||||
|
string originalFsPath = fsPath;
|
||||||
|
|
||||||
m_log.DebugFormat("[INVENTORY ARCHIVER]: Loading to file path {0}", filePath);
|
m_log.DebugFormat("[INVENTORY ARCHIVER]: Loading to folder {0}", fsPath);
|
||||||
|
|
||||||
|
InventoryFolderImpl foundFolder = null;
|
||||||
|
while (null == foundFolder && fsPath.Length > 0)
|
||||||
|
{
|
||||||
|
if (foldersCreated.ContainsKey(fsPath))
|
||||||
|
{
|
||||||
|
m_log.DebugFormat("[INVENTORY ARCHIVER]: Found previously created fs path {0}", fsPath);
|
||||||
|
foundFolder = foldersCreated[fsPath];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Don't include the last slash
|
||||||
|
int penultimateSlashIndex = fsPath.LastIndexOf("/", fsPath.Length - 2);
|
||||||
|
|
||||||
|
if (penultimateSlashIndex >= 0)
|
||||||
|
{
|
||||||
|
fsPath = fsPath.Remove(penultimateSlashIndex + 1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_log.DebugFormat(
|
||||||
|
"[INVENTORY ARCHIVER]: Found no previously created fs path for {0}",
|
||||||
|
originalFsPath);
|
||||||
|
fsPath = string.Empty;
|
||||||
|
foundFolder = rootDestinationFolder;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
string fsPathSectionToCreate = originalFsPath.Substring(fsPath.Length);
|
||||||
|
string[] rawDirsToCreate
|
||||||
|
= fsPathSectionToCreate.Split(new char[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
while (i < rawDirsToCreate.Length)
|
||||||
|
{
|
||||||
|
m_log.DebugFormat("[INVENTORY ARCHIVER]: Creating folder {0}", rawDirsToCreate[i]);
|
||||||
|
|
||||||
|
int identicalNameIdentifierIndex
|
||||||
|
= rawDirsToCreate[i].LastIndexOf(
|
||||||
|
InventoryArchiveConstants.INVENTORY_NODE_NAME_COMPONENT_SEPARATOR);
|
||||||
|
string folderName = rawDirsToCreate[i].Remove(identicalNameIdentifierIndex);
|
||||||
|
|
||||||
|
UUID newFolderId = UUID.Random();
|
||||||
|
m_userInfo.CreateFolder(
|
||||||
|
folderName, newFolderId, (ushort)AssetType.Folder, foundFolder.ID);
|
||||||
|
foundFolder = foundFolder.GetChildFolder(newFolderId);
|
||||||
|
|
||||||
|
// Record that we have now created this folder
|
||||||
|
fsPath += rawDirsToCreate[i] + "/";
|
||||||
|
m_log.DebugFormat("[INVENTORY ARCHIVER]: Recording creation of fs path {0}", fsPath);
|
||||||
|
foldersCreated[fsPath] = foundFolder;
|
||||||
|
|
||||||
|
if (0 == i)
|
||||||
|
nodesLoaded.Add(foundFolder);
|
||||||
|
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
string[] rawFolders = filePath.Split(new char[] { '/' });
|
string[] rawFolders = filePath.Split(new char[] { '/' });
|
||||||
|
|
||||||
// Find the folders that do exist along the path given
|
// Find the folders that do exist along the path given
|
||||||
|
@ -258,14 +318,17 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
|
||||||
rawFolders[i++], newFolderId, (ushort)AssetType.Folder, foundFolder.ID);
|
rawFolders[i++], newFolderId, (ushort)AssetType.Folder, foundFolder.ID);
|
||||||
foundFolder = foundFolder.GetChildFolder(newFolderId);
|
foundFolder = foundFolder.GetChildFolder(newFolderId);
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
// Reset folder ID to the one in which we want to load it
|
// Reset folder ID to the one in which we want to load it
|
||||||
item.Folder = foundFolder.ID;
|
item.Folder = foundFolder.ID;
|
||||||
|
|
||||||
//item.Folder = rootDestinationFolder.ID;
|
|
||||||
|
|
||||||
m_userInfo.AddItem(item);
|
m_userInfo.AddItem(item);
|
||||||
successfulItemRestores++;
|
successfulItemRestores++;
|
||||||
|
|
||||||
|
// If we're loading an item directly into the given destination folder then we need to record
|
||||||
|
// it separately from any loaded root folders
|
||||||
|
if (rootDestinationFolder == foundFolder)
|
||||||
nodesLoaded.Add(item);
|
nodesLoaded.Add(item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -106,14 +106,15 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
|
||||||
m_module.TriggerInventoryArchiveSaved(succeeded, m_userInfo, m_invPath, m_saveStream, reportedException);
|
m_module.TriggerInventoryArchiveSaved(succeeded, m_userInfo, m_invPath, m_saveStream, reportedException);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void saveInvItem(InventoryItemBase inventoryItem, string path)
|
protected void SaveInvItem(InventoryItemBase inventoryItem, string path)
|
||||||
{
|
{
|
||||||
string filename = string.Format("{0}{1}_{2}.xml", path, inventoryItem.Name, inventoryItem.ID);
|
string filename = string.Format("{0}{1}_{2}.xml", path, inventoryItem.Name, inventoryItem.ID);
|
||||||
StringWriter sw = new StringWriter();
|
StringWriter sw = new StringWriter();
|
||||||
XmlTextWriter writer = new XmlTextWriter(sw);
|
XmlTextWriter writer = new XmlTextWriter(sw);
|
||||||
writer.Formatting = Formatting.Indented;
|
writer.Formatting = Formatting.Indented;
|
||||||
|
|
||||||
writer.WriteStartElement("InventoryObject");
|
writer.WriteStartElement("InventoryItem");
|
||||||
|
|
||||||
writer.WriteStartElement("Name");
|
writer.WriteStartElement("Name");
|
||||||
writer.WriteString(inventoryItem.Name);
|
writer.WriteString(inventoryItem.Name);
|
||||||
writer.WriteEndElement();
|
writer.WriteEndElement();
|
||||||
|
@ -168,9 +169,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
|
||||||
writer.WriteStartElement("GroupOwned");
|
writer.WriteStartElement("GroupOwned");
|
||||||
writer.WriteString(inventoryItem.GroupOwned.ToString());
|
writer.WriteString(inventoryItem.GroupOwned.ToString());
|
||||||
writer.WriteEndElement();
|
writer.WriteEndElement();
|
||||||
writer.WriteStartElement("ParentFolderID");
|
|
||||||
writer.WriteString(inventoryItem.Folder.ToString());
|
|
||||||
writer.WriteEndElement();
|
|
||||||
writer.WriteEndElement();
|
writer.WriteEndElement();
|
||||||
|
|
||||||
archive.AddFile(filename, sw.ToString());
|
archive.AddFile(filename, sw.ToString());
|
||||||
|
@ -178,20 +177,48 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
|
||||||
m_assetGatherer.GatherAssetUuids(inventoryItem.AssetID, (AssetType)inventoryItem.AssetType, assetUuids);
|
m_assetGatherer.GatherAssetUuids(inventoryItem.AssetID, (AssetType)inventoryItem.AssetType, assetUuids);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void saveInvDir(InventoryFolderImpl inventoryFolder, string path)
|
protected void SaveInvDir(InventoryFolderImpl inventoryFolder, string path)
|
||||||
{
|
{
|
||||||
List<InventoryFolderImpl> inventories = inventoryFolder.RequestListOfFolderImpls();
|
path +=
|
||||||
|
string.Format(
|
||||||
|
"{0}{1}{2}/",
|
||||||
|
inventoryFolder.Name,
|
||||||
|
InventoryArchiveConstants.INVENTORY_NODE_NAME_COMPONENT_SEPARATOR,
|
||||||
|
inventoryFolder.ID);
|
||||||
|
archive.AddDir(path);
|
||||||
|
|
||||||
|
List<InventoryFolderImpl> childFolders = inventoryFolder.RequestListOfFolderImpls();
|
||||||
List<InventoryItemBase> items = inventoryFolder.RequestListOfItems();
|
List<InventoryItemBase> items = inventoryFolder.RequestListOfItems();
|
||||||
string newPath = path + inventoryFolder.Name + InventoryFolderImpl.PATH_DELIMITER;
|
|
||||||
archive.AddDir(newPath);
|
/*
|
||||||
|
Dictionary identicalFolderNames = new Dictionary<string, int>();
|
||||||
|
|
||||||
foreach (InventoryFolderImpl folder in inventories)
|
foreach (InventoryFolderImpl folder in inventories)
|
||||||
{
|
{
|
||||||
saveInvDir(folder, newPath);
|
|
||||||
|
if (!identicalFolderNames.ContainsKey(folder.Name))
|
||||||
|
identicalFolderNames[folder.Name] = 0;
|
||||||
|
else
|
||||||
|
identicalFolderNames[folder.Name] = identicalFolderNames[folder.Name]++;
|
||||||
|
|
||||||
|
int folderNameNumber = identicalFolderName[folder.Name];
|
||||||
|
|
||||||
|
SaveInvDir(
|
||||||
|
folder,
|
||||||
|
string.Format(
|
||||||
|
"{0}{1}{2}/",
|
||||||
|
path, InventoryArchiveConstants.INVENTORY_NODE_NAME_COMPONENT_SEPARATOR, folderNameNumber));
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
foreach (InventoryFolderImpl childFolder in childFolders)
|
||||||
|
{
|
||||||
|
SaveInvDir(childFolder, path);
|
||||||
|
}
|
||||||
|
|
||||||
foreach (InventoryItemBase item in items)
|
foreach (InventoryItemBase item in items)
|
||||||
{
|
{
|
||||||
saveInvItem(item, newPath);
|
SaveInvItem(item, path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -270,7 +297,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
|
||||||
inventoryItem.Name, inventoryItem.ID, m_invPath);
|
inventoryItem.Name, inventoryItem.ID, m_invPath);
|
||||||
|
|
||||||
//get and export item info
|
//get and export item info
|
||||||
saveInvItem(inventoryItem, m_invPath);
|
SaveInvItem(inventoryItem, m_invPath);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -280,7 +307,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
|
||||||
inventoryFolder.Name, inventoryFolder.ID, m_invPath);
|
inventoryFolder.Name, inventoryFolder.ID, m_invPath);
|
||||||
|
|
||||||
//recurse through all dirs getting dirs and files
|
//recurse through all dirs getting dirs and files
|
||||||
saveInvDir(inventoryFolder, InventoryArchiveConstants.INVENTORY_PATH);
|
SaveInvDir(inventoryFolder, InventoryArchiveConstants.INVENTORY_PATH);
|
||||||
}
|
}
|
||||||
|
|
||||||
new AssetsRequest(assetUuids.Keys, m_module.CommsManager.AssetCache, ReceivedAllAssets).Execute();
|
new AssetsRequest(assetUuids.Keys, m_module.CommsManager.AssetCache, ReceivedAllAssets).Execute();
|
||||||
|
|
|
@ -124,15 +124,19 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests
|
||||||
MemoryStream archiveReadStream = new MemoryStream(archive);
|
MemoryStream archiveReadStream = new MemoryStream(archive);
|
||||||
TarArchiveReader tar = new TarArchiveReader(archiveReadStream);
|
TarArchiveReader tar = new TarArchiveReader(archiveReadStream);
|
||||||
|
|
||||||
|
InventoryFolderImpl objectsFolder = userInfo.RootFolder.FindFolderByPath("Objects");
|
||||||
|
|
||||||
//bool gotControlFile = false;
|
//bool gotControlFile = false;
|
||||||
bool gotObject1File = false;
|
bool gotObject1File = false;
|
||||||
//bool gotObject2File = false;
|
//bool gotObject2File = false;
|
||||||
string expectedObject1FilePath = string.Format(
|
string expectedObject1FilePath = string.Format(
|
||||||
"{0}{1}{2}_{3}.xml",
|
"{0}{1}/{2}_{3}.xml",
|
||||||
InventoryArchiveConstants.INVENTORY_PATH,
|
InventoryArchiveConstants.INVENTORY_PATH,
|
||||||
"Objects/",
|
string.Format(
|
||||||
|
"Objects{0}{1}", InventoryArchiveConstants.INVENTORY_NODE_NAME_COMPONENT_SEPARATOR, objectsFolder.ID),
|
||||||
item1.Name,
|
item1.Name,
|
||||||
item1Id);
|
item1Id);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
string expectedObject2FileName = string.Format(
|
string expectedObject2FileName = string.Format(
|
||||||
"{0}_{1:000}-{2:000}-{3:000}__{4}.xml",
|
"{0}_{1:000}-{2:000}-{3:000}__{4}.xml",
|
||||||
|
@ -146,6 +150,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests
|
||||||
|
|
||||||
while (tar.ReadEntry(out filePath, out tarEntryType) != null)
|
while (tar.ReadEntry(out filePath, out tarEntryType) != null)
|
||||||
{
|
{
|
||||||
|
Console.WriteLine("Got {0}", filePath);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
if (ArchiveConstants.CONTROL_FILE_PATH == filePath)
|
if (ArchiveConstants.CONTROL_FILE_PATH == filePath)
|
||||||
{
|
{
|
||||||
|
|
|
@ -90,21 +90,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver
|
||||||
|
|
||||||
entryType = header.EntryType;
|
entryType = header.EntryType;
|
||||||
filePath = header.FilePath;
|
filePath = header.FilePath;
|
||||||
byte[] data = m_br.ReadBytes(header.FileSize);
|
return ReadData(header.FileSize);
|
||||||
|
|
||||||
//m_log.DebugFormat("[TAR ARCHIVE READER]: filePath {0}, fileSize {1}", filePath, header.FileSize);
|
|
||||||
|
|
||||||
// Read the rest of the empty padding in the 512 byte block
|
|
||||||
if (header.FileSize % 512 != 0)
|
|
||||||
{
|
|
||||||
int paddingLeft = 512 - (header.FileSize % 512);
|
|
||||||
|
|
||||||
//m_log.DebugFormat("[TAR ARCHIVE READER]: Reading {0} padding bytes", paddingLeft);
|
|
||||||
|
|
||||||
m_br.ReadBytes(paddingLeft);
|
|
||||||
}
|
|
||||||
|
|
||||||
return data;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -126,7 +112,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver
|
||||||
if (header[156] == (byte)'L')
|
if (header[156] == (byte)'L')
|
||||||
{
|
{
|
||||||
int longNameLength = ConvertOctalBytesToDecimal(header, 124, 11);
|
int longNameLength = ConvertOctalBytesToDecimal(header, 124, 11);
|
||||||
tarHeader.FilePath = m_asciiEncoding.GetString(m_br.ReadBytes(longNameLength));
|
tarHeader.FilePath = m_asciiEncoding.GetString(ReadData(longNameLength));
|
||||||
m_log.DebugFormat("[TAR ARCHIVE READER]: Got long file name {0}", tarHeader.FilePath);
|
m_log.DebugFormat("[TAR ARCHIVE READER]: Got long file name {0}", tarHeader.FilePath);
|
||||||
header = m_br.ReadBytes(512);
|
header = m_br.ReadBytes(512);
|
||||||
}
|
}
|
||||||
|
@ -134,6 +120,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver
|
||||||
{
|
{
|
||||||
tarHeader.FilePath = m_asciiEncoding.GetString(header, 0, 100);
|
tarHeader.FilePath = m_asciiEncoding.GetString(header, 0, 100);
|
||||||
tarHeader.FilePath = tarHeader.FilePath.Trim(m_nullCharArray);
|
tarHeader.FilePath = tarHeader.FilePath.Trim(m_nullCharArray);
|
||||||
|
m_log.DebugFormat("[TAR ARCHIVE READER]: Got short file name {0}", tarHeader.FilePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
tarHeader.FileSize = ConvertOctalBytesToDecimal(header, 124, 11);
|
tarHeader.FileSize = ConvertOctalBytesToDecimal(header, 124, 11);
|
||||||
|
@ -172,6 +159,30 @@ namespace OpenSim.Region.CoreModules.World.Archiver
|
||||||
return tarHeader;
|
return tarHeader;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Read data following a header
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="fileSize"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
protected byte[] ReadData(int fileSize)
|
||||||
|
{
|
||||||
|
byte[] data = m_br.ReadBytes(fileSize);
|
||||||
|
|
||||||
|
m_log.DebugFormat("[TAR ARCHIVE READER]: fileSize {0}", fileSize);
|
||||||
|
|
||||||
|
// Read the rest of the empty padding in the 512 byte block
|
||||||
|
if (fileSize % 512 != 0)
|
||||||
|
{
|
||||||
|
int paddingLeft = 512 - (fileSize % 512);
|
||||||
|
|
||||||
|
m_log.DebugFormat("[TAR ARCHIVE READER]: Reading {0} padding bytes", paddingLeft);
|
||||||
|
|
||||||
|
m_br.ReadBytes(paddingLeft);
|
||||||
|
}
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
public void Close()
|
public void Close()
|
||||||
{
|
{
|
||||||
m_br.Close();
|
m_br.Close();
|
||||||
|
|
Loading…
Reference in New Issue