Re: Difficulties with recovering NSAttributedString attachments from saved RTFD

2019-12-01 Thread Martin Wierschin via Cocoa-dev
> let savedRtfd = originalString.rtfd(from:NSRange(0.. recoveredAttachment.contents is still nil.


Your core problem is RTF/RTFD encoding. There's simply no guarantee those 
formats will preserve everything that's supported by the Apple text system, 
including NSTextAttachment data. Even features that are officially supported by 
RTF/RTFD might not be roundtripped if Apple didn't add support for it. 

A quick example: images in RTF data are discarded when loaded by 
NSAttributedString. That's despite the fact that images are completely 
supported by the RTF spec, NSTextAttachment, and even Apple's RTFD. It's just 
that Apple didn't bother with RTF.

Maybe there's another data format where Apple better handles attachment 
serialization? I don't know. But if I needed to reliably serialize all kinds of 
attachments I'd probably do it myself to be sure, since I don't recall seeing 
it mentioned explicitly.

~Martin Wierschin


___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com


Re: Difficulties with recovering NSAttributedString attachments from saved RTFD

2019-11-29 Thread Gary L. Wade via Cocoa-dev
While it may seem redundant, what if you specify the document type in the 
document attributes?  Also, you’re storing UTF8 data in the contents but 
specifying plain text; what if you specify it as UTF8 plain text?

Also, the source code for TextEdit is available somewhere; maybe try seeing 
what it’s doing.
--
Gary L. Wade
http://www.garywade.com/ 

> On Nov 27, 2019, at 11:35 AM, Gary L. Wade via Cocoa-dev 
>  wrote:
> 
> You want to use a file wrapper rather than data and specify the document type 
> in the attributes as RTFD.
> --
> Gary L. Wade
> http://www.garywade.com/ 
> 
>> On Nov 27, 2019, at 10:18 AM, Jeff Younker via Cocoa-dev 
>>  wrote:
>> 
>> I am having some difficulty with saving NSAttributedStrings as RTFD and
>> then recovering
>> them with attachments intact.  I generate a string containing an attachment
>> and turn that into
>> RTFD. When I turn that RTFD back into an NSAttributedString, I get the
>> .string back, and I
>> get an attachment, but the attachment's .contents is empty.
>> 
>> This is the smallest example I can come up with:
>> 
>> func testSaveAndRestoreAttachment() {
>> // Build up the string "deadbeefdeadbeef"
>> let originalContent = "foobar".data(using: .utf8)
>> let originalAttachment = NSTextAttachment(
>>   data: originalContent, ofType: "public.plain-text")
>> let originalString = NSMutableAttributedString(string: "deadbeef")
>> originalString.append(NSMutableAttributedString(attachment:
>> originalAttachment))
>> originalString.append(NSMutableAttributedString(string: "deadbeef")
>> 
>> // save string as RTFD (note that generated RTFD contains "foobar"
>> inside.)
>> let savedRtfd = originalString.rtfd(from:
>> NSRange(0..> 
>> // Recover string
>> let recoveredString = NSAttributedString(rtfd: savedRtfd,
>> documentAttributes: nil)!
>> // Implementation of attachments() can be found below.
>> let recoveredAttachments = attachments(from: recoveredString)
>> // There *is* an attachment!
>> let recoveredAttachment = recoveredAttachments[0]
>> // Want to get Data("foobar") but actually get nil :(
>> XCTAssertNotNil(recoveredAttachment.contents)
>> }
>> 
>> When I print out the RTFD I can see the document includes the attachment
>> "foobar".
>> 
>> I'm assuming that I need to pass some additional information when I
>> call NSAttributedString(rtfd:,
>> documentAttributes:)
>> but I'm at a loss here.
>> 
>> Am I missing something simple? Perhaps a magical setting to be passed in
>> documentAttributes?
>> 
>> -jeff
>> 
>> 
>> 
>> ** This is the attachments() function used above:
>> 
>> func attachments(from s: NSAttributedString) -> Array {
>>   var attachments: Array = []
>>   s.enumerateAttribute(.attachment, in: NSRange(0..>   value, range, stop in
>>   guard let a = value else {
>>  return
>>   }
>>   attachments.append(a as! NSTextAttachment)
>>   }
>>   return attachments
>> }
> 

___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com


Re: Difficulties with recovering NSAttributedString attachments from saved RTFD

2019-11-27 Thread Jeff Younker via Cocoa-dev
So, I replaced...

*let* recoveredString = NSMutableAttributedString(rtfd: savedRtfd,
documentAttributes: *nil*)!
...with...

*let* fw = FileWrapper(serializedRepresentation: savedRtfd)!

*let* filePath = URL(fileURLWithPath: "/tmp/bar")

*do* {

*try* fw.write(

to: filePath,

options: [FileWrapper.WritingOptions.atomic],

originalContentsURL: *nil*)

} *catch* {

print("Error info: \(error)")

XCTFail()

}

*let* recoveredString = NSMutableAttributedString(rtfdFileWrapper:
fw, documentAttributes: *nil*)!


The RTFD gets unpacked into /tmp/bar/..., and I can see the file with the
appropriate contents:


> cat /tmp/bar/Attachment.txt

foobar

>


*Bad News*

recoveredAttachment.contents is still nil.


*Good News*

Going through the attachment's file wrapper works:


   let recoveredContents = recoveredAttachment.fileWrapper?.
regularFileContents

   XCTAssertEqual(String(data: recoveredContents!, encoding: .utf8),
"foobar")


*Even Better News*

Going through the attachment's file wrapper works when using the original
code. (!!)

*Conclusion*

NSTextAttachment.contents seems to be broken, deeply misleading, or (most
likely) some other magic is required to get it to read its contents.


Thank you for pointing me in the right direction Gary.


-jeff

On Wed, Nov 27, 2019 at 8:35 PM Gary L. Wade 
wrote:

> You want to use a file wrapper rather than data and specify the document
> type in the attributes as RTFD.
> --
> Gary L. Wade
> http://www.garywade.com/
>
> On Nov 27, 2019, at 10:18 AM, Jeff Younker via Cocoa-dev <
> cocoa-dev@lists.apple.com> wrote:
>
> I am having some difficulty with saving NSAttributedStrings as RTFD and
> then recovering
> them with attachments intact.  I generate a string containing an attachment
> and turn that into
> RTFD. When I turn that RTFD back into an NSAttributedString, I get the
> .string back, and I
> get an attachment, but the attachment's .contents is empty.
>
> This is the smallest example I can come up with:
>
> func testSaveAndRestoreAttachment() {
>  // Build up the string "deadbeefdeadbeef"
>  let originalContent = "foobar".data(using: .utf8)
>  let originalAttachment = NSTextAttachment(
>data: originalContent, ofType: "public.plain-text")
>  let originalString = NSMutableAttributedString(string: "deadbeef")
>  originalString.append(NSMutableAttributedString(attachment:
> originalAttachment))
>  originalString.append(NSMutableAttributedString(string: "deadbeef")
>
>  // save string as RTFD (note that generated RTFD contains "foobar"
> inside.)
>  let savedRtfd = originalString.rtfd(from:
> NSRange(0..
>  // Recover string
>  let recoveredString = NSAttributedString(rtfd: savedRtfd,
> documentAttributes: nil)!
>  // Implementation of attachments() can be found below.
>  let recoveredAttachments = attachments(from: recoveredString)
>  // There *is* an attachment!
>  let recoveredAttachment = recoveredAttachments[0]
>  // Want to get Data("foobar") but actually get nil :(
>  XCTAssertNotNil(recoveredAttachment.contents)
> }
>
> When I print out the RTFD I can see the document includes the attachment
> "foobar".
>
> I'm assuming that I need to pass some additional information when I
> call NSAttributedString(rtfd:,
> documentAttributes:)
> but I'm at a loss here.
>
> Am I missing something simple? Perhaps a magical setting to be passed in
> documentAttributes?
>
> -jeff
>
>
>
> ** This is the attachments() function used above:
>
> func attachments(from s: NSAttributedString) -> Array {
>var attachments: Array = []
>s.enumerateAttribute(.attachment, in: NSRange(0..value, range, stop in
>guard let a = value else {
>   return
>}
>attachments.append(a as! NSTextAttachment)
>}
>return attachments
> }
>
>
>
___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com


Re: Difficulties with recovering NSAttributedString attachments from saved RTFD

2019-11-27 Thread Gary L. Wade via Cocoa-dev
You want to use a file wrapper rather than data and specify the document type 
in the attributes as RTFD.
--
Gary L. Wade
http://www.garywade.com/ 

> On Nov 27, 2019, at 10:18 AM, Jeff Younker via Cocoa-dev 
>  wrote:
> 
> I am having some difficulty with saving NSAttributedStrings as RTFD and
> then recovering
> them with attachments intact.  I generate a string containing an attachment
> and turn that into
> RTFD. When I turn that RTFD back into an NSAttributedString, I get the
> .string back, and I
> get an attachment, but the attachment's .contents is empty.
> 
> This is the smallest example I can come up with:
> 
> func testSaveAndRestoreAttachment() {
>  // Build up the string "deadbeefdeadbeef"
>  let originalContent = "foobar".data(using: .utf8)
>  let originalAttachment = NSTextAttachment(
>data: originalContent, ofType: "public.plain-text")
>  let originalString = NSMutableAttributedString(string: "deadbeef")
>  originalString.append(NSMutableAttributedString(attachment:
> originalAttachment))
>  originalString.append(NSMutableAttributedString(string: "deadbeef")
> 
>  // save string as RTFD (note that generated RTFD contains "foobar"
> inside.)
>  let savedRtfd = originalString.rtfd(from:
> NSRange(0.. 
>  // Recover string
>  let recoveredString = NSAttributedString(rtfd: savedRtfd,
> documentAttributes: nil)!
>  // Implementation of attachments() can be found below.
>  let recoveredAttachments = attachments(from: recoveredString)
>  // There *is* an attachment!
>  let recoveredAttachment = recoveredAttachments[0]
>  // Want to get Data("foobar") but actually get nil :(
>  XCTAssertNotNil(recoveredAttachment.contents)
> }
> 
> When I print out the RTFD I can see the document includes the attachment
> "foobar".
> 
> I'm assuming that I need to pass some additional information when I
> call NSAttributedString(rtfd:,
> documentAttributes:)
> but I'm at a loss here.
> 
> Am I missing something simple? Perhaps a magical setting to be passed in
> documentAttributes?
> 
> -jeff
> 
> 
> 
> ** This is the attachments() function used above:
> 
> func attachments(from s: NSAttributedString) -> Array {
>var attachments: Array = []
>s.enumerateAttribute(.attachment, in: NSRange(0..value, range, stop in
>guard let a = value else {
>   return
>}
>attachments.append(a as! NSTextAttachment)
>}
>return attachments
> }

___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com