Re: Decoding FxPlug custom params from FCP-XML
Re: Decoding FxPlug custom params from FCP-XML
- Subject: Re: Decoding FxPlug custom params from FCP-XML
- From: Steve Christensen <email@hidden>
- Date: Tue, 27 Apr 2010 15:26:34 -0700
Since I noticed my name mentioned at the beginning of the thread, I
figured I'd jump in. I only do the encoding side in my case, but did
find that I have to run the parameter value through an archiver twice
before UUEncoding, like this:
// archive the original object into a data blob
NSMutableData* archivedValue = [NSMutableData data];
NSMutableData* archivedData = [NSMutableData data];
NSKeyedArchiver* archiver;
archiver = [[[NSKeyedArchiver alloc]
initForWritingWithMutableData:archivedValue] autorelease];
[archiver encodeObject:parameterValue];
[archiver finishEncoding];
// then archive the data blob
archiver = [[[NSKeyedArchiver alloc]
initForWritingWithMutableData:archivedData] autorelease];
[archiver encodeObject:archivedValue];
[archiver finishEncoding];
return UUEncode(archivedData, false);
I have also appended the UUEncode/UUDecode functions I'm using. At
this point I don't remember the origins of any original sources, but I
had used them to create a version to my liking. I added an extra
parameter to turn on/off the standard feature of adding a line break,
since it is not included when encoding for FCP.
steve
On Apr 27, 2010, at 10:11 AM, Robert Monaghan wrote:
Hi Eryk!
I am about to implement some of this kind of code too. Is there a
boiler-plate code sample for the uuencode/decode that Apple can
point to?
Thanks
Bob
Sent from my iPhone
On Apr 27, 2010, at 9:43, Kristian Harms <email@hidden> wrote:
Thank you Eryk.
It was indeed a length-related issue. The NSKeyedUnarchiver's init
no longer throws.
Regarding the uuencoding, am I right in guessing you have rolled
your own implementation? The reason is that it doesn't seem to have
been encoded using any of the uuencoding implementations I have
found, which insert a newline at regular intervals in the encoded
data. It would be nice if you could document any peculiarities of
your uuencode.
Best regards,
Kristian Harms
Den 2010-04-26 11:02 PM, skrev Eryk Vershen:
Kristian,
From the link you gave it is clear you had Paul's response; that
should be the right thing to do. I agree the uudecode shouldn't
have a problem. The string of bytes that NSKeyedUnarchiver
mentions in the error is the string 'bplist00' (i.e. the start of
a binary plist). I believe keyed archives are stored using plists
these days, so that seems right.
Perhaps you've messed up the length of the data?
It's probably complaining because it's having a failure reading
the plist (qua plist).
-eryk
On Apr 26, 2010, at 12:15 PM, Kristian Harms wrote:
Hi,
I'm doing something similar to what Steve Christensen asked about
in this email to the list, a year ago:
http://lists.apple.com/archives/Pro-apps-dev/2009/Feb/msg00036.html
In brief, I want to grab from the FCP XML the parameter value for
any custom parameters in my FxPlugs and deserialise them.
However, when I come to the point where I instantiate the
NSKeyedUnarchiver with my NSData, which I have uudecoded based on
the string I acquire from the XML, I actually get an Objective-C
exception, of type NSInvalidArgumentException, and with reason:
*** -[NSKeyedUnarchiver initForReadingWithData:]:
incomprehensible archive (0x62, 0x70, 0x6c, 0x69, 0x73, 0x74,
0x30, 0x30)
This happens on the init call itself, and not on the [unarchiver
decodeObject] call that the link above recommends doing next.
I'm stumped as to how to procede. There are no obvious things
I've done that could compromise the data -- the only point where
a character encoding is involved is when I extract the char* from
the NSString holding the uuencoded data, but uuencoded data
should be representable as 7-bit ascii anyway, so choosing utf8,
latin1 or even ascii should work fine there. There are no
character encodings involved after the point where I uudecode.
Version info: Running FCP 7.0.2 and plugin compiled using FxPlug
SDK 1.2.5, on top of OS X 10.5.
//--------------------------------------------------------------------------------
NSInteger UUEncodeStringBufferSize(NSInteger dataLength, bool
hasNewlines)
{
return (dataLength * 4 / 3) + (((dataLength + 44) / 45) * (1 +
(hasNewlines ? 2 : 0))) + 1;
}
//--------------------------------------------------------------------------------
NSInteger UUEncode(const uint8_t* dataBuffer, NSInteger dataLength,
uint8_t* stringBuffer, bool hasNewlines)
{
#define EncodeByte_(ch) ((ch) != 0) ? (((ch) & 0x3f) + ' ') : '`'
NSInteger dataIndex = 0;
NSInteger stringIndex = 0;
NSInteger lineLength;
// break up the data into lines of up to 45 bytes...
while ((lineLength = MIN(dataLength - dataIndex, 45)) > 0)
{
// encode the line length
stringBuffer[stringIndex++] = EncodeByte_(lineLength);
// encode the data bytes for the current line
for (; lineLength > 0; lineLength -= 3)
{
NSUInteger data0 = dataBuffer[dataIndex + 0], data1 = 0, data2 = 0;
// handle buffers that aren't an even multiple of 3 by avoiding
reads off the end
switch (lineLength)
{
default:
data2 = dataBuffer[dataIndex + 2];
case 2:
data1 = dataBuffer[dataIndex + 1];
case 1:
break;
}
stringBuffer[stringIndex + 0] = EncodeByte_((data0 >> 2));
stringBuffer[stringIndex + 1] = EncodeByte_((data0 << 4) | (data1
>> 4));
stringBuffer[stringIndex + 2] = EncodeByte_((data1 << 2) | (data2
>> 6));
stringBuffer[stringIndex + 3] = EncodeByte_((data2 & 0x3f));
dataIndex += 3;
stringIndex += 4;
}
// the uuencode spec puts "\r\n" at the end of each line but there
might be cases where they're not included
if (hasNewlines)
{
stringBuffer[stringIndex + 0] = '\r';
stringBuffer[stringIndex + 1] = '\n';
stringIndex += 2;
}
}
stringBuffer[stringIndex] = '\0';
return stringIndex;
}
//--------------------------------------------------------------------------------
NSString* UUEncode(const NSData* data, bool hasNewlines)
{
if (data != nil)
{
NSInteger dataLength = [data length];
uint8_t stringBuffer[UUEncodeStringBufferSize(dataLength)];
UUEncode(static_cast<const uint8_t*>([data bytes]), dataLength,
stringBuffer, hasNewlines);
return [NSString
stringWithCString:reinterpret_cast<char*>(stringBuffer)
encoding:NSASCIIStringEncoding];
}
return nil;
}
//--------------------------------------------------------------------------------
NSInteger UUDecode(const uint8_t* stringBuffer, NSInteger
stringLength, uint8_t* dataBuffer, bool hasNewlines)
{
#define DecodeByte_(ch) ((ch) - ' ') & 0x3f
NSInteger dataIndex = 0;
NSInteger stringIndex = 0;
while (stringIndex < stringLength)
{
// decode the length of the current line
NSInteger lineLength = DecodeByte_(stringBuffer[stringIndex++]);
// decode the data bytes for the current line
for (; lineLength > 0; lineLength -= 3)
{
NSUInteger string0 = DecodeByte_(stringBuffer[stringIndex + 0]);
NSUInteger string1 = DecodeByte_(stringBuffer[stringIndex + 1]);
NSUInteger string2 = DecodeByte_(stringBuffer[stringIndex + 2]);
NSUInteger string3 = DecodeByte_(stringBuffer[stringIndex + 3]);
dataBuffer[dataIndex++] = (string0 << 2) | (string1 >> 4);
if (lineLength >= 2)
{
dataBuffer[dataIndex++] = (string1 << 4) | (string2 >> 2);
if (lineLength >= 3)
{
dataBuffer[dataIndex++] = (string2 << 6) | (string3 >> 0);
}
}
stringIndex += 4;
}
// the uuencode spec puts "\r\n" at the end of each line but there
might be cases where they're not included
if (hasNewlines)
stringIndex += 2;
}
return dataIndex;
}
//--------------------------------------------------------------------------------
NSData* UUDecode(const NSString* string, bool hasNewlines)
{
if (string != nil)
{
NSInteger stringLength = [string length];
uint8_t stringBuffer[stringLength + 1];
if ([string getCString:(char*)stringBuffer maxLength:(stringLength +
1) encoding:NSASCIIStringEncoding])
{
uint8_t dataBuffer[stringLength];
NSInteger dataLength = UUDecode(stringBuffer, stringLength,
dataBuffer, hasNewlines);
return [NSData dataWithBytes:dataBuffer length:dataLength];
}
}
return nil;
}
_______________________________________________
Do not post admin requests to the list. They will be ignored.
Pro-apps-dev mailing list (email@hidden)
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden