views:

65

answers:

2

I am trying to send a small image along with some XML information to App Engine from my iPhone app. I am having trouble with the image somewhere along the path. There is no error given and data is being transfered into a Blob entry in Datastore Viewer but the blob files on App Engine do not appear in Blob Viewer. I have a suspicion that the image is being messed up in one of my transforms in App Engine, or is not being stored as the correct type in App Engine. What do you think?

On the iPhone, here is the relevant section that encodes the image (using a standard base64Encoding function) and adds it to a GDataXMLElement, which then gets added to a GDataXMLDoc and sent with ASIHTTPRequest:

NSString *dataString = [self.data base64Encoding];
GDataXMLElement *tempXMLElement = [GDataXMLElement elementWithName:@"data" stringValue: dataString];
[imageElement addChild: tempXMLElement];

the ASIHTTPRequest part:

ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL: url]; 
[request setDelegate: self];
[request addRequestHeader:@"User-Agent" value: [NSString stringWithFormat:@"MyApp:%@", version]]; 
[request addRequestHeader:@"Content-Type" value:@"text/xml"]; 
[request setShouldStreamPostDataFromDisk:YES]; 
[request appendPostDataFromFile: path]; 
[request start]; 

On App Engine in Python (most likely where a problem lies):

image_data_xml_element = image_xml_node.getElementsByTagName("data")[0]
image_data_base64_unicode = image_data_xml_element.firstChild.data
image_data_base64_ascii = image_data_unicode.encode("utf8")
image_data_string = binascii.a2b_base64(image_data_base64_ascii)
new_image.data = db.Blob(image_data_string) 

Additionally I have tried:

image_data_xml_element = image_xml_node.getElementsByTagName("data")[0]
image_data_base64_unicode = image_data_xml_element.firstChild.data
image_data_string = base64.b64decode(image_data_base64_unicode)
new_image.data = db.Blob(image_data_string) 

Edit: For completeness, here is the objective-c base64 library I am using - it doesn't look like what I expected:

static const char encodingTable[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
- (NSString *)base64Encoding;{
    if ([self length] == 0)
        return @"";

    char *characters = malloc((([self length] + 2) / 3) * 4);
    if (characters == NULL)
        return nil;
    NSUInteger length = 0;
    NSUInteger i = 0;
    while (i < [self length]){
        char buffer[3] = {0,0,0};
        short bufferLength = 0;
        while (bufferLength < 3 && i < [self length])
            buffer[bufferLength++] = ((char *)[self bytes])[i++];

        //  Encode the bytes in the buffer to four characters, including padding "=" characters if necessary.
        characters[length++] = encodingTable[(buffer[0] & 0xFC) >> 2];
        characters[length++] = encodingTable[((buffer[0] & 0x03) << 4) | ((buffer[1] & 0xF0) >> 4)];
        if (bufferLength > 1)
            characters[length++] = encodingTable[((buffer[1] & 0x0F) << 2) | ((buffer[2] & 0xC0) >> 6)];
        else characters[length++] = '=';
        if (bufferLength > 2)
            characters[length++] = encodingTable[buffer[2] & 0x3F];
        else characters[length++] = '=';    
    }

    return [[[NSString alloc] initWithBytesNoCopy:characters length:length encoding:NSASCIIStringEncoding freeWhenDone:YES] autorelease];
}
+2  A: 

The Blob Viewer displays files uploaded with the Blobstore API, not those added to regular datastore entities in Blob Properties.

Wooble
Thanks, makes sense. I won't use their absence from Blob Viewer as feedback now.
Ryan Bavetta
A: 

What I ended up doing was sending the image to the Blobstore prior to sending the XML then, if successful, send the XML including a key to the blobstore image data. I did not realize initially that Blobstore was a different entity than Blobs stored in the Datastore.

Thanks

Ryan Bavetta