Hi I am new to blackberry 10 platform. I am developing an application to unzip files compressed using GZip. I am looking for extracting folder that compressed with GZip.
I have the same problem and I solved this problem by adding the following method
gUncompress(const QByteArray &data)
{
qDebug()<<"Reached Guncompress";
qDebug()<<"size="<<data.size();
if (data.size() <= 4) {
qWarning("gUncompress: Input data is truncated");
return QByteArray();
}
QByteArray result;
int ret;
z_stream strm;
static const int CHUNK_SIZE = 1024;
char out[CHUNK_SIZE];
/* allocate inflate state */
strm.zalloc = Z_NULL;
strm.zfree = Z_NULL;
strm.opaque = Z_NULL;
strm.avail_in = data.size();
strm.next_in = (Bytef*)(data.data());
ret = inflateInit2(&strm, 15 + 32); // gzip decoding
if (ret != Z_OK)
return QByteArray();
// run inflate()
do {
strm.avail_out = CHUNK_SIZE;
strm.next_out = (Bytef*)(out);
ret = inflate(&strm, Z_NO_FLUSH);
Q_ASSERT(ret != Z_STREAM_ERROR); // state not clobbered
switch (ret) {
case Z_NEED_DICT:
ret = Z_DATA_ERROR; // and fall through
case Z_DATA_ERROR:
case Z_MEM_ERROR:
(void)inflateEnd(&strm);
return QByteArray();
}
result.append(out, CHUNK_SIZE - strm.avail_out);
} while (strm.avail_out == 0);
// clean up and return
inflateEnd(&strm);
return result;
}
I think this will solve your problem
Related
I want to stream JPEG images or motion-JPEG file through live 555. But the problem is that in live 555 implementation for Jpegs is not available. Anyone can help ??
You can find a implementation that was posted to the devel mailing list http://lists.live555.com/pipermail/live-devel/2012-February/014672.html.
The code and a sample is available but this modification was rejected by live555 maintainer.
First we need to implement an MJPEGVideoSource than can feed a JPEGVideoRTPSink.
#include "JPEGVideoSource.hh"
class MJPEGVideoSource : public JPEGVideoSource
{
public:
static MJPEGVideoSource* createNew (UsageEnvironment& env, FramedSource* source)
{
return new MJPEGVideoSource(env,source);
}
virtual void doGetNextFrame()
{
if (m_inputSource)
m_inputSource->getNextFrame(fTo, fMaxSize, afterGettingFrameSub, this, FramedSource::handleClosure, this);
}
virtual void doStopGettingFrames()
{
FramedSource::doStopGettingFrames();
if (m_inputSource)
m_inputSource->stopGettingFrames();
}
static void afterGettingFrameSub(void* clientData, unsigned frameSize,unsigned numTruncatedBytes,struct timeval presentationTime,unsigned durationInMicroseconds)
{
MJPEGVideoSource* source = (MJPEGVideoSource*)clientData;
source->afterGettingFrame(frameSize, numTruncatedBytes, presentationTime, durationInMicroseconds);
}
void afterGettingFrame(unsigned frameSize,unsigned numTruncatedBytes,struct timeval presentationTime,unsigned durationInMicroseconds)
{
int headerSize = 0;
bool headerOk = false;
fFrameSize = 0;
for (unsigned int i = 0; i < frameSize ; ++i)
{
// SOF
if ( (i+8) < frameSize && fTo[i] == 0xFF && fTo[i+1] == 0xC0 )
{
m_height = (fTo[i+5]<<5)|(fTo[i+6]>>3);
m_width = (fTo[i+7]<<5)|(fTo[i+8]>>3);
}
// DQT
if ( (i+5+64) < frameSize && fTo[i] == 0xFF && fTo[i+1] == 0xDB)
{
if (fTo[i+4] ==0)
{
memcpy(m_qTable, fTo + i + 5, 64);
m_qTable0Init = true;
}
else if (fTo[i+4] ==1)
{
memcpy(m_qTable + 64, fTo + i + 5, 64);
m_qTable1Init = true;
}
}
// End of header
if ( (i+1) < frameSize && fTo[i] == 0x3F && fTo[i+1] == 0x00 )
{
headerOk = true;
headerSize = i+2;
break;
}
}
if (headerOk)
{
fFrameSize = frameSize - headerSize;
memmove( fTo, fTo + headerSize, fFrameSize );
}
fNumTruncatedBytes = numTruncatedBytes;
fPresentationTime = presentationTime;
fDurationInMicroseconds = durationInMicroseconds;
afterGetting(this);
}
virtual u_int8_t type() { return 1; };
virtual u_int8_t qFactor() { return 128; };
virtual u_int8_t width() { return m_width; };
virtual u_int8_t height() { return m_height; };
u_int8_t const* quantizationTables( u_int8_t& precision, u_int16_t& length )
{
length = 0;
precision = 0;
if ( m_qTable0Init && m_qTable1Init )
{
precision = 8;
length = sizeof(m_qTable);
}
return m_qTable;
}
protected:
MJPEGVideoSource(UsageEnvironment& env, FramedSource* source) : JPEGVideoSource(env),
m_inputSource(source),
m_width(0),
m_height(0),
m_qTable0Init(false),
m_qTable1Init(false)
{
memset(&m_qTable,0,sizeof(m_qTable));
}
virtual ~MJPEGVideoSource()
{
Medium::close(m_inputSource);
}
protected:
FramedSource* m_inputSource;
u_int8_t m_width;
u_int8_t m_height;
u_int8_t m_qTable[128];
bool m_qTable0Init;
bool m_qTable1Init;
};
Next we can use it as a video source in order to build a simple RTSP server:
#include "liveMedia.hh"
#include "BasicUsageEnvironment.hh"
#include "GroupsockHelper.hh"
#include "MJPEGVideoSource.hh"
char const* inputFileName = "test.mjpeg";
int main(int argc, char** argv) {
// Begin by setting up our usage environment:
TaskScheduler* scheduler = BasicTaskScheduler::createNew();
UsageEnvironment* env = BasicUsageEnvironment::createNew(*scheduler);
// Create 'groupsocks' for RTP and RTCP:
struct in_addr destinationAddress;
destinationAddress.s_addr = chooseRandomIPv4SSMAddress(*env);
const unsigned short rtpPortNum = 18888;
const unsigned short rtcpPortNum = rtpPortNum+1;
const unsigned char ttl = 255;
const Port rtpPort(rtpPortNum);
const Port rtcpPort(rtcpPortNum);
Groupsock rtpGroupsock(*env, destinationAddress, rtpPort, ttl);
rtpGroupsock.multicastSendOnly(); // we're a SSM source
Groupsock rtcpGroupsock(*env, destinationAddress, rtcpPort, ttl);
rtcpGroupsock.multicastSendOnly(); // we're a SSM source
// Create a 'JPEG Video RTP' sink from the RTP 'groupsock':
RTPSink* videoSink = JPEGVideoRTPSink::createNew(*env, &rtpGroupsock);
// Create (and start) a 'RTCP instance' for this RTP sink:
const unsigned estimatedSessionBandwidth = 5000; // in kbps; for RTCP b/w share
const unsigned maxCNAMElen = 100;
unsigned char CNAME[maxCNAMElen+1];
gethostname((char*)CNAME, maxCNAMElen);
CNAME[maxCNAMElen] = '\0'; // just in case
RTCPInstance* rtcp = RTCPInstance::createNew(*env, &rtcpGroupsock,
estimatedSessionBandwidth, CNAME,
videoSink, NULL /* we're a server */,
True /* we're a SSM source */);
// Note: This starts RTCP running automatically
RTSPServer* rtspServer = RTSPServer::createNew(*env, 8554);
if (rtspServer == NULL) {
*env << "Failed to create RTSP server: " << env->getResultMsg() << "\n";
exit(1);
}
ServerMediaSession* sms = ServerMediaSession::createNew(*env, "testStream", inputFileName,"Session streamed by \"testMJPEGVideoStreamer\"",
True /*SSM*/);
sms->addSubsession(PassiveServerMediaSubsession::createNew(*videoSink, rtcp));
rtspServer->addServerMediaSession(sms);
char* url = rtspServer->rtspURL(sms);
*env << "Play this stream using the URL \"" << url << "\"\n";
delete[] url;
// Start the streaming:
*env << "Beginning streaming...\n";
// Open the input file as a 'byte-stream file source':
ByteStreamFileSource* fileSource = ByteStreamFileSource::createNew(*env, inputFileName);
if (fileSource == NULL) {
*env << "Unable to open file \"" << inputFileName
<< "\" as a byte-stream file source\n";
exit(1);
}
// Create the MJPEG video source:
MJPEGVideoSource* videoSource = MJPEGVideoSource::createNew(*env, fileSource);
// Finally, start playing:
*env << "Beginning to read from file...\n";
videoSink->startPlaying(*videoSource, NULL, NULL);
env->taskScheduler().doEventLoop();
return 0;
}
Hope you have done it but if not-
see this Jpeg Streaming using live555
This is doing the same thing as you have asked to stream the images/Jpegs.
For MJpegs you'll have to do the same process.
I need to encode and decode BER data. .NET has the class System.DirectoryServices.Protocols.BerConverter
The static method requires me to enter a string in the first parameter as shown below
byte[] oid = { 0x30, 0xD, 0x6, 0x9, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0xD, 0x1, 0x1, 0x1, 0x5, 0x0 }; // Object ID for RSA
var result2 = System.DirectoryServices.Protocols.BerConverter.Decoding("?what goes here?", oid);
BER encoding is used in LDAP, Certificates, and is commonplace in many other formats.
I'll be happy with information telling me how to Encode or Decode on this class. There is nothing on Stack Overflow or the first few pages of Google (or Bing) regarding this.
Question
How do I convert the byte array above to the corresponding OID using BER decoding?
How can I parse (or attempt to parse) SubjectPublicKeyInfo ASN.1 data in DER or BER format?
It seems the DER encoding\decoding classes are internal to the .NET framework. If so, where are they? (I'd like to ask connect.microsoft.com to make these members public)
How do I convert the byte array above to the corresponding OID using BER decoding?
After you have extracted the OID byte array, you can convert it to an OID string using OidByteArrayToString(). I have included the code below, since I couldn't find a similar function in the .NET libraries.
How can I parse (or attempt to parse) SubjectPublicKeyInfo ASN.1 data in DER or BER format?
I was not able to find a TLV parser in the .NET SDK either. Below is an implementation of a BER TLV parser, BerTlv. Since DER is a subset of BER, parsing will work the same way. Given a BER-TLV byte[] array, it will return a list of BerTlv objects that support access of sub TLVs.
It seems the DER encoding\decoding classes are internal to the .NET framework. If so, where are they? (I'd like to ask connect.microsoft.com to make these members public)
Maybe somebody else can answer this question.
Summary
Here is an example of how you can use the code provided below. I have used the public key data you provided in your previous post. The BerTlv should probably be augmented to support querying like BerTlv.getValue(rootTlvs, '/30/30/06');.
public static void Main(string[] args)
{
string pubkey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDrEee0Ri4Juz+QfiWYui/E9UGSXau/2P8LjnTD8V4Unn+2FAZVGE3kL23bzeoULYv4PeleB3gfmJiDJOKU3Ns5L4KJAUUHjFwDebt0NP+sBK0VKeTATL2Yr/S3bT/xhy+1xtj4RkdV7fVxTn56Lb4udUnwuxK4V5b5PdOKj/+XcwIDAQAB";
byte[] pubkeyByteArray = Convert.FromBase64String(pubkey);
List<BerTlv> rootTlvs = BerTlv.parseTlv(pubkeyByteArray);
BerTlv firstTlv = rootTlvs.Where(tlv => tlv.Tag == 0x30).First();//first sequence (tag 30)
BerTlv secondTlv = firstTlv.SubTlv.Where(tlv => tlv.Tag == 0x30).First();//second sequence (tag 30)
BerTlv oid = secondTlv.SubTlv.Where(tlv => tlv.Tag == 0x06).First();//OID tag (tag 30)
string strOid = OidByteArrayToString(oid.Value);
Console.WriteLine(strOid);
}
Output:
1.2.840.113549.1.1.1
OID Encode/Decode
public static byte[] OidStringToByteArray(string oid)
{
string[] split = oid.Split('.');
List<byte> retVal = new List<byte>();
//root arc
if (split.Length > 0)
retVal.Add((byte)(Convert.ToInt32(split[0])*40));
//first arc
if (split.Length > 1)
retVal[0] += Convert.ToByte(split[1]);
//subsequent arcs
for (int i = 2; i < split.Length; i++)
{
int arc_value = Convert.ToInt32(split[i]);
Stack<byte> bytes = new Stack<byte>();
while (arc_value != 0)
{
byte val = (byte) ((arc_value & 0x7F) | (bytes.Count == 0 ? 0x0:0x80));
arc_value >>= 7;
bytes.Push(val);
}
retVal.AddRange(bytes);
}
return retVal.ToArray();
}
public static string OidByteArrayToString(byte[] oid)
{
StringBuilder retVal = new StringBuilder();
//first byte
if (oid.Length > 0)
retVal.Append(String.Format("{0}.{1}", oid[0] / 40, oid[0] % 40));
// subsequent bytes
int current_arc = 0;
for (int i = 1; i < oid.Length; i++)
{
current_arc = (current_arc <<= 7) | oid[i] & 0x7F;
//check if last byte of arc value
if ((oid[i] & 0x80) == 0)
{
retVal.Append('.');
retVal.Append(Convert.ToString(current_arc));
current_arc = 0;
}
}
return retVal.ToString();
}
BER-TLV Parser
class BerTlv
{
private int tag;
private int length;
private int valueOffset;
private byte[] rawData;
private List<BerTlv> subTlv;
private BerTlv(int tag, int length, int valueOffset, byte[] rawData)
{
this.tag = tag;
this.length = length;
this.valueOffset = valueOffset;
this.rawData = rawData;
this.subTlv = new List<BerTlv>();
}
public int Tag
{
get { return tag; }
}
public byte[] RawData
{
get { return rawData; }
}
public byte[] Value
{
get
{
byte[] result = new byte[length];
Array.Copy(rawData, valueOffset, result, 0, length);
return result;
}
}
public List<BerTlv> SubTlv
{
get { return subTlv; }
}
public static List<BerTlv> parseTlv(byte[] rawTlv)
{
List<BerTlv> result = new List<BerTlv>();
parseTlv(rawTlv, result);
return result;
}
private static void parseTlv(byte[] rawTlv, List<BerTlv> result)
{
for (int i = 0, start=0; i < rawTlv.Length; start=i)
{
//parse Tag
bool constructed_tlv = (rawTlv[i] & 0x20) != 0;
bool more_bytes = (rawTlv[i] & 0x1F) == 0x1F;
while (more_bytes && (rawTlv[++i] & 0x80) != 0) ;
i++;
int tag = Util.getInt(rawTlv, start, i-start);
//parse Length
bool multiByte_Length = (rawTlv[i] & 0x80) != 0;
int length = multiByte_Length ? Util.getInt(rawTlv, i+1, rawTlv[i] & 0x1F) : rawTlv[i];
i = multiByte_Length ? i + (rawTlv[i] & 0x1F) + 1: i + 1;
i += length;
byte[] rawData = new byte[i - start];
Array.Copy(rawTlv, start, rawData, 0, i - start);
BerTlv tlv = new BerTlv(tag, length, i - length, rawData);
result.Add(tlv);
if (constructed_tlv)
parseTlv(tlv.Value, tlv.subTlv);
}
}
}
Here is a utility class that contains some functions used in the class above. It is included for the sake of clarity how it works.
class Util
{
public static string getHexString(byte[] arr)
{
StringBuilder sb = new StringBuilder(arr.Length * 2);
foreach (byte b in arr)
{
sb.AppendFormat("{0:X2}", b);
}
return sb.ToString();
}
public static byte[] getBytes(String str)
{
byte[] result = new byte[str.Length >> 1];
for (int i = 0; i < result.Length; i++)
{
result[i] = (byte)Convert.ToInt32(str.Substring(i * 2, 2), 16);
}
return result;
}
public static int getInt(byte[] data, int offset, int length)
{
int result = 0;
for (int i = 0; i < length; i++)
{
result = (result << 8) | data[offset + i];
}
return result;
}
}
I have problem converting .NET C# AES 128 Encryption to iOS (iPhone). Everything generated correctly except the last block. The final call to xfrm.TransformFinalBlock generate differently than what I got from iOS code (using CCCryptorFinal). I am using the same parameter for BlockSize, Key and IV. What else am I missing? Thank you.
Obj-C
CCCryptorStatus ccStatus = kCCSuccess;
CCCryptorRef thisEncipher = NULL;
// Create and Initialize the crypto reference.
ccStatus = CCCryptorCreate(kCCEncrypt,
kCCAlgorithmAES128,
kCCOptionPKCS7Padding,
szKey,
kCCKeySizeAES128,
iv,
&thisEncipher
);
// Calculate byte block alignment for all calls through to and including final.
int bufferPtrSize = CCCryptorGetOutputLength(thisEncipher, InputLength, true);
unsigned char *szResult = (unsigned char *)malloc(bufferPtrSize+1);
memset(szResult, 0x00, bufferPtrSize+1);
while (dataEncrypted < dataToEncrypt)
{
bool final = (dataToEncrypt - dataEncrypted) <= lrcEncryptionBlockSize;
if (final)
{
// Finalize everything to the output buffer.
ccStatus = CCCryptorFinal(thisEncipher,
szResult + dataEncrypted,
bufferPtrSize - dataEncrypted,
pOutSize
);
dataEncrypted += *pOutSize;
for(int c=0;c<dataEncrypted;++c)
{
printf("\n%d => %d\n", c, szResult[c]);
}
success = true;
break;
}
else
{
// Actually perform the encryption or decryption.
ccStatus = CCCryptorUpdate( thisEncipher,
szInput+cb,
lrcEncryptionBlockSize,
szResult+dataEncrypted,
bufferPtrSize - dataEncrypted,
pOutSize
);
dataEncrypted += *pOutSize;
cb += lrcEncryptionBlockSize;
}
}
if (thisEncipher) {
(void) CCCryptorRelease(thisEncipher);
thisEncipher = NULL;
}
C#
AesManaged aesAlg = new AesManaged();
ICryptoTransform xfrm;
aesAlg.IV = GenerateIV();
aesAlg.Key = "1111111111111111";
aesAlg.BlockSize = 128;
xfrm = aesAlg.CreateEncryptor();
while (dataEncrypted < dataToEncrypt)
{
bool final = (dataToEncrypt - dataEncrypted) <= lrcEncryptionBlockSize;
int nbytes = !final ? lrcEncryptionBlockSize : (int)(dataToEncrypt - dataEncrypted);
if (final)
{
byte[] finalblock = xfrm.TransformFinalBlock(message, cb, nbytes);
Buffer.BlockCopy(finalblock, 0, message, cb, lrcEncryptionBlockSize);
success = true;
break;
}
else
{
dataEncrypted += (uint)xfrm.TransformBlock(message, cb, nbytes, message, cb);
cb += lrcEncryptionBlockSize;
}
}
xfrm.Dispose();
aesAlg.Clear();
If only the last block differs, the difference is probably that they use different padding. The first example uses PKCS7, but I cant see what the second one uses.
i am using iOS-libarchive library for .tar extraction on iphone. i am using the sample code given here at this link
http://code.google.com/p/libarchive/wiki/Examples
but i am facing problem in extracting .tar file.
i am placing my .tar file in library/simulator.../Application/617C31E0/Documents folder.
when i run application for extraction then it completes it flow successfully without giving any error code. but i could not fine that extracted folder anywhere in machine.
here is the piece of code, i am using in my application
static int copy_data(struct archive *ar, struct archive *aw)
{
int r;
const void *buff;
size_t size;
off_t offset;
for (;;) {
r = archive_read_data_block(ar, &buff, &size, &offset);
if (r == ARCHIVE_EOF)
return (ARCHIVE_OK);
if (r != ARCHIVE_OK)
return (r);
r = archive_write_data_block(aw, buff, size, offset);
if (r != ARCHIVE_OK) {
warn("archive_write_data_block()",
archive_error_string(aw));
return (r);
}
}
}
static int verbose = 0;
static void extract(const char *filename, int do_extract, int flags)
{
struct archive *a;
struct archive *ext;
struct archive_entry *entry;
int r;
a = archive_read_new();
ext = archive_write_disk_new();
archive_write_disk_set_options(ext, flags);
/*
* Note: archive_write_disk_set_standard_lookup() is useful
* here, but it requires library routines that can add 500k or
* more to a static executable.
*/
archive_read_support_format_tar(a);
/*
* On my system, enabling other archive formats adds 20k-30k
* each. Enabling gzip decompression adds about 20k.
* Enabling bzip2 is more expensive because the libbz2 library
* isn't very well factored.
*/
if (filename != NULL && strcmp(filename, "-") == 0)
filename = NULL;
if ((r = archive_read_open_file(a, filename, 10240)))
fail("archive_read_open_file()",
archive_error_string(a), r);
for (;;) {
r = archive_read_next_header(a, &entry);
if (r == ARCHIVE_EOF)
break;
if (r != ARCHIVE_OK)
fail("archive_read_next_header()",
archive_error_string(a), 1);
if (verbose && do_extract)
msg("x ");
if (verbose || !do_extract)
msg(archive_entry_pathname(entry));
if (do_extract) {
r = archive_write_header(ext, entry);
if (r != ARCHIVE_OK)
warn("archive_write_header()",
archive_error_string(ext));
else {
copy_data(a, ext);
r = archive_write_finish_entry(ext);
if (r != ARCHIVE_OK)
fail("archive_write_finish_entry()",
archive_error_string(ext), 1);
}
}
if (verbose || !do_extract)
msg("\n");
}
archive_read_close(a);
archive_read_finish(a);
exit(0);
}
- (void)applicationDidFinishLaunching:(UIApplication *)application
{
// Override point for customization after application launch
[window makeKeyAndVisible];
// Extract files from archive into named dir in the temp dir
NSString* databaseName = #"PIIS147020451170078X.tar";
NSArray* documentPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString* documentsDir = [documentPaths objectAtIndex:0];
NSString* make7zResPath = [documentsDir stringByAppendingPathComponent:databaseName];
/*
NSString *tmpDirname = #"Extract7z";
NSString *make7zFilename = #"PIIS147020451170078X";//#"test.7z";
NSString *make7zResPath = [[NSBundle mainBundle] pathForResource:make7zFilename ofType:#"tar"];
*/
extract([make7zResPath cStringUsingEncoding:NSUTF8StringEncoding],1, ARCHIVE_EXTRACT_TIME);
return;
}
Please help me into this :(.
Thanks!!
I write another library that do exactly what you want: https://github.com/mhausherr/Light-Untar-for-iOS
In few words i've only implemented the minimal functions to untar a file.
Full explanation here http://blog.octo.com/en/untar-on-ios-the-pragmatic-way/
I have an API which sends an XML Request to a server:
<?xml version="1.0" encoding="UTF-8"?>
<request type="handle" action="update">
<userdata>
<username>YourUsername</username>
<password>YourPassword</password>
</userdata>
<handledata type="PERSON" id="HandleId">
<name>Mustermann</name>
<firstname>Max</firstname>
<organization>Firma KG</organization>
<street>Musterstrasse 1</street>
<postalcode>11111</postalcode>
<city>Musterstadt</city>
<state>Niedersachsen</state>
<country>DE</country>
<email>email#adresse.de</email>
<phone>+43-111-111111</phone>
<fax>+43-111-111111</fax>
<remarks>remarks</remarks>
</handledata>
</request>
How do I do this on the iPhone?
You can use libxml2. I suspect it is the fastest approach. Add its framework to your project (see the "setting up your project" section of this document).
In the header of your XML writer, add the following imports:
#import <libxml/encoding.h>
#import <libxml/xmlwriter.h>
In the implementation, write a method to generate your XML. Presumably you'll be sending your request's bytes via an NSData* object, so you might write something like this:
- (NSData *) xmlDataFromRequest
{
xmlTextWriterPtr _writer;
xmlBufferPtr _buf;
xmlChar *_tmp;
const char *_UTF8Encoding = "UTF-8";
_buf = xmlBufferCreate();
_writer = xmlNewTextWriterMemory(_buf, 0);
// <?xml version="1.0" encoding="UTF-8"?>
xmlTextWriterStartDocument(_writer, "1.0", _UTF8Encoding, NULL);
// <request type="handle" action="update">
xmlTextWriterStartElement(_writer, BAD_CAST "request");
xmlTextWriterWriteAttribute(_writer, BAD_CAST "type", BAD_CAST "handle");
xmlTextWriterWriteAttribute(_writer, BAD_CAST "action", BAD_CAST "update");
xmlTextWriterEndElement(_writer);
// <userdata>...</userdata>
xmlTextWriterStartElement(_writer, BAD_CAST "userdata");
xmlTextWriterStartElement(_writer, BAD_CAST "username");
_tmp = [self xmlCharPtrForInput:[[NSString stringWithFormat:#"YourUsername"] cStringUsingEncoding:NSUTF8StringEncoding] withEncoding:_UTF8Encoding];
xmlTextWriterWriteString(_writer, _tmp);
xmlTextWriterEndElement(_writer); // closing <username>
xmlFree(_tmp);
xmlTextWriterStartElement(_writer, BAD_CAST "password");
_tmp = [self xmlCharPtrForInput:[[NSString stringWithFormat:#"YourPassword"] cStringUsingEncoding:NSUTF8StringEncoding] withEncoding:_UTF8Encoding];
xmlTextWriterWriteString(_writer, _tmp);
xmlTextWriterEndElement(_writer); // closing <password>
xmlFree(_tmp);
xmlTextWriterEndElement(_writer); // closing <userdata>
// etc.
xmlTextWriterEndDocument(_writer);
xmlFreeTextWriter(_writer);
// turn libxml2 buffer into NSData* object
NSData *_xmlData = [NSData dataWithBytes:(_buf->content) length:(_buf->use)];
xmlBufferFree(_buf);
return _xmlData;
}
I have a helper method here that I use to convert const char * into xmlChar *:
- (xmlChar *) xmlCharPtrForInput:(const char *)_input withEncoding:(const char *)_encoding
{
xmlChar *_output;
int _ret;
int _size;
int _outputSize;
int _temp;
xmlCharEncodingHandlerPtr _handler;
if (_input == 0)
return 0;
_handler = xmlFindCharEncodingHandler(_encoding);
if (!_handler) {
NSLog(#"convertInput: no encoding handler found for '%s'\n", (_encoding ? _encoding : ""));
return 0;
}
_size = (int) strlen(_input) + 1;
_outputSize = _size * 2 - 1;
_output = (unsigned char *) xmlMalloc((size_t) _outputSize);
if (_output != 0) {
_temp = _size - 1;
_ret = _handler->input(_output, &_outputSize, (const xmlChar *) _input, &_temp);
if ((_ret < 0) || (_temp - _size + 1)) {
if (_ret < 0) {
NSLog(#"convertInput: conversion wasn't successful.\n");
} else {
NSLog(#"convertInput: conversion wasn't successful. Converted: %i octets.\n", _temp);
}
xmlFree(_output);
_output = 0;
} else {
_output = (unsigned char *) xmlRealloc(_output, _outputSize + 1);
_output[_outputSize] = 0; /*null terminating out */
}
} else {
NSLog(#"convertInput: no memory\n");
}
return _output;
}
I would use string formatting for such a simple structure.