Thanks so much for this. I managed to get it working by checking for a field that only exists on group start and end layers ("8BIMlsct"), and then search back from that, to get the related layer ID. I then put these into an array to check against, to allow any group items to be removed from the main array. I used a fair bit of trial an error to find the right number of bytes to adjust it, and as you suggested I looked through the spec and a hex editor, and managed to at least find the other fields.
The thing that still baffles me a bit is where the number 12 comes from in this line:
readWord(PSD_data, findResult.index + 12)
Should I be able to simply count in the plain-text view of the hex editor? I will have to do a bit more research on this. I obviously need a better foundation of knowledge to build upon. 
Anyway, the checking with a loop inside a loop probably isn't the most efficient way of doing that, but it seems fairly robust after a few tests.
Can't thank you enough for all your help. I would never had got this working without it.
Kind regards,
- Ian
[CODE=javascript]function main() {
file = File.openDialog("Please select PSD file.","PSD File:*.psd");
if(!file.exists) return;
file.open("r");
file.encoding = 'BINARY';
var PSD_data = file.read();
file.close();
var findResult;
var indexPos =[];
var name_arr= [];
var ID_arr = [];
var GRP_arr = [];
var rex_name = new RegExp ('8BIMluni','g');
while ((findResult = rex_name.exec(PSD_data)) != null) { // Find ALL occurencies of search string
indexPos.push(findResult.index+(findResult[0].length));
}
var rex_id = new RegExp ('8BIMlyid','g');
while ((findResult = rex_id.exec(PSD_data)) != null) { // Find ALL occurencies of search string
ID_arr.push( readWord(PSD_data, findResult.index + 12));
}
var rex_type = new RegExp ('8BIMlsct','g');
// USE THE lsct SEARCH TO FIND ITEMS THAT ARE A GROUP START OR END AND ADD TO AN ARRAY
while ((findResult = rex_type.exec(PSD_data)) != null) { // Find ALL occurencies of search string
IDforType = readWord(PSD_data, findResult.index - 4);
GRP_arr.push(IDforType);
}
function readByte(str, ofs) { // Read one byte at offset
return str.charCodeAt(ofs);
}
function readInt16(str, ofs) { //read two byttes at offset
return (readByte(str, ofs) << 8) + readByte(str, ofs+1);
}
function readWord(str, ofs) { //read four bytes at offset
return (readInt16(str, ofs) << 16) + readInt16(str, ofs+2);
}
function readUnicodeChar(str, ofs) { //get character at offset
return String.fromCharCode(readInt16(str, ofs));
}
for (var i = 0; i < indexPos.length; i++) { //loop through all finds
var ofs = indexPos[i]; //offset of find
var name_arrLength = readWord(PSD_data, (ofs+ 4)); //Read length of string at offset
ofs += 8; //increment offset to suit
var str = ''; //reset string to ''
for (var j = 0; j < name_arrLength; j++) { //loop through string
str += readUnicodeChar(PSD_data, ofs); // add char
ofs += 2; //increment two bytes
}
name_arr.push(str); //Layer name found and stored
}
//reverse arrays so that ir reads Photoshop layers top down
name_arr.reverse();
ID_arr.reverse();
var PSDlayersArr = [];
var thisArr = [];
var a;
var grpID;
var thisID;
var chk = false;
// CREATE ARRAY OF LAYER NAMES AND ID
for (i=0,len=name_arr.length;i<len;i++) {
// CHECK IF LAYER ID IS IN THE LIST OF GROUP IDs
for (a=0,len2=GRP_arr.length ; a<len2 ; a++) {
grpID = GRP_arr[a];
thisID = ID_arr[i];
if (grpID === thisID) {
chk = true;
break;
}
}
if (chk) {
chk = false;
continue;
};
thisArr = [name_arr[i],ID_arr[i]];
PSDlayersArr.push(thisArr);
}
alert(PSDlayersArr.join("\n"));
}
main();[/CODE]