public byte[] ReadBlob(long pageIndex) { //Create buffer from the length specified in the first page byte[] buffer = new byte[pages[(int)pageIndex].total_blob_length]; //Begin reading pages long nextPageIndex = pageIndex; int currentPageIndex = 0; //Read index for writing to our buffer //Loop through this page and it's decendants while (nextPageIndex != -1) { //Get page DatabasePage page = pages[(int)nextPageIndex]; //Get index of the next page nextPageIndex = page.next_page_index; //Calculate read parameters int readOffset = currentPageIndex * pageContentSize; int readLength = Math.Min(pageContentSize, buffer.Length - readOffset); //Jump to and read file.Position = GetPageFileOffset(page.index) + PAGE_HEADER_SIZE; file.Read(buffer, readOffset, readLength); currentPageIndex++; } return(buffer); }
private DatabasePage CreateDatabasePage() { //Jump to new page location file.Position = GetPageFileOffset(pages.Count); //Write placeholder data for (int i = 0; i < pageTotalSize; i++) { file.WriteByte(0x00); } //Add page info DatabasePage pageInfo = new DatabasePage { index = pages.Count, type = PAGE_TYPE_ORPHAN, modified_utc = GetCurrentUtcEpoch(), next_page_index = -1 }; pages.Add(pageInfo); orphanedPages.Add(pageInfo); //Jump to counter and update file.Position = 16; WriteInt64ToStream(pages.Count); //Jump to new page location file.Position = GetPageFileOffset(pageInfo.index); return(pageInfo); }
public void ReadHeader() { //Jump to beginning file.Position = 0; //Read file signature if (ReadInt32FromStream() != FILE_SIN) { throw new Exception("This is not a Delta Web Map Content file."); } //Read version if (ReadInt32FromStream() != 1) { throw new Exception("Unknown file version."); } //Read header data pageContentSize = ReadInt32FromStream(); modifiedUtc = ReadInt32FromStream(); long pageCount = ReadInt64FromStream(); //Read data for each page pages = new List <DatabasePage>(); for (long i = 0; i < pageCount; i += 1) { //Jump to page file.Position = GetPageFileOffset(i); //Read int pageType = ReadInt32FromStream(); int pageModifiedUtc = ReadInt32FromStream(); int pageContentSize = ReadInt32FromStream(); int pageReserved = ReadInt32FromStream(); long pageNextIndex = ReadInt64FromStream(); //Make var page = new DatabasePage { index = i, type = pageType, modified_utc = pageModifiedUtc, total_blob_length = pageContentSize, flags = pageReserved, next_page_index = pageNextIndex }; //Add pages.Add(page); //If this is an orphaned page, set it as so if (pageTotalSize == PAGE_TYPE_ORPHAN) { orphanedPages.Add(page); } } }
public long WriteNewBlob(int objectType, byte[] payload) { //Calculate number of chunks we need int objectPageCount = (payload.Length / pageContentSize) + 1; //Find orphaned pages. These are pages that are unused DatabasePage[] objectPages = new DatabasePage[objectPageCount]; int objectPageIndex = 0; foreach (var p in orphanedPages) { if (p.type == PAGE_TYPE_ORPHAN) { objectPages[objectPageIndex] = p; objectPageIndex++; if (objectPageIndex == objectPageCount) { break; } } } //If we need additional pages, create them while (objectPageIndex < objectPageCount) { objectPages[objectPageIndex] = CreateDatabasePage(); objectPageIndex++; } //Now write content to each page for (int i = 0; i < objectPageCount; i += 1) { //Find the index of the next page long nextPageIndex; if (i + 1 == objectPageCount) { nextPageIndex = -1; } else { nextPageIndex = objectPages[i + 1].index; } //Make flags int flags = 0; if (i != 0) //If this is not the first one, set the continuation flag to true { flags |= 1 << DatabasePage.FLAG_CONTINUATION; } //Write content UpdateDatabasePage(objectPages[i], objectType, nextPageIndex, payload, i, flags); } return(objectPages[0].index); }
private void UpdateDatabasePage(DatabasePage page, int pageType, long nextPageIndex, byte[] buffer, int pageIndex, int flags) { //Update metadata UpdateDatabasePage(page, pageType, nextPageIndex, buffer.Length, flags); //Calculate where to read from the buffer int bufferReadOffset = pageIndex * pageContentSize; int bufferReadLength = Math.Min(pageContentSize, buffer.Length - bufferReadOffset); //Copy content file.Write(buffer, bufferReadOffset, bufferReadLength); }
public void DeleteBlob(long pageIndex) { //Get first page long nextPageIndex = pageIndex; //Loop through this page and it's decendants while (nextPageIndex != -1) { //Get page DatabasePage page = pages[(int)nextPageIndex]; //Get index of the next page before it's removed nextPageIndex = page.next_page_index; //Update the page selected UpdateDatabasePage(page, PAGE_TYPE_ORPHAN, -1, 0, 0x00); } }
private void UpdateDatabasePage(DatabasePage page, int pageType, long nextPageIndex, int totalBlobLength, int flags) { //Get current last modified time int modifiedUtc = GetCurrentUtcEpoch(); //Jump to file header to write the current UTC time file.Position = 12; WriteInt32ToStream(modifiedUtc); //Jump to the header for this page file.Position = GetPageFileOffset(page.index); //Update type WriteInt32ToStream(pageType); page.type = pageType; //Update UTC time WriteInt32ToStream(modifiedUtc); page.modified_utc = modifiedUtc; //Update blob length WriteInt32ToStream(totalBlobLength); page.total_blob_length = totalBlobLength; //Update flags WriteInt32ToStream(flags); page.flags = flags; //Update next page index WriteInt64ToStream(nextPageIndex); page.next_page_index = nextPageIndex; //Add/remove to orphaned pages if needed bool isInOrphaned = orphanedPages.Contains(page); if (pageType == PAGE_TYPE_ORPHAN && !isInOrphaned) { orphanedPages.Add(page); } if (pageTotalSize != PAGE_TYPE_ORPHAN && isInOrphaned) { orphanedPages.Remove(page); } }