write(array("E1EDKA1","AG", "0815", "Stefan Moises", "Some company", "Street 45a"), array(0,63,66,100,135,240), 1063); * $idocWriter->toFile("/tmp/test_idoc.dat"); */ class smxIdocWriter { // content string protected $_content; // array of content strings ["content"] and content offsets ["offsets"] per line protected $_contentArray; // total lines protected $_totalLines = 0; /** * Constructor */ public function __construct() { } /** * Convenience function to save typing :) * @param array $contentArray The contents to add at the offsets. * @param array $offsetArray The offsets for the content parts of the line. * @param int $lineLen The length of the line in characters (bytes) */ public function write($contentArray, $offsetArray, $lineLen = -1) { $this->_addLineContentsWithOffsets($contentArray, $offsetArray, $lineLen); } /** * Write contents to idoc file * @param String $path The path and filename to write to. */ public function toFile($path) { $content = $this->get_content(); $handle = fopen ($path, "w"); fwrite($handle, $content); fclose($handle); } /** * Get a line by index - remember to start from 1, not 0! * @param int $idx The line index, starting from 1 * @return array The line (or false if invalid index) */ public function getLine($idx) { if($idx > $this->_totalLines) return false; else return $this->_contentArray[$idx]; } /** * Get the offsets in a line * @param $idx * @return */ public function getLineOffsets($idx) { $line = $this->getLine($idx); if($line) return $line["offsets"]; else return false; } /** * Get the offsets in a line * @param $idx * @return */ public function setLineOffsets($idx, $offsetArray) { $line = $this->getLine($idx); if($line) $this->_contentArray[$idx]["offsets"] = $offsetArray; else return false; } /** * Returns the content of a certain line. * @param int $idx The line index, starting from 1. * @return String The line content. */ public function getLineContent($idx) { $line = $this->getLine($idx); if($line) return $line["content"]; else return false; } /** * Sets the content of the specified line. * @param int $idx The line index. * @param String $content The content with spaces between values. */ public function setLineContent($idx, $content) { $line = $this->getLine($idx); if($line) { $this->_contentArray[$idx]["content"] = $content; } } /** * Add multiple values to a line at specified offsets * Main function to add lines to the idoc. * @param array $contentArray The contents to add at the offsets. * @param array $offsetArray The offsets for the content parts of the line. * @param int $lineLen The length of the line in characters (bytes) */ protected function _addLineContentsWithOffsets($contentArray, $offsetArray, $lineLen) { // add new line $this->_totalLines++; $this->_contentArray[$this->_totalLines]["content"] = ""; $this->_contentArray[$this->_totalLines]["offsets"] = array(); $idx = $this->get_totalLines(); // set contents at offsets specified $this->setLineContentsWithOffsets($idx, $contentArray, $offsetArray, $lineLen); } /** * Set multiple values to a line at specified offsets * @param int $idx * @param array $contentArray * @param array $offsetArray * @param int $lineLen The length of the line in characters (bytes) */ public function setLineContentsWithOffsets($idx, $contentArray, $offsetArray, $lineLen) { if(count($contentArray) != count($offsetArray)) die("Content and offset amount must match!"); $counter = 0; // set fixed offsets $this->setLineOffsets($idx, $offsetArray); foreach($contentArray as $content) { // set value at its offset $this->setValueAtOffset($idx, $offsetArray[$counter], $content, $lineLen); $counter++; } } /** * Find lines by sequence ident (value at offset 0) * @param String $ident * @return array The matching lines */ public function getLinesByIdent($ident) { $lines = array(); $numLines = $this->get_totalLines(); for($i=1;$i<=$numLines;$i++) { $firstValue = $this->getValueAtOffset($i, 0); if(trim($firstValue) == trim($ident)) $lines[] = $this->getLine($i); } return $lines; } /** * Returns a content value on a line at a specified offset. * @param int $lineIdx The line number, starting from 1. * @param int $offset The offset on the line. * @return String The value at the line offset or false if nothing found. */ public function getValueAtOffset($lineIdx, $offset) { $line = $this->getLine($lineIdx); if($line) { $content = $line["content"]; $offsets = $line["offsets"]; $len = strlen($content); $nextOffset = $this->_getNextOffset($lineIdx, $offset, $len); $value = substr($content, $offset, $nextOffset); return $value; } else return false; } /** * Sets a specified value at an offset on a line. * If the value is too long to fit between two offsets, it will be cut. * If there already is a value at that offset, if will be overwritten. * @param int $lineIdx The line number. * @param int $offset The offset on the line. * @param String $value The value to set. * @param int $lineLen The length of the line in characters (bytes) */ public function setValueAtOffset($lineIdx, $offset, $value, $lineLen) { // we are dealing with amount of chars here, not offsets, so // substract 1 from lineLen if($lineLen > 0) $lineLen-=1; $line = $this->getLine($lineIdx); $newContent = ""; if($line) { try { $content = $line["content"]; $offsets = $line["offsets"]; $len = strlen($content); $valueLen = strlen($value); // insert if($offset < $len) { // replace value in line $nextOffset = $this->_getNextOffset($lineIdx, $offset, $len, $offset+$valueLen); $strToReplace = substr($content, (($offset>0)?$offset-1:0), $nextOffset-(($offset>0)?$offset-1:0)); $spacesNeeded = $nextOffset - ($offset + $valueLen); // add trailing spaces if($spacesNeeded > 0) { $value .= $this->_getSpacer($spacesNeeded); } else { // if we are inside the line and need to cut the string to stop before the next offset if($nextOffset < $offset+$valueLen) { $value = substr($value,0,$nextOffset - ($offset + $valueLen)); } } $startStr = substr($content, 0, $offset); $endStr = substr($content, $nextOffset); $newContent = $startStr . $value . $endStr; } else { // add value to line if($len < $offset) { $spacesNeeded = ($offset) - $len; // add leading spaces $value = $this->_getSpacer($spacesNeeded) . $value; } $newContent = $content . $value; } // add spaces to get full segement length? $newLen = strlen($newContent); $lineLen = intval($lineLen); if($newLen < $lineLen) { $numSpaces = $lineLen - $newLen; $newContent .= $this->_getSpacer($numSpaces); } // set new line content for the full line $this->setLineContent($lineIdx, $newContent); } catch(Exception $ex) { print_r($ex); } } else { echo "
ERROR: Invalid line ($lineIdx)!"; } } /** * Get the current content * @return String The IDoc content as string */ public function get_content() { $this->_content = ""; for($i=1; $i <= $this->get_totalLines(); $i++) { $line = $this->getLine($i); $this->_content .= $line["content"] . "\n"; } return $this->_content; } /** * Returs the current line count, starting from 1 * @return int The line count. */ public function get_totalLines() { return $this->_totalLines; } /** * Get a character at a specified position in a string * @param string $string String to "search" from * @param int $index Index of the letter we want. * @return string The letter found on $index. */ public function charAt($string, $index) { if($index < mb_strlen($string)) { return mb_substr($string, $index, 1); } else { return -1; } } /** * Prints out the content array for debugging. */ public function debug() { echo "
\n";
        print_r($this->_contentArray);
        echo "
\n"; } /** * Returns a string of spaces for the specified number of chars * @param $len The number of chars * @return String The string of spaces */ protected function _getSpacer($len) { $str = ""; for($i=0;$i<$len;$i++) { $str .= " "; } return $str; } /** * Get the next offset in the specified line, or the line end * @param int $idx The line index * @param int $pos The starting position / offset * @param int $lineLen The total length of the line before the new insertion * @param int $newValueLen The position after the new string to insert * @return int The next offset or the end of the line (the "old" length, or, if the new string to * insert is longer than the old one, the new length, set by $newValueLen) */ protected function _getNextOffset($idx, $pos, $lineLen, $newValueLen = -1) { $nextOffset = -1; $lineLen += 1; $offsets = $this->getLineOffsets($idx); if($offsets) { foreach($offsets as $offset) { if($offset > $pos) { $nextOffset = $offset; break; } } if($nextOffset == -1) $nextOffset = ($newValueLen > $lineLen) ? $newValueLen : $lineLen; } return $nextOffset; } /** * Computes the offsets in a string, indicated by spaces * Just for testing, not usable ;) * @param string $strLine The string to examine. * @return array The offsets as integers. */ protected function _getLineOffsetsFromString($strLine) { $offsets = array(); $offsets[] = 0; $inWord = true; $len = strlen($strLine); for($i=0;$i<=$len;$i++) { if($this->charAt($strLine, $i) != " ") { if(!$inWord) { $offsets[] = $i; $inWord = true; } } else { $inWord = false; } } return $offsets; } } ?>