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];
}