Search Results (7 posts found):
I've just started a little C programming project in order to improve my C programming and, indeed, to see if I'm actually clever enough to write something in C. The project I've chosen is a little ID3 tag editor for MP3 files.
I've chosen this because it might be useful and because it involves something I quite enjoy, which is parsing files. It's also the sort of project that doesn't need a GUI but can later be extended to have one.
I chose C because, as stated earlier, I wanted to prove to myself that I can do it and because it's a great language for byte level manipulation of the sort required to parse a binary file like an MP3.
MP3 files support two types of ID3 tag, these being version 1 and version 2 (of which there are 4 types). ID3v1 tags reside at the end of the mp3 file and are limited in length to 128 total bytes: 3 for the keyword "TAG", 30 each for the title, artist and album, 4 for the year, and then either 28 or 30 for a comment, and, if using a 28 byte comment, 2 for the track number, and finally 1 byte for the genre.
ID3v1 tags are therefore trivial to manipulate.
ID3v2 moved the tags to the start of the file and introduced the concept of separate frames of data, each to store one tag and its value.
The ID3v2 header starts with the values "ID3" (0x49 0x44 0x43 in hex) followed by the minor version number (0x03 for ID3v2.3, 0x04 for ID3v2.4, etc) and then the build number (usually 0), a byte for flags related to the ID3 tagss, and finally four bytes for the overall ID3 header size. Thus an ID3v2 header can be identified by looking like this:
49 44 33 vv vv ff xx xx xx xx
Where vv are the version bytes, ff is the flags, and xx xx xx xx is the big-endian header size.
When I first started writing the decoding function for the ID3 header I was reading the number of bytes as dictated by the xx xx xx xx in the header, but found I was reading well beyond the end of the header itself, causing all sorts of problems. This led me to a google search where I discovered the concept of "Sync-Safe Integers".
These sync-safe integers are not a universal computing concept, but rather one created purely for MP3 encoding, it seems. And this is where sychronisation safe integers come in.
In order for those four bytes indicating header size to not be confused for later bytes that are used to synchronise data frames they cannot contain the values "FF 00" and the way to do this is to ensure that no bytes not intended for syncronisation contain the value FF unless always guaranteed to be followed by a non-zero value, such as the byte order marker FF FE.
To do this, we insert a zero at bit 8 (the left-most bit, and most-significant bit) of each byte, working from least to most significant, and shift the rest of the bytes accordingly:
Thus the value:
00000001 00000110 00010100 11000001
becomes
00001000 00011000 00101000 01000001
This has the side-effect of reducing the capacity of our integer from being 32 bits to being 28 bits, but in the context of ID3 tags that limitation is irrelevant.
For my own program, I achieved this shift by using a bit mask to take each group of bits I want to operate on in turn, applying the mask as a bitwise AND to the integer, and then shifting the requisite number of positions to the right.
I then bitwise ORed the results together:
return ((in & 0x0000007F) |bit mask %00000000 00000000 00000000 01111111
((in & 0x00003F80) << 1) |bit mask %00000000 00000000 00111111 10000000
((in & 0x001FC000) << 2) |bit mask %00000000 00011111 11000000 00000000
((in & 0x0FE00000) << 3));bit mask %00001111 11100000 00000000 00000000
g a sync-safe integer from a regular integer.
The decoding sequence is just the reverse:
return ((in & 0x0000007F) | // bit mask %00000000 00000000 00000000 01111111
((in & 0x00007F00) >> 1) |bit mask %00000000 00000000 01111111 00000000
((in & 0x007F0000) >> 2) |bit mask %00000000 01111111 00000000 00000000
((in & 0x7F000000) >> 3)); // bit mask %01111111 00000000 00000000 00000000
In both cases, the ORed instructions are independent of each other in the sense that each has its bitmask applied and is shifted BEFORE all four results are ORed together.
And using this approach I was able to now correctly identify the length of the ID3 tags. Note, this value includes any padding at the end of the tags and before the audio data.
So that's sync safe integers - something you'll never encounter outside the realms of writing a decoder for ID3 tags.
I recently needed to implement RSA cryptography in Delphi, sticking to a few requirements of my own choosing:
1. The library used should be free
2. The library license should be permissive enough that I can use the library in a commercial application
3. The library should have as few extra files to include as possible
I looked initially at LockBox, but it came with a multitude of files to either copy to my source folder or include in my library path. I don't want other developers in my team to have to add yet more third party libraries, so I gave this a miss. Additionally, the documentation wasn't great and finding example online was quite tricky.
I then tried PGPCrypt, but could only find a version of that for Lazarus, the free Delphi compiler.
Next was the TMS Cryptography pack, but this isn't free, so again a non-starter.
Then I thought about OpenSSL. We already use OpenSSL as a DLL for a different, but related, purpose so the file is already present in our source and program folder. What we don't have are function headers as we're calling the DLL functions by importing them directly (we only use three at present), but RSA is more complicated and uses a particular structure that would need replicating in Delphi. I thought this might mean OpenSSL was also a non-starter, but after much searching online I came across the Delphi-OpenSSL project at https://github.com/UniGe/delphiopenssl/ which consists really of only three .pas files, only one of which is necessary for what I'm trying to implement: RSA encryption and decryption. For this purpose I need use only the LibEAY32.pas file coupled with the LibEAY32.dll file. We're using version 1.0.2 of this, and the Delphi-OpenSSL project is compatible with that. Great!
I needed to make a few minor changes, as despite the programmers' best efforts it seemed confused about the difference between Char and AnsiChar in Delphi 2009, but the changes were minimal and consisted, almost entirely, of me replacing references to PChar or PCharacter with PAnsiChar.
The next challenge was to see if I could use an existing key to encrypt a file.
I added my modulus, public exponent and private exponent (not needed for encryption) as Base64 encoded string constants and used:
_rsa = RSA_New();
to create a new RSA structure to populate with the key information. This actually returns a pointer to an RSA object, so it needs both dereferencing and casting when used. The properties we're interested in are the modulus, n; the public exponent, e; and the private exponent, d (when decrypting, later).
These properties take the form of BigNum objects as they can be sometimes thousands of bits long. The BigNums need to be created before being used:
RSA(_rsa^).n := BN_New();
RSA(_rsa^).e := BN_New();
The Base64 values were then decoded and altered, one byte at a time, to hex using IntToHex (which returns a string) and then BN_HexToBN was used to set the RSA record's properties accordingly:
BN_HexToBN(RSA(_rsa^).n, ansistring(public_modulus));
BN_HexToBN(RSA(_rsa^).e, ansistring(public_exponent));
The input string can then be encrypted by calling:
enc_in := SysUtils.TEncoding.ASCII.GetBytes(string(input_text));
to get the string character values as a byte array, followed by:
RSA_Public_Encrypt(length(enc_in),PAnsiChar(enc_in), PAnsiChar(@textout),_rsa,RSA_PKCS1_PADDING);
to do the actual encryption. The output cypher text is held in textout. This will look like garbage but can be converted to a Base64 string for convenient storage.
And that's it.
Two caveats:
I had to add an extra property to the RSA record to match the version of OpenSSL we're using. This was:
engine: pointer;
below the meth property.
And I had to initialise the SSL library by calling:
SSLEay_version(_SSLEAY_VERSION);
before making any calls to encryption or decryption routines. There's probably a better way to do this, but this did the trick.
I put this information here in the hope that it helps someone else who struggled as much as I did to implement this!
As one would expect, YouTube has myriad resources for the Welsh learner, ranging from brief clickbait like "An American tries to speak Welsh" to full episodes of educational programmes and everything in between.
The first port of call, really before going any further, is to watch the Welsh Plus series which go into great detail about how to pronounce the letters of the Welsh alphabet, both individually and in common combinations. They also touch on the mutations. Welsh Plus's playlist can be found
here.
When I started learning Welsh, and before I'd discovered the Say Something in Welsh website, I discovered a series of videos called "Learn Welsh with Will" in which Will Huw, an Englishman living in Wales, disseminates his own Welsh knowledge as he goes about learning it. I liked Will's videos as he comes across as non-judgemental and very amiable. You can see Will's playlists, which include more than just Learn Welsh With Will,
here.
Another series of videos I happened upon are aimed at adult learners from the 1990s, Now You're Talking (conveniently mis-spelled as "Now Your Talking" by whomever uploaded them!). These are presented by the likeable Elin Rhys in a variety of very early 90s outfits! There are 36 full half-hour episodes covering a variety of topics and gradually building vocabulary. I enjoy these videos as they present a chance to hear simple conversations in Welsh and learn everyday vocabulary. My only criticisms are that the programmes are now quite dates, the language is in some places a little too old-fashioned, and the pace of the lessons is a little slow for my liking. There's also not a great focus on grammar, so you'll need other resources to accompany these. You can find all 36 videos
here.
Much more recent, are Margaret Hall's wonderful videos. Margaret is a Welsh learner and as part of her learning process she's created a series of videos in which she explores various places in Wales. Margaret speaks very clearly and uses a great vocabulary for the upper-beginner or intermediate Welsh learner. I find I can understand a lot of what she says, but not everything. That's due to limitations in my Welsh, though, not any problems with her speaking. Margaret's channel is
here.
Finally, the Easy Languages series have several videos in Welsh. These are largely conversations with Welsh speakers in towns and establishments around Wales, conducted entirely in Welsh. The videos are subtitled in both English and Welsh, which is both a blessing and a curse, as you can find yourself reading the English subtitles rather than understanding the spoken Welsh. The ease of understanding the spoken Welsh depends largely on the speaker. Some interviewees are fluent speakers, some only beginners, but the most encouraging thing I took from these videos is that, actually, Welsh is very fluid, Welsh speakers are very forgiving of mistakes and, in reality, things like mutations are not nearly as stuck-to as online guides may lead you to believe. You can find those videos
here.
There are plenty more besides, but these are the video series that I've found most useful and most enjoyable while learning Welsh. Feel free to comment if you feel I've missed anything important!
Da bo am y tro!
Ah, Milton Jones. King of the Wise Crack, Prince of the Pun.
Milton - ably assisted by his best friend, Anton (Tom Goodman-Hill) - takes on a variety of unusual and unlikely jobs ranging from a gardening expert, to lorry driver, chef and international diplomat. The recurring theme is that Milton is monumentally unsuited to every single job, although somehow things work out for him in the end. For the first series only, his adventures include his sister, Susan (Debbie Chazen).
As with other Milton Jones programmes, this one really serves as a vehicle for Milton's craft with puns and one-liners. That's not to say it's bad, though. There are a lot of jokes that made me laugh out loud and, if anything, the very tenuous storylines actually add re-listening value, as the plots are largely irrelevant and the stories can be enjoyed again.
Some of the jokes fall a little flat, but there are still plenty that work well as well as some running-gags that appear in many episodes. One that springs to mind is that something will crop up that makes Anton reminisce, some sentimental music will play, and Anton will tell an anecdote where something went wrong that caused embarrassment for him and can therefore either not visit a certain place or fulfil a certain role, like addressing the UN General Assembly and opening with "So where have you all come from?". Another, that always makes me laugh, is when Jones uses very small snippets from songs to create conversations involving various singers ("What flavour ice cream do you want, Prince?", "Raspberry beret"; "What's the forecast today, Bill Withers?", "Lovely day, lovely day, lovely day")
Of all the Milton Jones series, "Another Case of..." is probably my favourite. I found The House of Milton Jones to be too confined and contrived, the good witch idea in The Very World of Milton Jones to be just a little too irritating and the stories, which are just a series of flashbacks, to be too tenuous and disjointed. Another Case of Milton Jones, on the other hand, does at least have a coherent story for each episode to balance the constant flow of puns.
I've listened to Another Case of Milton Jones several times now, and I still find myself returning to it when I just want some honest, uncomplicated, good fun comedy.
Rating: * * * *
If you're learning a language, one of the best ways to gain exposure to that language and increase fluency is to visit a country where that language is spoken.
Herein lies the problem with Welsh: not all Welsh people speak it. They all speak English, but only around 20% of the population speaks Welsh. This means that if I'm in Wales, I can't initiate a conversation in Welsh because I can't guarantee that the other person will be a Welsh speaker.
Such a situation, where a native does not speak the native language, would be inconceivable in most other countries.
The fact that there are no monoglot Welsh speakers remaining also doesn't help. Because everyone speaks English fluently there's less incentive to make the effort to learn and speak Welsh.
Then there's the problem with signage. In France, other than at some touristy areas, all signs are in French. Signs alerting me to the "dèrniere sortie avant péage" will do so only in French. Translating and understanding the signs becomes part of the learning experience. Unfortunately, in Wales most signs are bilingual. The order of the languages is left to the discretion of the local authority, but an English translation will be on the sign somewhere. On the one hand, this allows you to quickly confirm that your translation of the Welsh was correct. On the other, it takes a lot of the fun and the necessity out of translating in the first place. It's very hard not to notice the English accidentally before you've had chance to attempt the Welsh.
What I have discovered, to my surprise and delight, is that several of my colleagues speak varying levels of Welsh. Remember, this is Somerset, England, not the north of Wales, so it's not entirely expected. One even speaks fluent Welsh, having attended a Welsh medium school. And he's said he's always happy to help with my Welsh learning.
So things are looking up.
Here's an odd one: the Welsh have no word for "to have", as in to possess something.
The Welsh, though, are a resourceful lot and get around this apparent limitation by saying that something is "with" something else.
I do not have a ball, a ball is with me. Likewise, a new house is with me; a girlfriend is with me; even a beard is with me.
The concept isn't complicated, but I find it tricky to get the word order right. During a conversation at work, I was asked if I knew how to say "The red dog has a ball" in Welsh. I had to think about this. Is the red ball with the dog, or is the dog with the red ball? I eventually settled on the former: mae pêl gyda'r ci coch. I think that's right.
It doesn't trip off my tongue quite as easily as it would in, say, French: Le chien rouge a un ballon. It's a little clumsy and awkward, but that's part of the charm.
This problem isn't limited to possessing an object (or a girlfriend) though. It rears its head when talking about health too. You don't have a sore throat, there is a sore throat with you. You do not have a cold, there is a cold "on you": Mae annwyd arna i.
Let's hope I don't get sick while in Wales; this might take some getting used to.
Welsh, like most European languages, assigns nouns a gender. Some of these are obvious: a man (dyn) is masculine. A woman (menyw or dynes) is feminine. A cat (cath) is feminine. A dog (ci) is masculine. Well, that makes sense to me, at least.
But what's a table? Or a bed? Or love?
And how do we differentiate between them? And how do we learn the gender of a new object?
Well, in other European languages you can tell whether a noun is masculine or feminine by the article in front of it. In French, we have the indefinite articles "un" and "une" and the definite articles "le" and "la". When you learn a new word you also learn the gender. While on holiday in Paris in 2003 I asked "Qu'est-ce que c'est?" while holder up a token to use the toilet in a bar, and I got the answer "un jeton". Un. Masculine. And I've never forgotten that a token, in French, is masculine: "un jeton".
So what about Welsh? Welsh doesn't have an indefinite article at all. There is no way of saying "a table" or "an apple", it's just "bwrdd" and "afal". There IS a definite article ("the table" or "the apple") and it has three forms:
Y for words following and preceding a consonant
Yr for words preceding a vowel, but following a consonant
'r for words following a vowel (regardless of what follows it)
Sadly, none of these differentiate by gender, so it's almost impossible when learning a new word as part of conversation or when reading to tell whether it's masculine or feminine. And it's this that is, so far, the most frustrating thing about learning Welsh. I find myself looking up words that I already know just to determine their gender. While writing this I had to check to see if "coffi" (coffee) is feminine (it isn't).
So, does that matter? Well, yes! Welsh also has no gender-neutral word for "it". When talking about an object you refer to it as either he or she depending on its gender. When talking about the weather, for example, you refer to "she". "Mae hi'n oer" is "it's cold", only it's really "she's cold". And not only that, but certain words mutate in certain ways depending on context and gender. Would a Welsh person understand you if you were to get a gender wrong? Yes, of course. But it would grate. It wouldn't sound right. And if I'm going to learn a language, I'm going to do it right.