/// <summary> /// Given a revision, read its _attachments dictionary (if any), convert each attachment to a /// AttachmentInternal object, and return a dictionary mapping names->CBL_Attachments. /// </summary> /// <remarks> /// Given a revision, read its _attachments dictionary (if any), convert each attachment to a /// AttachmentInternal object, and return a dictionary mapping names->CBL_Attachments. /// </remarks> /// <exception cref="Couchbase.Lite.CouchbaseLiteException"></exception> internal IDictionary<String, AttachmentInternal> GetAttachmentsFromRevision(RevisionInternal rev) { var revAttachments = rev.GetPropertyForKey("_attachments").AsDictionary<string, object>(); if (revAttachments == null || revAttachments.Count == 0 || rev.IsDeleted()) { return new Dictionary<string, AttachmentInternal>(); } var attachments = new Dictionary<string, AttachmentInternal>(); foreach (var name in revAttachments.Keys) { var attachInfo = revAttachments.Get(name).AsDictionary<string, object>(); var contentType = (string)attachInfo.Get("content_type"); var attachment = new AttachmentInternal(name, contentType); var newContentBase64 = (string)attachInfo.Get("data"); if (newContentBase64 != null) { // If there's inline attachment data, decode and store it: byte[] newContents; try { newContents = StringUtils.ConvertFromUnpaddedBase64String (newContentBase64); } catch (IOException e) { throw new CouchbaseLiteException(e, StatusCode.BadEncoding); } attachment.Length = newContents.Length; var outBlobKey = new BlobKey(); var storedBlob = Attachments.StoreBlob(newContents, outBlobKey); attachment.BlobKey = outBlobKey; if (!storedBlob) { throw new CouchbaseLiteException(StatusCode.AttachmentError); } } else { if (attachInfo.ContainsKey("follows") && ((bool)attachInfo.Get("follows"))) { // "follows" means the uploader provided the attachment in a separate MIME part. // This means it's already been registered in _pendingAttachmentsByDigest; // I just need to look it up by its "digest" property and install it into the store: InstallAttachment(attachment, attachInfo); } else { // This item is just a stub; validate and skip it if (((bool)attachInfo.Get("stub")) == false) { throw new CouchbaseLiteException("Expected this attachment to be a stub", StatusCode. BadAttachment); } var revPos = Convert.ToInt64(attachInfo.Get("revpos")); if (revPos <= 0) { throw new CouchbaseLiteException("Invalid revpos: " + revPos, StatusCode.BadAttachment); } continue; } } // Handle encoded attachment: string encodingStr = (string)attachInfo.Get("encoding"); if (encodingStr != null && encodingStr.Length > 0) { if (Runtime.EqualsIgnoreCase(encodingStr, "gzip")) { attachment.Encoding = AttachmentEncoding.GZIP; } else { throw new CouchbaseLiteException("Unnkown encoding: " + encodingStr, StatusCode.BadEncoding ); } attachment.EncodedLength = attachment.Length; if (attachInfo.ContainsKey("length")) { attachment.Length = attachInfo.GetCast<long>("length"); } } if (attachInfo.ContainsKey("revpos")) { var revpos = Convert.ToInt32(attachInfo.Get("revpos")); attachment.RevPos = revpos; } attachments[name] = attachment; } return attachments; }
internal IDictionary<string, AttachmentInternal> GetAttachmentsFromRevision(RevisionInternal rev) { IDictionary<string, object> revAttachments = (IDictionary<string, object>)rev.GetPropertyForKey ("_attachments"); if (revAttachments == null || revAttachments.Count == 0 || rev.IsDeleted()) { return new Dictionary<string, AttachmentInternal>(); } IDictionary<string, AttachmentInternal> attachments = new Dictionary<string, AttachmentInternal >(); foreach (string name in revAttachments.Keys) { IDictionary<string, object> attachInfo = (IDictionary<string, object>)revAttachments .Get(name); string contentType = (string)attachInfo.Get("content_type"); AttachmentInternal attachment = new AttachmentInternal(name, contentType); string newContentBase64 = (string)attachInfo.Get("data"); if (newContentBase64 != null) { // If there's inline attachment data, decode and store it: byte[] newContents; try { newContents = Base64.Decode(newContentBase64); } catch (IOException e) { throw new CouchbaseLiteException(e, Status.BadEncoding); } attachment.SetLength(newContents.Length); BlobKey outBlobKey = new BlobKey(); bool storedBlob = GetAttachments().StoreBlob(newContents, outBlobKey); attachment.SetBlobKey(outBlobKey); if (!storedBlob) { throw new CouchbaseLiteException(Status.StatusAttachmentError); } } else { if (attachInfo.ContainsKey("follows") && ((bool)attachInfo.Get("follows")) == true) { // "follows" means the uploader provided the attachment in a separate MIME part. // This means it's already been registered in _pendingAttachmentsByDigest; // I just need to look it up by its "digest" property and install it into the store: InstallAttachment(attachment, attachInfo); } else { // This item is just a stub; validate and skip it if (((bool)attachInfo.Get("stub")) == false) { throw new CouchbaseLiteException("Expected this attachment to be a stub", Status. BadAttachment); } int revPos = ((int)attachInfo.Get("revpos")); if (revPos <= 0) { throw new CouchbaseLiteException("Invalid revpos: " + revPos, Status.BadAttachment ); } continue; } } // Handle encoded attachment: string encodingStr = (string)attachInfo.Get("encoding"); if (encodingStr != null && encodingStr.Length > 0) { if (Sharpen.Runtime.EqualsIgnoreCase(encodingStr, "gzip")) { attachment.SetEncoding(AttachmentInternal.AttachmentEncoding.AttachmentEncodingGZIP ); } else { throw new CouchbaseLiteException("Unnkown encoding: " + encodingStr, Status.BadEncoding ); } attachment.SetEncodedLength(attachment.GetLength()); if (attachInfo.ContainsKey("length")) { Number attachmentLength = (Number)attachInfo.Get("length"); attachment.SetLength(attachmentLength); } } if (attachInfo.ContainsKey("revpos")) { attachment.SetRevpos((int)attachInfo.Get("revpos")); } else { attachment.SetRevpos(1); } attachments.Put(name, attachment); } return attachments; }