//returns a node that is nested somewhere inside this node, the path to the nested node //is described by a series of node names giben in 'keys' public TextEngineNode getNestedNodeByKey(String[] keys) { TextEngineNode tempNode = this; foreach (string key in keys) { if (tempNode == null) { return(null); } else { tempNode = tempNode.getNodeByKey(key); } } return(tempNode); }
private TextEngineNode parseEngineData(ByteArray bytes, uint depth) { //set up the root node that is the top of the tree TextEngineNode rootNode = new TextEngineNode(); rootNode.type = TextEngineNode.TYPE_STRUCTURE; rootNode.key = "root"; long tempPos = bytes.Position; while (bytes.Position < bytes.Length) { //find a key String key = findKeyOrEnd(bytes); //returns null if end of structure is found if (key == null) { return(rootNode); } //if we have reached this point we have found a key of the form "/keyname " //what follows is either a value or a structure, the following code works out which it is Boolean isStructure = false; byte b = bytes.getByte(); //depending on the value of the next byte, we know what is going to follow switch (b) { case 0x20: //if there is a space, then a value follows //little hack to get structures inside of arrays working if (bytes.bytes[bytes.Position] == 0x5b && bytes.bytes[bytes.Position + 1] == 0x0a) { Boolean stopBracketLoop = false; while (!stopBracketLoop) { TextEngineNode node2 = parseEngineData(bytes, depth + 1); node2.key = key; rootNode.structure.Add(node2); if (bytes.Position == bytes.Length) { return(rootNode); //massive hack just to get it working, //basically it just ends if we run out of data } while (bytes.Position < bytes.Length) { b = bytes.getByte(); if (b != 0x09 && b != 0x3e && b != 0x0a) //its a tab, so we can skip { if (b == 0x5d) { stopBracketLoop = true; } else if (b == 0x3c || b == 0x2f) { //we have a new structure or property } else { if (bytes.Position == bytes.Length) { return(rootNode); //massive hack just to get it working, //basically it just ends if we run out of data } Console.Out.WriteLine("unknown byte in middle of array at: " + bytes.Position); } break; } } } continue; } else { isStructure = false; } break; case 0x0a: //if its a new line, then we have found a structure isStructure = true; break; default: Console.Out.WriteLine("unknown value after key: 0x" + b + ", at: " + bytes.Position); break; } //now we can build the node TextEngineNode node; if (isStructure) { //if its a structure, we use recursion to build the node node = parseEngineData(bytes, depth + 1); node.key = key; } else { //if its a value, we create a new node and fill in the value manually node = new TextEngineNode(); node.key = key; node.value = findValue(bytes); node.type = TextEngineNode.TYPE_VALUE; } rootNode.structure.Add(node); } return(rootNode); }
//the text engine data format is complicated, although godden told me its the //same as how pdf's store it private void parseEngineDataStructure(ByteArray bytes, long endOfTag) { byte b; //find the start of the data by looking for the first < while ((b = bytes.getByte()) != 0x3c && bytes.Position < endOfTag) { } //make sure we actually found one if (bytes.Position == endOfTag) { throw new Exception("could not find start of text engine data"); } long startPos = bytes.Position; //we are at the start now, the end of the data will be 0x3e 0x3e 0x00 byte firstByte = bytes.getByte(); byte secondByte = bytes.getByte(); byte thirdByte = bytes.getByte(); //move to the start of the structure while (bytes.Position < endOfTag) { // 0x3e is a > if (firstByte == 0x3e && secondByte == 0x3e && thirdByte == 0x00) { break; } firstByte = secondByte; secondByte = thirdByte; thirdByte = bytes.getByte(); } if (bytes.Position == endOfTag) { throw new Exception("could not find end of text engine data"); } long endPos = bytes.Position; //we can use the startPos and endPos to get the data in the middle bytes.Position = startPos; ByteArray engineData = bytes.getBytes((uint)(endPos - startPos)); //engineData now contains the engineData, this code works TextEngineNode dataObject = parseEngineData(engineData, 0); //now that we have parsed all of the engineData and stored it in 'dataObject', we retreive the //nodes that we need TextEngineNode tempNode; tempNode = dataObject.getNestedNodeByKey(new string[] { "ResourceDict", "FontSet", "Name" }); if (tempNode != null) { fontName = tempNode.value; } tempNode = dataObject.getNestedNodeByKey(new string[] { "EngineDict", "StyleRun", "RunArray", "StyleSheet", "StyleSheetData", "FontSize" }); if (tempNode != null) { fontSize = tempNode.value; } tempNode = dataObject.getNestedNodeByKey(new string[] { "EngineDict", "Editor", "Text" }); if (tempNode != null) { text = tempNode.value; } }